source: libabac/abac_id.c @ 3c30b59

abac0-leakabac0-mei
Last change on this file since 3c30b59 was 3c30b59, checked in by Mei <mei@…>, 11 years ago

1) add in new refactored regression testing directory
2) undo the abac.hh/ABAC.hh api changes
3) merged with Ted's changes to attribute format/nickname/issuer processing

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