source: libabac/abac_id.c @ f89b991

mei_rt2
Last change on this file since f89b991 was accd63d, checked in by Mei <mei@…>, 11 years ago

1) remove \n out of echo calls

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