source: libabac/abac_id.c @ c199a27

abac0-leakabac0-meimei-idtvf-new-xml
Last change on this file since c199a27 was c199a27, checked in by Ted Faber <faber@…>, 11 years ago

Remove a few assumptions about XML parsing.

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