source: libabac/abac_id.c @ a02c849

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

1) add examples from wiki into regression tests
2) add code to complete the support of combo id/privkey file format
3) update abac.hh/API

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