source: libabac/abac_id.c @ 756011e

abac0-leak
Last change on this file since 756011e was 756011e, checked in by Ted Faber <faber@…>, 11 years ago

Now we pass -Wall with no warnings.

  • Property mode set to 100644
File size: 12.5 KB
Line 
1
2/* abac_id.c */
3
4// include the GNU extension of asprintf
5#define _GNU_SOURCE
6#include <stdio.h>
7#include <string.h>
8
9#include <assert.h>
10#include <err.h>
11#include <time.h>
12
13#include "libabac_common.h"
14#include "abac_util.h"
15#include "abac_openssl.h"
16
17#define KEY_SUFFIX  "_private.pem"
18#define CERT_SUFFIX "_ID.pem"
19
20static int debug=0;
21
22// ID object
23//
24struct _abac_id_t {
25    char *keyid;
26    char *cn;
27    X509 *cert;
28    EVP_PKEY *key;
29
30    int refcount;
31};
32
33/**************************************************************/
34/**
35 * Helper function for building a ID from a cert. Used by
36 * abac_id_from_*
37 */
38abac_id_t *_id_from_cert(X509 *cert) {
39    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
40    id->cert = cert;
41    id->key = NULL;
42
43    id->keyid = abac_get_keyid(cert);
44    id->cn = NULL;
45    char *tmp=abac_get_cn(cert);
46    if(tmp)  id->cn = abac_xstrdup(tmp);
47    id->refcount = 1;
48    return id;
49}
50
51/**
52 * Load an ID cert from a file.
53 */
54abac_id_t *abac_id_from_file(char *filename) {
55    libabac_init();
56
57    FILE *fp=fopen(filename,"r");
58    if(fp==NULL)
59        return NULL;
60
61    X509 *cert = abac_load_id_from_fp(fp);
62    /* try to see if private key is also in here .. */
63    fclose(fp);
64
65    if (cert == NULL)
66        return NULL;
67
68    abac_id_t *id=_id_from_cert(cert);
69    if(abac_id_privkey_from_file(id, filename)==ABAC_SUCCESS) {
70        if(debug) fprintf(stderr,"abac_id_from_file:found a combo file!!! %s\n", filename);
71    }
72    return id;
73}
74
75/* for some reason, there might be beginning and trailing spaces
76in pem, zap the end with \0 and skip the spaces at the start*/
77char *zap_spaces(char *string)
78{
79   int space=0;
80   int total=strlen(string);
81   int i=0;
82   char *ptr=string;
83   while(string[i]==' ' && i<total) {
84       i++;
85       ptr++;
86   }
87   for(;i<total; i++) {
88       if(string[i]==' ') {
89         space++;
90         string[i]='\0';
91       } 
92   }
93   return ptr;
94}
95
96/* turn a naked pem into a real pem */
97char *make_pem_from_naked_pem(char *naked_pem) {
98    /* Headers and trailers with and w/o newlines (see below) */
99    static char *start="-----BEGIN CERTIFICATE-----";
100    static char *startnl="-----BEGIN CERTIFICATE-----\n";
101    static char *end="-----END CERTIFICATE-----";
102    static char *endnl="\n-----END CERTIFICATE-----";
103    char *s = NULL;
104    char *e = NULL;
105    char *pem=NULL;
106    char *ptr=zap_spaces(naked_pem);
107    int slen = strlen(ptr);
108
109    /*
110     * The -----BEGIN...  and -----END need to be followed by newlines and the
111     * Base64 that gets passed in here may or may not have newlines in the
112     * right places.  when we add a header or trailer, pick one that makes the
113     * newlines right.
114     */
115    if (ptr[0] == '\n') s = start;
116    else s = startnl;
117
118    if (ptr[slen-1] == '\n') e = end;
119    else e = endnl;
120
121    asprintf(&pem,"%s%s%s",s,ptr,e);
122    return pem;
123}
124
125/* build a x509 out of a named pem, extract the sha1 value and
126   free up everything */
127void abac_get_sha_from_nake_pem(char *naked_pem, char **sha1) {
128    abac_chunk_t chunk;
129    /* make a copy of this naked_pem */
130    char *new_naked_pem=abac_xstrdup(naked_pem);
131    char *pem=make_pem_from_naked_pem(new_naked_pem);
132    chunk.ptr = (unsigned char *) pem;
133    chunk.len = strlen(pem);
134    X509 *cert=abac_load_id_from_chunk(chunk.ptr,chunk.len);
135    *sha1=NULL;
136    if(cert) {
137        *sha1 = abac_get_keyid(cert);
138        } else {
139            *sha1=NULL;
140            fprintf(stderr,"can not make cert from pem blob!!\n");
141    }
142    X509_free(cert);
143    free(new_naked_pem);
144    abac_chunk_free(&chunk);
145}
146
147/**
148 * Load an ID cert from a chunk.
149 */
150abac_id_t *abac_id_from_chunk(abac_chunk_t chunk) {
151    libabac_init();
152    X509 *cert= abac_load_id_from_chunk(chunk.ptr, chunk.len);
153
154    if (cert == NULL)
155        return NULL;
156
157    abac_id_t *id=_id_from_cert(cert);
158    if(abac_id_privkey_from_chunk(id, chunk)==ABAC_SUCCESS) {
159        if(debug) fprintf(stderr,"abac_id_from_chunk:found a combo chunk!!!\n");
160    }
161    return id;
162}
163
164static EVP_PKEY *_load_privkey_from_file(char *filename)
165{
166    FILE *fp=fopen(filename,"r");
167    if(fp==NULL) return NULL;
168    EVP_PKEY *key=abac_load_privkey_from_fp(fp);
169    fclose(fp);
170    return key;
171}
172
173/**
174 * Load private key for a cert.
175 */
176int abac_id_privkey_from_file(abac_id_t *id, char *filename) {
177    assert(id != NULL);
178
179    EVP_PKEY *key=_load_privkey_from_file(filename);
180    if (key == NULL) return ABAC_FAILURE;
181
182/* needs to make sure that the key matches up with the id */
183    /* extract the pub key from the id */
184    EVP_PKEY *pubkey=extract_pubkey_from_cert(id->cert);
185    /* cmp will just compare the pub key part of the key to see
186       if they are the same */
187    if(!EVP_PKEY_cmp(pubkey, key)) {
188        fprintf(stderr,"wrong private key for the cert!!\n");
189        return ABAC_FAILURE;
190    }
191
192    /* free up the extracted pukey */
193    EVP_PKEY_free(pubkey);
194
195    id->key = key;
196    return ABAC_SUCCESS;
197}
198
199int abac_id_privkey_from_chunk(abac_id_t *id, abac_chunk_t chunk) {
200    assert(id != NULL);
201
202    EVP_PKEY *key=abac_load_privkey_from_chunk(chunk.ptr, chunk.len);
203    if (key == NULL) return ABAC_FAILURE;
204
205/* needs to make sure that the key matches up with the id */
206    /* extract the pub key from the id */
207    EVP_PKEY *pubkey=extract_pubkey_from_cert(id->cert);
208    /* cmp will just compare the pub key part of the key to see
209       if they are the same */
210    if(!EVP_PKEY_cmp(pubkey, key)) {
211        fprintf(stderr,"wrong private key for the cert!!\n");
212        return ABAC_FAILURE;
213    }
214
215    /* free up the extracted pukey */
216    EVP_PKEY_free(pubkey);
217
218    id->key = key;
219    return ABAC_SUCCESS;
220}
221
222/* pass a privkey from one id to another, very special case for
223   preloading issuer id when attribute is being loaded and when
224   there is an exising principal credential in the hashlist but
225   did not have its privkey setup yet */
226int abac_id_pass_privkey_from_id(abac_id_t *to_id, abac_id_t *from_id) {
227    EVP_PKEY *key=from_id->key;
228    from_id->key=NULL; /* reset the one in from so it does not get freed */
229    if (key==NULL) return ABAC_FAILURE;
230
231/* needs to make sure that the key matches up with the id */
232    /* extract the pub key from the id */
233    EVP_PKEY *pubkey=extract_pubkey_from_cert(to_id->cert);
234    /* cmp will just compare the pub key part of the key to see
235       if they are the same */
236    if(!EVP_PKEY_cmp(pubkey, key)) {
237        fprintf(stderr,"wrong private key for the cert!!\n");
238        return ABAC_FAILURE;
239    }
240
241    /* free up the extracted pukey */
242    EVP_PKEY_free(pubkey);
243
244    to_id->key = key;
245    return ABAC_SUCCESS;
246}
247
248/**
249 * Generate an ID with the specified CN and validity.
250 *
251 * validity is measured in seconds (as of 0.2.0)
252 */
253int abac_id_generate(abac_id_t **ret, char *cn, long validity) {
254    libabac_init();
255    if (cn == NULL || !abac_clean_name(cn))
256        return ABAC_GENERATE_INVALID_CN;
257
258    if (validity < 0)
259        return ABAC_GENERATE_INVALID_VALIDITY;
260
261    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
262
263    id->cn = abac_xstrdup(cn);
264    id->key = abac_generate_key();
265    id->cert = abac_generate_cert(id->key, cn, validity);
266    id->keyid = abac_get_keyid(id->cert);
267
268    id->refcount = 1;
269
270    *ret = id;
271    return ABAC_SUCCESS;
272}
273
274/**
275 * Generate an ID with the specified CN and validity.
276 *
277 * validity is measured in seconds (as of 0.2.0)
278 */
279int abac_id_generate_with_key(abac_id_t **ret, char *cn, long validity, char *keyfile) {
280    libabac_init();
281    if (cn == NULL || !abac_clean_name(cn))
282        return ABAC_GENERATE_INVALID_CN;
283
284    if (validity < 0)
285        return ABAC_GENERATE_INVALID_VALIDITY;
286
287    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
288
289    id->cn = abac_xstrdup(cn);
290    id->key = _load_privkey_from_file(keyfile);
291    id->cert = abac_generate_cert(id->key, cn, validity);
292    id->keyid = abac_get_keyid(id->cert);
293    id->refcount = 1;
294
295    *ret = id;
296    return ABAC_SUCCESS;
297}
298
299char *abac_id_keyid(abac_id_t *id) {
300    if(id) return id->keyid;
301        return NULL;
302}
303
304char *abac_id_cn(abac_id_t *id) {
305    if(id) return id->cn;
306        return NULL;
307}
308
309/**
310 * Get the issuer of an ID cert.
311 * Returns a malloc'd string that must be free'd.
312 */
313char *abac_id_issuer(abac_id_t *id) {
314    if(id) return abac_get_issuer(id->cert);
315        else return NULL;
316}
317
318/**
319 * Gets the subject DN of an ID cert.
320 * Returns a malloc'd string that must be free'd.
321 */
322char *abac_id_subject(abac_id_t *id) {
323    if(id) return abac_get_subject(id->cert);
324        else return NULL;
325}
326
327/**
328 * Get the validity period.
329 */
330int abac_id_validity(abac_id_t *id,struct tm *not_before,struct tm *not_after) {
331    assert(id);
332    if(abac_check_validity(id->cert, not_before, not_after)==0)
333        return ABAC_SUCCESS;
334    return ABAC_FAILURE;
335}
336
337X509 *abac_id_cert(abac_id_t *id) {
338    assert(id);
339    return id->cert;
340}
341
342// get the private key from the ID
343// will return NULL if no key has been loaded
344EVP_PKEY *abac_id_privkey(abac_id_t *id) {
345    assert(id);
346    return id->key;
347}
348
349int abac_id_has_privkey(abac_id_t *id) {
350    if(id && (id->key !=NULL))
351        return 1;
352    return 0;
353}
354
355// see if keyid is the same as id's
356int abac_id_has_keyid(abac_id_t *id, char *keyid)
357{
358    assert(id); assert(keyid);
359    if(strcmp(id->keyid, keyid) == 0)
360        return 1;
361    return 0;
362}
363
364/*
365   return a chunk with both id and key info,
366   err if missing privkey
367*/
368int abac_id_PEM(abac_id_t *id, abac_chunk_t *chunk) {
369    if(id==NULL)
370        return ABAC_CERT_MISSING_ISSUER;
371    if(id->key == NULL)
372        return ABAC_CERT_SIGNER_NOKEY;
373
374    unsigned char *kptr=NULL;
375    unsigned char *ptr=abac_string_cert(id->cert);
376    if(id->key)
377        kptr=abac_string_privkey(id->key);
378   
379    char *tmp=NULL;
380    if(kptr)  {
381        asprintf(&tmp,"%s%s", ptr,kptr);
382        free(ptr);
383        free(kptr);
384        } else {
385            tmp=(char *)ptr;
386    }
387
388
389    chunk->ptr=(unsigned char *)tmp;
390    chunk->len=strlen(tmp);
391
392    return ABAC_CERT_SUCCESS;
393}
394
395abac_chunk_t abac_id_in_PEM(abac_id_t *id) {
396    assert(id);
397    unsigned char *ptr=abac_string_cert(id->cert);
398    int len=0;
399    if(ptr)
400        len=strlen((char *)ptr);
401    abac_chunk_t ret = { ptr, len};
402    return ret;
403}
404
405
406int abac_id_still_valid(abac_id_t *id) {
407    assert(id);
408    return abac_still_valid(id->cert);
409}
410
411/**
412 * Get the default filename for the cert. Value must be freed by caller.
413 */
414char *abac_id_cert_filename(abac_id_t *id) {
415    assert(id != NULL);
416    assert(id->cn != NULL);
417
418    // malloc the filename
419    int len = strlen(id->cn) + strlen(CERT_SUFFIX) + 1;
420    char *filename = abac_xmalloc(len);
421    sprintf(filename, "%s" CERT_SUFFIX, id->cn);
422
423    return filename;
424}
425
426/**
427 * Write the ID cert to an open file pointer.
428 * pem format
429 */
430int abac_id_write_cert(abac_id_t *id, FILE *out) {
431    assert(id != NULL);
432
433    int ret=abac_write_id_to_fp(id->cert, out);
434    if(ret) return ABAC_FAILURE; 
435    return ABAC_SUCCESS;
436}
437
438/**
439 * Default private key filename. Value must be freed by caller.
440 */
441char *abac_id_privkey_filename(abac_id_t *id) {
442    assert(id != NULL);
443    assert(id->cn != NULL);
444
445    // malloc the filename
446    int len = strlen(id->cn) + strlen(KEY_SUFFIX) + 1;
447    char *filename = abac_xmalloc(len);
448    sprintf(filename, "%s" KEY_SUFFIX, id->cn);
449
450    return filename;
451}
452
453/**
454 * Write the private key to a file.
455 * Returns false if there's no private key loaded
456 * PEM format
457 */
458int abac_id_write_privkey(abac_id_t *id, FILE *out) {
459    assert(id != NULL);
460    if (id->key == NULL)
461        return ABAC_FAILURE;
462
463    int ret=abac_write_privkey_to_fp(id->key, out);
464    if (ret)
465        return ABAC_FAILURE;
466
467    return ABAC_SUCCESS;
468}
469
470/**
471 * Get a abac_chunk representing the id cert.
472 * caller is responsible to free up the chunk after use
473 */
474abac_chunk_t abac_id_cert_chunk(abac_id_t *id) {
475
476    assert(id); assert(id->cert);
477    unsigned char *ptr=abac_string_cert(id->cert);
478    int len=0;
479    if(ptr) len=strlen( (char *)ptr);
480
481    abac_chunk_t ret = { ptr, len };
482    return ret;
483}
484
485/**
486 * Get a abac_chunk representing the privkey cert.
487 */
488abac_chunk_t abac_id_privkey_chunk(abac_id_t *id) {
489
490    assert(id); assert(id->key);
491    unsigned char *ptr=abac_string_privkey(id->key);
492    int len=0;
493    if(ptr) len=strlen( (char *)ptr);
494
495    abac_chunk_t ret = { ptr, len };
496    return ret;
497}
498
499
500/**
501 * Copy a ID. Actually just increases its reference count.
502 */
503abac_id_t *abac_id_dup(abac_id_t *id) {
504    assert(id);
505    ++id->refcount;
506    return id;
507}
508
509void abac_id_free(abac_id_t *id) {
510    if (id == NULL)
511        return;
512
513    --id->refcount;
514    if (id->refcount > 0)
515        return;
516
517    // free once the reference count reaches 0
518    X509_free(id->cert);
519    EVP_PKEY_free(id->key);
520
521    free(id->keyid);
522    if(id->cn) free(id->cn);
523
524    free(id);
525}
526
Note: See TracBrowser for help on using the repository browser.