source: libabac/abac_id.c @ b92a620

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

1) route debug printf to stderr
2) add some check for swig in configure.ac (also yap)

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