source: libabac/abac_id.c @ 288a267

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

Make chunk operations take pointers.

  • 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    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.ptr = pem;
134    chunk.len = strlen(pem)+1;
135    X509 *cert=abac_load_id_from_chunk(chunk.ptr,chunk.len);
136    *sha1=NULL;
137    if(cert) {
138        *sha1 = abac_get_keyid(cert);
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    abac_chunk_free(&chunk);
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    /* free up the extracted pukey */
194    EVP_PKEY_free(pubkey);
195
196    id->key = key;
197    return ABAC_SUCCESS;
198}
199
200int abac_id_privkey_from_chunk(abac_id_t *id, abac_chunk_t chunk) {
201    assert(id != NULL);
202
203    EVP_PKEY *key=abac_load_privkey_from_chunk(chunk.ptr, chunk.len);
204    if (key == NULL) return ABAC_FAILURE;
205
206/* needs to make sure that the key matches up with the id */
207    /* extract the pub key from the id */
208    EVP_PKEY *pubkey=extract_pubkey_from_cert(id->cert);
209    /* cmp will just compare the pub key part of the key to see
210       if they are the same */
211    if(!EVP_PKEY_cmp(pubkey, key)) {
212        fprintf(stderr,"wrong private key for the cert!!\n");
213        return ABAC_FAILURE;
214    }
215
216    /* free up the extracted pukey */
217    EVP_PKEY_free(pubkey);
218
219    id->key = key;
220    return ABAC_SUCCESS;
221}
222
223/* pass a privkey from one id to another, very special case for
224   preloading issuer id when attribute is being loaded and when
225   there is an exising principal credential in the hashlist but
226   did not have its privkey setup yet */
227int abac_id_pass_privkey_from_id(abac_id_t *to_id, abac_id_t *from_id) {
228    EVP_PKEY *key=from_id->key;
229    from_id->key=NULL; /* reset the one in from so it does not get freed */
230    if (key==NULL) return ABAC_FAILURE;
231
232/* needs to make sure that the key matches up with the id */
233    /* extract the pub key from the id */
234    EVP_PKEY *pubkey=extract_pubkey_from_cert(to_id->cert);
235    /* cmp will just compare the pub key part of the key to see
236       if they are the same */
237    if(!EVP_PKEY_cmp(pubkey, key)) {
238        fprintf(stderr,"wrong private key for the cert!!\n");
239        return ABAC_FAILURE;
240    }
241
242    /* free up the extracted pukey */
243    EVP_PKEY_free(pubkey);
244
245    to_id->key = key;
246    return ABAC_SUCCESS;
247}
248
249/**
250 * Generate an ID with the specified CN and validity.
251 *
252 * validity is measured in seconds (as of 0.2.0)
253 */
254int abac_id_generate(abac_id_t **ret, char *cn, long validity) {
255    libabac_init();
256    if (cn == NULL || !abac_clean_name(cn))
257        return ABAC_GENERATE_INVALID_CN;
258
259    if (validity < 0)
260        return ABAC_GENERATE_INVALID_VALIDITY;
261
262    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
263
264    id->cn = abac_xstrdup(cn);
265    id->key = abac_generate_key();
266    id->cert = abac_generate_cert(id->key, cn, validity);
267    id->keyid = abac_get_keyid(id->cert);
268
269    id->refcount = 1;
270
271    *ret = id;
272    return ABAC_SUCCESS;
273}
274
275/**
276 * Generate an ID with the specified CN and validity.
277 *
278 * validity is measured in seconds (as of 0.2.0)
279 */
280int abac_id_generate_with_key(abac_id_t **ret, char *cn, long validity, char *keyfile) {
281    libabac_init();
282    if (cn == NULL || !abac_clean_name(cn))
283        return ABAC_GENERATE_INVALID_CN;
284
285    if (validity < 0)
286        return ABAC_GENERATE_INVALID_VALIDITY;
287
288    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
289
290    id->cn = abac_xstrdup(cn);
291    id->key = _load_privkey_from_file(keyfile);
292    id->cert = abac_generate_cert(id->key, cn, validity);
293    id->keyid = abac_get_keyid(id->cert);
294    id->refcount = 1;
295
296    *ret = id;
297    return ABAC_SUCCESS;
298}
299
300char *abac_id_keyid(abac_id_t *id) {
301    if(id) return id->keyid;
302        return NULL;
303}
304
305char *abac_id_cn(abac_id_t *id) {
306    if(id) return id->cn;
307        return NULL;
308}
309
310/**
311 * Get the issuer of an ID cert.
312 * Returns a malloc'd string that must be free'd.
313 */
314char *abac_id_issuer(abac_id_t *id) {
315    if(id) return abac_get_issuer(id->cert);
316        else return NULL;
317}
318
319/**
320 * Gets the subject DN of an ID cert.
321 * Returns a malloc'd string that must be free'd.
322 */
323char *abac_id_subject(abac_id_t *id) {
324    if(id) return abac_get_subject(id->cert);
325        else return NULL;
326}
327
328/**
329 * Get the validity period.
330 */
331int abac_id_validity(abac_id_t *id,struct tm *not_before,struct tm *not_after) {
332    assert(id);
333    if(abac_check_validity(id->cert, not_before, not_after)==0)
334        return ABAC_SUCCESS;
335    return ABAC_FAILURE;
336}
337
338X509 *abac_id_cert(abac_id_t *id) {
339    assert(id);
340    return id->cert;
341}
342
343// get the private key from the ID
344// will return NULL if no key has been loaded
345EVP_PKEY *abac_id_privkey(abac_id_t *id) {
346    assert(id);
347    return id->key;
348}
349
350int abac_id_has_privkey(abac_id_t *id) {
351    if(id && (id->key !=NULL))
352        return 1;
353    return 0;
354}
355
356// see if keyid is the same as id's
357int abac_id_has_keyid(abac_id_t *id, char *keyid)
358{
359    assert(id); assert(keyid);
360    if(strcmp(id->keyid, keyid) == 0)
361        return 1;
362    return 0;
363}
364
365/*
366   return a chunk with both id and key info,
367   err if missing privkey
368*/
369int abac_id_PEM(abac_id_t *id, abac_chunk_t *chunk) {
370    if(id==NULL)
371        return ABAC_CERT_MISSING_ISSUER;
372    if(id->key == NULL)
373        return ABAC_CERT_SIGNER_NOKEY;
374
375    unsigned char *kptr=NULL;
376    unsigned char *ptr=abac_string_cert(id->cert);
377    if(id->key)
378        kptr=abac_string_privkey(id->key);
379   
380    char *tmp=NULL;
381    if(kptr)  {
382        int rc=asprintf(&tmp,"%s%s", ptr,kptr);
383        free(ptr);
384        free(kptr);
385        } else {
386            tmp=(char *)ptr;
387    }
388
389
390    chunk->ptr=(unsigned char *)tmp;
391    chunk->len=strlen(tmp)+1;
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)+1;
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)+1;
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)+1;
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.