source: libabac/abac_id.c @ 7764378

abac0-leak
Last change on this file since 7764378 was f2622ee, checked in by Mei-Hui Su <mei@…>, 6 years ago

1) ran with valgrind and did some leak patching

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