source: libabac/abac_id.c @ c0fe894

abac0-leak
Last change on this file since c0fe894 was 4f79997, checked in by Mei <mei@…>, 11 years ago

1) add a new scaling test -haystack/ralphs
2) tweak some libabac code here and there

  • Property mode set to 100644
File size: 12.3 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
294char *abac_id_cn(abac_id_t *id) {
295    if(id) return id->cn;
296        return NULL;
297}
298
299/**
300 * Get the issuer of an ID cert.
301 * Returns a malloc'd string that must be free'd.
302 */
303char *abac_id_issuer(abac_id_t *id) {
304    if(id) return abac_get_issuer(id->cert);
305        else return NULL;
306}
307
308/**
309 * Gets the subject DN of an ID cert.
310 * Returns a malloc'd string that must be free'd.
311 */
312char *abac_id_subject(abac_id_t *id) {
313    if(id) return abac_get_subject(id->cert);
314        else return NULL;
315}
316
317/**
318 * Get the validity period.
319 */
320int abac_id_validity(abac_id_t *id,struct tm *not_before,struct tm *not_after) {
321    assert(id);
322    if(abac_check_validity(id->cert, not_before, not_after)==0)
323        return ABAC_SUCCESS;
324    return ABAC_FAILURE;
325}
326
327X509 *abac_id_cert(abac_id_t *id) {
328    assert(id);
329    return id->cert;
330}
331
332// get the private key from the ID
333// will return NULL if no key has been loaded
334EVP_PKEY *abac_id_privkey(abac_id_t *id) {
335    assert(id);
336    return id->key;
337}
338
339int abac_id_has_privkey(abac_id_t *id) {
340    if(id && (id->key !=NULL))
341        return 1;
342    return 0;
343}
344
345// see if keyid is the same as id's
346int abac_id_has_keyid(abac_id_t *id, char *keyid)
347{
348    assert(id); assert(keyid);
349    if(strcmp(id->keyid, keyid) == 0)
350        return 1;
351    return 0;
352}
353
354/*
355   return a chunk with both id and key info,
356   err if missing privkey
357*/
358int abac_id_PEM(abac_id_t *id, abac_chunk_t *chunk) {
359    if(id==NULL)
360        return ABAC_CERT_MISSING_ISSUER;
361    if(id->key == NULL)
362        return ABAC_CERT_SIGNER_NOKEY;
363
364    unsigned char *kptr=NULL;
365    unsigned char *ptr=abac_string_cert(id->cert);
366    if(id->key)
367        kptr=abac_string_privkey(id->key);
368    int len=0;
369   
370    char *tmp=NULL;
371    if(kptr)  {
372        int rc=asprintf(&tmp,"%s%s", ptr,kptr);
373        free(ptr);
374        free(kptr);
375        } else {
376            tmp=(char *)ptr;
377    }
378    len=strlen(tmp);
379
380    chunk->ptr=(unsigned char *)tmp;
381    chunk->len=len;
382    return ABAC_CERT_SUCCESS;
383}
384
385abac_chunk_t abac_id_in_PEM(abac_id_t *id) {
386    assert(id);
387    unsigned char *ptr=abac_string_cert(id->cert);
388    int len=0;
389    if(ptr)
390        len=strlen((char *)ptr);
391    abac_chunk_t ret = {ptr, len };
392    return ret;
393}
394
395
396int abac_id_still_valid(abac_id_t *id) {
397    assert(id);
398    return abac_still_valid(id->cert);
399}
400
401/**
402 * Get the default filename for the cert. Value must be freed by caller.
403 */
404char *abac_id_cert_filename(abac_id_t *id) {
405    assert(id != NULL);
406    assert(id->cn != NULL);
407
408    // malloc the filename
409    int len = strlen(id->cn) + strlen(CERT_SUFFIX) + 1;
410    char *filename = abac_xmalloc(len);
411    sprintf(filename, "%s" CERT_SUFFIX, id->cn);
412
413    return filename;
414}
415
416/**
417 * Write the ID cert to an open file pointer.
418 * pem format
419 */
420int abac_id_write_cert(abac_id_t *id, FILE *out) {
421    assert(id != NULL);
422
423    int ret=abac_write_id_to_fp(id->cert, out);
424    if(ret) return ABAC_FAILURE; 
425    return ABAC_SUCCESS;
426}
427
428/**
429 * Default private key filename. Value must be freed by caller.
430 */
431char *abac_id_privkey_filename(abac_id_t *id) {
432    assert(id != NULL);
433    assert(id->cn != NULL);
434
435    // malloc the filename
436    int len = strlen(id->cn) + strlen(KEY_SUFFIX) + 1;
437    char *filename = abac_xmalloc(len);
438    sprintf(filename, "%s" KEY_SUFFIX, id->cn);
439
440    return filename;
441}
442
443/**
444 * Write the private key to a file.
445 * Returns false if there's no private key loaded
446 * PEM format
447 */
448int abac_id_write_privkey(abac_id_t *id, FILE *out) {
449    assert(id != NULL);
450    if (id->key == NULL)
451        return ABAC_FAILURE;
452
453    int ret=abac_write_privkey_to_fp(id->key, out);
454    if (ret)
455        return ABAC_FAILURE;
456
457    return ABAC_SUCCESS;
458}
459
460/**
461 * Get a abac_chunk representing the id cert.
462 */
463abac_chunk_t abac_id_cert_chunk(abac_id_t *id) {
464
465    assert(id); assert(id->cert);
466    unsigned char *ptr=abac_string_cert(id->cert);
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 * Get a abac_chunk representing the privkey cert.
476 */
477abac_chunk_t abac_id_privkey_chunk(abac_id_t *id) {
478
479    assert(id); assert(id->key);
480    unsigned char *ptr=abac_string_privkey(id->key);
481    int len=0;
482    if(ptr) len=strlen( (char *)ptr);
483
484    abac_chunk_t ret = { ptr, len };
485    return ret;
486}
487
488
489/**
490 * Copy a ID. Actually just increases its reference count.
491 */
492abac_id_t *abac_id_dup(abac_id_t *id) {
493    assert(id);
494    ++id->refcount;
495    return id;
496}
497
498void abac_id_free(abac_id_t *id) {
499    if (id == NULL)
500        return;
501
502    --id->refcount;
503    if (id->refcount > 0)
504        return;
505
506    // free once the reference count reaches 0
507    X509_free(id->cert);
508    EVP_PKEY_free(id->key);
509
510    free(id->keyid);
511    free(id);
512}
513
Note: See TracBrowser for help on using the repository browser.