source: libabac/abac_id.c @ e97d2e2

mei_rt2_fix_1
Last change on this file since e97d2e2 was d34f7ef, checked in by Mei <mei@…>, 11 years ago

1) accidentally commited some debug statements

  • Property mode set to 100644
File size: 14.5 KB
Line 
1
2/**
3**  abac_id.c
4**/
5
6#include <assert.h>
7#include <err.h>
8#include <time.h>
9
10// include the GNU extension of asprintf
11#define _GNU_SOURCE
12#include <stdio.h>
13#include <err.h>
14
15#include "abac_internal.h"
16#include "abac_util.h"
17
18static int debug=0;
19static int yes=1;
20
21#define KEY_SUFFIX  "_private.pem"
22#define CERT_SUFFIX "_ID.pem"
23
24extern private_key_t *abac_key_private_key(abac_key_t *ptr);
25extern abac_key_t *abac_key_file_new(char *filename, chunk_t potato);
26extern abac_key_t *abac_key_chunk_new(chunk_t keyblob, chunk_t potato);
27extern chunk_t abac_key_chunk(abac_key_t *);
28
29static int _abac_id_set_cn(abac_id_t *id, char* cn);
30
31//
32// abac_id object
33//
34struct _abac_id_t {
35    int idtype;    /* default to string 'keyid' for now */
36
37    char *keyid; /* sha */
38    char *cn;
39
40    certificate_t *cert;
41    abac_key_t *key;
42
43    int refcount;
44};
45
46/****************************************************************/
47//
48// Helper functions below
49//
50static int _add_into_id_credentials(abac_id_t *id) 
51{
52    char *keyid=abac_id_keyid(id);
53    abac_id_credential_t *idcred=abac_id_credential_lookup(keyid);
54    if(idcred !=NULL) {
55       if(debug) fprintf(stderr,"_add_into_id_credentials: something in there for %s\n",keyid);
56       } else {
57          if(debug) fprintf(stderr,"_add_into_id_credentials: adding %s\n",keyid);
58          if(yes) {
59             abac_verifier_add_id_credential(abac_id_dup(id));
60          }
61    }
62}
63
64static char *_get_keyid(certificate_t *cert) {
65    // get the keyid
66    x509_t *x509 = (x509_t *)cert;
67    chunk_t keyid = x509->get_subjectKeyIdentifier(x509);
68    chunk_t string = chunk_to_hex(keyid, NULL, 0);
69    return (char *)string.ptr;
70}
71
72static char *_create_dn(char *cn) {
73
74#define DN "cn="
75
76    char *dn = abac_xmalloc(sizeof(DN) + strlen(cn));
77    memcpy(dn, DN, sizeof(DN));
78    strcat(dn, cn);
79
80    return dn;
81}
82
83/**
84 * Generate ID certificate.
85 *
86 * validity is measured in seconds (as of 0.2.0)
87 */
88static certificate_t *_generate_cert(abac_key_t *keyptr, char *cn, int validity) {
89    // build the DN
90    char *dn_string = _create_dn(cn);
91    libabac_init();
92
93    identification_t *id = identification_create_from_string(dn_string);
94    if (id == NULL)
95        errx(1, "couldn't create ID from DN %s", dn_string);
96    free(dn_string);
97
98    // get the private key
99    private_key_t *private = abac_key_private_key(keyptr);
100    if(private == NULL)
101        errx(1, "couldn't create ID without private key");
102
103    public_key_t *public = private->get_public_key(private);
104    if (public == NULL)
105        errx(1, "couldn't get public key from private key");
106
107    // create a serial (stolen from strongswan pki)
108    rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
109    if (!rng)
110        errx(1, "no random number generator");
111
112    // random serial
113    chunk_t serial = abac_generate_serial();
114
115    // validity period
116    time_t not_before = time(NULL);
117    time_t not_after = not_before + validity;
118
119    // create!
120    certificate_t *cert = lib->creds->create(lib->creds,
121        CRED_CERTIFICATE, CERT_X509,
122        BUILD_SIGNING_KEY, private,
123        BUILD_PUBLIC_KEY, public,
124        BUILD_SUBJECT, id,
125        BUILD_NOT_BEFORE_TIME, not_before,
126        BUILD_NOT_AFTER_TIME, not_after,
127        BUILD_SERIAL, serial,
128        BUILD_DIGEST_ALG, HASH_SHA1,
129        BUILD_X509_FLAG, X509_CA,
130        BUILD_PATHLEN, X509_NO_CONSTRAINT,
131        BUILD_END
132    );
133    if (cert == NULL)
134        errx(1, "couldn't build cert :(");
135
136    DESTROY_IF(id);
137    DESTROY_IF(public);
138    DESTROY_IF(private);
139    free(serial.ptr);
140
141    return cert;
142}
143
144#define BYTES_PER_LINE 64
145
146// thx libstrongswan
147static void _encode_base64(FILE *out, chunk_t encoding) {
148    int start;
149
150    chunk_t b64 = chunk_to_base64(encoding, NULL);
151
152    fprintf(out, "-----BEGIN CERTIFICATE-----\n");
153
154    for (start = 0; start < b64.len; start += BYTES_PER_LINE) {
155        int left = b64.len - start;
156        int len = left < BYTES_PER_LINE ? left : BYTES_PER_LINE;
157        fwrite(b64.ptr + start, len, 1, out);
158        fprintf(out, "\n");
159    }
160
161    fprintf(out, "-----END CERTIFICATE-----\n");
162
163    free(b64.ptr);
164}
165/****************************************************************/
166int abac_id_idtype(abac_id_t *id)
167{
168    assert(id != NULL);
169    return id->idtype;
170}
171
172char* abac_id_idtype_string(abac_id_t *id)
173{
174    assert(id != NULL);
175    return abac_idtype_string(id->idtype);
176}
177
178char *abac_id_keyid(abac_id_t *id) {
179    assert(id != NULL);
180    return id->keyid;
181}
182
183char *abac_id_cn(abac_id_t *id) {
184    assert(id != NULL);
185    return id->cn;
186}
187
188static int _abac_id_set_cn(abac_id_t *id, char* cn) {
189    if(cn) {
190        if(id->cn != NULL)
191            free(id->cn);
192        id->cn = abac_xstrdup(cn);
193    }
194    return 0;
195}
196
197
198char *abac_id_name(abac_id_t *id)
199{
200    assert(id != NULL);
201    if(USE("ABAC_CN"))
202        return abac_id_cn(id);
203    else return abac_id_keyid(id);
204}
205
206char *abac_id_string(abac_id_t *id) 
207{
208    char *tmp=NULL;
209    if(abac_id_has_privkey(id)) 
210        asprintf(&tmp,"(%s,%s,y)",abac_id_name(id),abac_id_idtype_string(id));
211        else asprintf(&tmp,"(%s,%s,n)",abac_id_name(id),abac_id_idtype_string(id));
212    return tmp;
213}
214
215/**
216 * Get the issuer of an ID cert.
217 * Returns a malloc'd string that must be free'd.
218 */
219char *abac_id_issuer(abac_id_t *id) {
220    char *ret;
221    int rv = asprintf(&ret, "%Y", id->cert->get_issuer(id->cert));
222
223    if (rv < 0)
224        err(1, "couldn't malloc string for issuer\n");
225
226    return ret;
227}
228
229int abac_id_lastone(abac_id_t *ptr)
230{
231    assert(ptr);
232    if(ptr->refcount == 1)
233        return 1;
234    return 0;
235}
236
237
238/**
239 * Gets the subject DN of an ID cert.
240 * Returns a malloc'd string that must be free'd.
241 */
242char *abac_id_subject(abac_id_t *id) {
243    char *ret;
244    int rv = asprintf(&ret, "%Y", id->cert->get_subject(id->cert));
245
246    if (rv < 0)
247        err(1, "couldn't malloc string for subject\n");
248
249    return ret;
250}
251
252/**
253 * Get the validity period.
254 */
255void abac_id_validity(abac_id_t *id, time_t *not_before, time_t *not_after) {
256    id->cert->get_validity(id->cert, NULL, not_before, not_after);
257}
258
259certificate_t *abac_id_cert(abac_id_t *id) {
260    assert(id != NULL);
261    return id->cert;
262}
263
264private_key_t *abac_id_privkey(abac_id_t *id) {
265    assert(id != NULL);
266    if(id->key !=0)
267        return abac_key_private_key(id->key);
268    return NULL;
269}
270
271abac_key_t *abac_id_keyptr(abac_id_t *id)
272{
273    return id->key;
274}
275
276int abac_id_has_privkey(abac_id_t *id) {
277    if(id && id->key !=0)
278       return 1;
279    return 0;
280}
281
282
283/**
284 * Write the ID cert to an open file pointer.
285 */
286void abac_id_write_cert(abac_id_t *id, FILE *out) {
287    assert(id != NULL);
288
289    chunk_t encoding = chunk_empty;
290    int rc=id->cert->get_encoding(id->cert,CERT_ASN1_DER,&encoding);
291    if(rc) {
292        _encode_base64(out, encoding);
293        free(encoding.ptr);
294    }
295}
296
297/**
298 * Write the private key to a file.
299 * Returns false if there's no private key loaded
300 */
301int abac_id_write_privkey(abac_id_t *id, FILE *out)
302{
303    return abac_key_write_privkey(id->key, out);
304}
305
306/**
307 * Get a DER-encoded chunk representing the cert.
308 */
309abac_chunk_t abac_id_cert_chunk(abac_id_t *id) {
310    assert(id->cert);
311    chunk_t encoding = chunk_empty;
312    int rc= id->cert->get_encoding(id->cert, CERT_ASN1_DER, &encoding);
313    abac_chunk_t ret= { encoding.ptr, encoding.len };
314    return ret;
315}
316
317/**
318 * Get a PEM-encoded chunk representing the private key
319 */
320abac_chunk_t abac_id_privkey_chunk(abac_id_t *id) 
321{
322    chunk_t tmp=chunk_empty;
323    if(id->key)
324         tmp=abac_key_chunk(id->key);
325    abac_chunk_t ret= {tmp.ptr, tmp.len};
326    return ret;
327}
328
329void abac_id_print_key_chunk(abac_id_t *id)
330{
331   if(id->key)
332       print_abac_key("abac_id_print_key_chunk",id->key);
333}
334
335/**
336 * Copy an abac ID. Actually just increases its reference count.
337 */
338abac_id_t *abac_id_dup(abac_id_t *id) {
339    if(id)
340        ++id->refcount;
341    return id;
342}
343
344void abac_id_free(abac_id_t *id) {
345    if (id == NULL)
346        return;
347
348    --id->refcount;
349    if (id->refcount > 0)
350        return;
351
352    if(debug)
353        fprintf(stderr,"making abac_id_free call on (%s)!!!\n", id->cn);
354    // free once the reference count reaches 0
355    DESTROY_IF(id->cert);
356
357    if(id->key) abac_key_free(id->key);
358
359    free(id->keyid);
360    free(id->cn);
361    free(id);
362}
363
364/****************************************************************/
365/**
366 * Default private key filename. Value must be freed by caller.
367 */
368char *abac_id_privkey_filename(abac_id_t *id) {
369    assert(id != NULL);
370    assert(id->cn != NULL);
371
372    /* this cn has pCN attached to it */
373    char *filename = NULL;
374    char* ptr=id->cn;
375    asprintf(&filename, "%s%s",(ptr+1),KEY_SUFFIX);
376    return filename;
377}
378
379/**
380 * Get the default filename for the cert. Value must be freed by caller.
381 */
382char *abac_id_cert_filename(abac_id_t *id) {
383    assert(id != NULL);
384    assert(id->cn != NULL);
385
386    /* this cn has pCN attached to it */
387    char *filename = NULL;
388    char* ptr=id->cn;
389    asprintf(&filename, "%s%s",(ptr+1),CERT_SUFFIX);
390    return filename;
391}
392
393/****************************************************************/
394
395/*
396** Create an ID from tidbits info
397*/
398abac_id_t *abac_id_new(int idtype,char *keyid, char *cn, 
399certificate_t *cert)
400{
401    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
402    id->idtype = idtype;
403    id->keyid = abac_xstrdup(keyid);
404    id->cn = abac_xstrdup(cn);
405    id->cert = cert;
406    id->key = NULL;
407    id->refcount = 1;
408    if(debug) fprintf(stderr,"abac_id_new: made a new id, %ld\n",(long) id);
409    _add_into_id_credentials(id);
410    return id;
411}
412
413abac_id_t *abac_id_keyid_new(char *keyid, char *cn, certificate_t *cert)
414{
415    return abac_id_new(e_KEYID,keyid,cn,cert); 
416}
417
418static abac_id_t *_abac_id_from_cert(certificate_t *cert) {
419    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
420    id->idtype = e_KEYID;
421    id->keyid = NULL;
422    id->cn = NULL;
423    id->cert = cert;
424    id->key = NULL;
425
426    id->keyid = _get_keyid(id->cert);
427    // get the CN from the cert
428    id_part_t type;
429    chunk_t data;
430
431    identification_t *cert_id = id->cert->get_subject(id->cert);
432    enumerator_t *id_enum = cert_id->create_part_enumerator(cert_id);
433    while (id_enum->enumerate(id_enum, &type, &data))
434        if (type == ID_PART_RDN_CN) {
435            id->cn = abac_xmalloc(data.len + 2);
436            id->cn[0]='p';
437            memcpy(&id->cn[1], data.ptr, data.len);
438            id->cn[data.len+1] = 0;
439        }
440    id_enum->destroy(id_enum);
441
442    if(id->cn != NULL) {
443        if(debug) fprintf(stderr, "_abac_id_from_cert, found cn (%s)\n", id->cn);
444        } else { /* have to prepend a p */
445            char *tmp=NULL;
446            asprintf(&tmp,"p%s",id->keyid);
447            _abac_id_set_cn(id,tmp);
448            free(tmp);
449            if(debug) fprintf(stderr,"_abac_id_from_cert, did not find cn, set it to (%s)\n", id->cn);
450    }
451
452    id->refcount = 1;
453    _add_into_id_credentials(id);
454    return id;
455}
456
457/**
458 * Create an ID cert from a file.
459 * this one does not add id into id hash list
460 */
461abac_id_t *abac_id_from_file(char *filename) {
462
463    /* make sure file exists */
464    if(!file_exist(filename)) return NULL;
465
466    libabac_init();
467    certificate_t *cert = lib->creds->create(lib->creds,
468        CRED_CERTIFICATE, CERT_X509,
469        BUILD_FROM_FILE, filename,
470        BUILD_X509_FLAG, X509_AA,
471        BUILD_END
472    );
473
474    if (cert == NULL)
475        return NULL;
476
477    return _abac_id_from_cert(cert);
478}
479
480/**
481 * Create an ID cert from a chunk.
482 */
483abac_id_t *abac_id_from_chunk(abac_chunk_t achunk) {
484    chunk_t chunk = { .ptr = achunk.ptr, .len = achunk.len };
485
486    certificate_t *cert = lib->creds->create(lib->creds,
487        CRED_CERTIFICATE, CERT_X509,
488        BUILD_BLOB_ASN1_DER, chunk,
489        BUILD_X509_FLAG, X509_AA,
490        BUILD_END
491    );
492
493    if (cert == NULL)
494        return NULL;
495
496    return _abac_id_from_cert(cert);
497}
498
499/**
500 * Generate an ID with the specified CN and validity.
501 *
502 * validity is measured in seconds (as of 0.2.0)
503 */
504int abac_id_generate(abac_id_t **ret, char *cn, int validity)
505{
506    if (cn == NULL || !abac_validate_clean_name(cn))
507        return ABAC_ID_GENERATE_INVALID_CN;
508
509    if(debug) fprintf(stderr,"abac_id_generate: generating id with cn(%s)\n",cn);
510
511    if (validity < 0)
512        return ABAC_ID_GENERATE_INVALID_VALIDITY;
513
514    if (validity == 0) validity = 1080 * 86400;
515
516    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
517
518    /* add p to cn here */
519    char *tmp=NULL;
520    asprintf(&tmp,"p%s",cn);
521    id->idtype = e_KEYID;
522    id->cn = tmp;
523    id->key = abac_key_generate();
524    id->cert = _generate_cert(id->key, cn, validity);
525    id->keyid = _get_keyid(id->cert);
526
527    id->refcount = 1;
528    _add_into_id_credentials(id);
529
530    *ret = id;
531    return ABAC_ID_SUCCESS;
532}
533
534
535/**
536 * Generate an ID with the specified CN and validity and a passphrase.
537 *
538 * validity is measured in seconds (as of 0.2.0)
539 */
540int abac_id_generate_with_key(abac_id_t **ret, char *cn, int validity, char *filename, char *pfile) {
541    if (cn == NULL || !abac_validate_clean_name(cn))
542        return ABAC_ID_GENERATE_INVALID_CN;
543
544    if(debug) {
545        fprintf(stderr,"abac_id_generate: generating id with cn(%s) and privkey(%s)",
546                                                    cn, filename);
547        if(pfile) fprintf(stderr,"pfile(%s)\n",pfile);
548            else fprintf(stderr,"\n");
549    }
550
551    if (validity < 0)
552        return ABAC_ID_GENERATE_INVALID_VALIDITY;
553
554    if (validity == 0) validity = 1080 * 86400;
555
556    chunk_t pp=chunk_empty;
557    if(pfile && strlen(pfile)!=0) {
558        if(!file_exist(pfile))
559            errx(1, "passphrase file does not exist!!\n");
560        pp=extract_potato(filename,pfile);
561    }
562
563    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
564    char *tmp=NULL;
565    asprintf(&tmp,"p%s",cn);
566    id->idtype = e_KEYID;
567    id->cn = tmp;
568    id->key = abac_key_file_new(filename,pp);
569    id->cert = _generate_cert(id->key, cn, validity);
570    id->keyid = _get_keyid(id->cert);
571
572    id->refcount = 1;
573    _add_into_id_credentials(id);
574
575    *ret = id;
576    return ABAC_ID_SUCCESS;
577}
578
579int abac_id_load_privkey_file(abac_id_t *ptr, char *keyfile)
580{
581    assert(ptr);
582    ptr->key=abac_key_file_new(keyfile, chunk_empty);
583    return 1;
584}
585
586int abac_id_load_enc_privkey_file(abac_id_t *ptr, char *keyfile, char *pfile)
587{
588    assert(ptr);
589    chunk_t pp=extract_potato(keyfile,pfile);
590    ptr->key=abac_key_file_new(keyfile, pp);
591    return 1;
592}
593
594int abac_id_load_privkey_chunk(abac_id_t *ptr, chunk_t keychunk)
595{
596    assert(ptr);
597    ptr->key=abac_key_chunk_new(keychunk, chunk_empty);
598    if(debug)
599        print_abac_key("after abac_id_load_privkey_chunk", ptr->key);
600    return 1;
601}
602
603int abac_id_load_enc_privkey_chunk(abac_id_t *ptr, chunk_t keychunk, char *pfile)
604{
605    assert(ptr);
606    chunk_t pp=extract_potato(NULL,pfile);
607    ptr->key=abac_key_chunk_new(keychunk, pp);
608    return 1;
609}
610
Note: See TracBrowser for help on using the repository browser.