source: libabac/abac_id.c @ 4f40c3e

mei_rt2mei_rt2_fix_1
Last change on this file since 4f40c3e was dfe6b61, checked in by Mei <mei@…>, 12 years ago

1) added ID_chunk() and Attribute_chunk() to abac.hh

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