source: libabac/abac_id.c

Last change on this file was c19da53, checked in by Mei <mei@…>, 11 years ago

Merge branch 'abac0-leak' of git://abac.deterlab.net/abac

Conflicts:

libabac/abac_id.c

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