source: libabac/abac_id.c @ ca402ad

abac0-leak
Last change on this file since ca402ad was 8164e70, checked in by Mei <mei@…>, 11 years ago

1) tweak with changes for handling abac_chunk_t

  • 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=abac_chunk_new(pem,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        int rc=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=len;
391*/
392    *chunk=abac_chunk_new(tmp,strlen(tmp));
393
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 = abac_chunk_new(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 = abac_chunk_new(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 = abac_chunk_new(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.