source: libabac/abac_id.c @ 23bc596

abac0-leak
Last change on this file since 23bc596 was 23bc596, checked in by Ted Faber <faber@…>, 11 years ago

Pass -Wall on Ubuntu

  • Property mode set to 100644
File size: 12.5 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    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   if ( asprintf(&pem,"%s%s%s",s,ptr,e) < 0 ) return NULL;
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_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        if (rc < 0 ) return -1;
385        } else {
386            tmp=(char *)ptr;
387    }
388
389
390    chunk->ptr=(unsigned char *)tmp;
391    chunk->len=strlen(tmp);
392
393    return ABAC_CERT_SUCCESS;
394}
395
396abac_chunk_t abac_id_in_PEM(abac_id_t *id) {
397    assert(id);
398    unsigned char *ptr=abac_string_cert(id->cert);
399    int len=0;
400    if(ptr)
401        len=strlen((char *)ptr);
402    abac_chunk_t ret = { ptr, len};
403    return ret;
404}
405
406
407int abac_id_still_valid(abac_id_t *id) {
408    assert(id);
409    return abac_still_valid(id->cert);
410}
411
412/**
413 * Get the default filename for the cert. Value must be freed by caller.
414 */
415char *abac_id_cert_filename(abac_id_t *id) {
416    assert(id != NULL);
417    assert(id->cn != NULL);
418
419    // malloc the filename
420    int len = strlen(id->cn) + strlen(CERT_SUFFIX) + 1;
421    char *filename = abac_xmalloc(len);
422    sprintf(filename, "%s" CERT_SUFFIX, id->cn);
423
424    return filename;
425}
426
427/**
428 * Write the ID cert to an open file pointer.
429 * pem format
430 */
431int abac_id_write_cert(abac_id_t *id, FILE *out) {
432    assert(id != NULL);
433
434    int ret=abac_write_id_to_fp(id->cert, out);
435    if(ret) return ABAC_FAILURE; 
436    return ABAC_SUCCESS;
437}
438
439/**
440 * Default private key filename. Value must be freed by caller.
441 */
442char *abac_id_privkey_filename(abac_id_t *id) {
443    assert(id != NULL);
444    assert(id->cn != NULL);
445
446    // malloc the filename
447    int len = strlen(id->cn) + strlen(KEY_SUFFIX) + 1;
448    char *filename = abac_xmalloc(len);
449    sprintf(filename, "%s" KEY_SUFFIX, id->cn);
450
451    return filename;
452}
453
454/**
455 * Write the private key to a file.
456 * Returns false if there's no private key loaded
457 * PEM format
458 */
459int abac_id_write_privkey(abac_id_t *id, FILE *out) {
460    assert(id != NULL);
461    if (id->key == NULL)
462        return ABAC_FAILURE;
463
464    int ret=abac_write_privkey_to_fp(id->key, out);
465    if (ret)
466        return ABAC_FAILURE;
467
468    return ABAC_SUCCESS;
469}
470
471/**
472 * Get a abac_chunk representing the id cert.
473 * caller is responsible to free up the chunk after use
474 */
475abac_chunk_t abac_id_cert_chunk(abac_id_t *id) {
476
477    assert(id); assert(id->cert);
478    unsigned char *ptr=abac_string_cert(id->cert);
479    int len=0;
480    if(ptr) len=strlen( (char *)ptr);
481
482    abac_chunk_t ret = { ptr, len };
483    return ret;
484}
485
486/**
487 * Get a abac_chunk representing the privkey cert.
488 */
489abac_chunk_t abac_id_privkey_chunk(abac_id_t *id) {
490
491    assert(id); assert(id->key);
492    unsigned char *ptr=abac_string_privkey(id->key);
493    int len=0;
494    if(ptr) len=strlen( (char *)ptr);
495
496    abac_chunk_t ret = { ptr, len };
497    return ret;
498}
499
500
501/**
502 * Copy a ID. Actually just increases its reference count.
503 */
504abac_id_t *abac_id_dup(abac_id_t *id) {
505    assert(id);
506    ++id->refcount;
507    return id;
508}
509
510void abac_id_free(abac_id_t *id) {
511    if (id == NULL)
512        return;
513
514    --id->refcount;
515    if (id->refcount > 0)
516        return;
517
518    // free once the reference count reaches 0
519    X509_free(id->cert);
520    EVP_PKEY_free(id->key);
521
522    free(id->keyid);
523    if(id->cn) free(id->cn);
524
525    free(id);
526}
527
Note: See TracBrowser for help on using the repository browser.