source: libabac/abac_id.c @ ec550f7

abac0-leakabac0-meimei-idtvf-new-xml
Last change on this file since ec550f7 was ec550f7, checked in by Mei <mei@…>, 11 years ago

1) reworked how API doc is generated
2) tweak top level Makefile.am
3) loading issuer principal as side-effect of loading

an attribute credentials

4) add examples of GENI specific attribute credentials

and principal certificates into the regression testing

5) rename examples to tests

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