source: libabac/abac_attribute.c @ f89b991

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

1) added namespace
2) tweak ?This,
3) allowing linking role/oset as constraining conditions
4) adding access_tests regression testing that uses GENI's access policy
5) added couple multi contexts regression tests
6) add compression/uncompression calls to abac_encode_string/abac_decode_string
(libstrongwan only allows 512 char for attribute rule storage)
7) add attribute_now option to creddy that takes a whole char string for attribute
rule

  • Property mode set to 100644
File size: 17.9 KB
Line 
1/**
2**  abac_attribute.c
3**/
4
5#include <assert.h>
6#include <ctype.h>
7#include <string.h>
8#include <time.h>
9
10#include <credentials/certificates/x509.h>
11#include <credentials/certificates/certificate.h>
12#include <credentials/certificates/ac.h>
13
14#include "abac_util.h"
15#include "abac_aspect.h"
16#include "abac_m64.h"
17#include "abac_id.h"
18#include "abac_pl_yy.h"
19#include "rt2_yy.h"
20#include "abac_verifier.h"
21#include "abac_util_cert.h"
22#include "abac_id.h"
23
24/*****************************************************************/
25static int debug=0;
26
27/* the correct setting of using_this depends on user if the attribute is
28   not generate from yyparse call */
29struct _abac_attribute_t {
30    abac_id_t *issuer_id; 
31    abac_aspect_t *head;
32    abac_aspect_t *tail;
33    int validity;
34    int using_this; /* tracking use of (?This) */
35    certificate_t *cert; // NULL until baked
36    certificate_t *issuer_cert;
37
38    int refcount;
39};
40
41/* local */
42abac_attribute_t *abac_attribute_set_head(abac_attribute_t *ptr, abac_aspect_t *head);
43abac_aspect_t *abac_attribute_head(abac_attribute_t *ptr);
44abac_aspect_t *abac_attribute_tail(abac_attribute_t *ptr);
45abac_attribute_t *abac_attribute_add_tail(abac_attribute_t *ptr, abac_aspect_t *tail);
46void abac_attribute_set_using_this(abac_attribute_t *ptr, int using_this);
47
48/********************************************************************/
49/* currently the hashkeyid is the uuencoded 'sha attribute string'  */
50char *get_cred_encoding(abac_attribute_t *ptr)
51{
52    char *encoding=NULL;
53 
54    /* must have a head aspect and tail aspect */
55    assert(ptr->head != NULL);
56    assert(ptr->tail != NULL);
57
58    if(ptr->cert != NULL) { /* already a baked one */
59        ac_t *ac = (ac_t *)ptr->cert;
60        ietf_attributes_t *attr_cert = ac->get_groups(ac);
61        char *encoded_attr_string=attr_cert->get_string(attr_cert);
62        return encoded_attr_string;
63    }
64
65    /* not a baked one should not be in ABAC_CN mode at all !!! */
66    /* needs to be the one with sha */
67    if(USE("ABAC_CN")) {
68        fprintf(stderr,"get_cred_encoding, MIGHT be BAD..\n");
69    } 
70    char *head_string=abac_aspect_typed_string_with_condition(ptr->head);
71    char *tail_string=abac_aspect_typed_string_with_condition(ptr->tail);
72
73    asprintf(&encoding,"%s<-%s", head_string,tail_string);
74    char* base64_encoding=abac_encode_string(encoding);
75
76    if(USE("ABAC_CN")) {
77        fprintf(stderr,"    --> (%s)\n", encoding);
78    }
79
80    free(encoding);
81    free(head_string);
82    free(tail_string);
83    return base64_encoding;
84}
85
86static abac_attribute_t *_abac_attribute_init()
87{
88    abac_attribute_t *ptr = abac_xmalloc(sizeof(abac_attribute_t));
89    ptr->issuer_id = NULL;
90    ptr->head = NULL;
91    ptr->tail = NULL;
92    ptr->validity= 365 * 86400; // default
93    // NULL until baked
94    ptr->using_this=0;
95    ptr->cert= NULL;
96    ptr->issuer_cert= NULL;
97    ptr->refcount=1;
98    return ptr;
99}
100
101/********************************************************************/
102abac_attribute_t *abac_attribute_new(abac_id_t *issuer, certificate_t *cert,
103certificate_t *issuer_cert)
104{
105    abac_attribute_t *ptr = _abac_attribute_init();
106    ptr->issuer_id = abac_id_dup(issuer);
107    ptr->cert=cert; // already baked..
108    ptr->issuer_cert=issuer_cert;
109    ptr->refcount=1;
110    return ptr;
111}
112
113// validity is measured in seconds (as of 0.2.0)
114// remember using_this,
115int abac_attribute_create(abac_attribute_t **ret, abac_aspect_t *head, 
116abac_aspect_t *tail, int validity)
117{
118    abac_id_t *issuer_id=abac_aspect_get_issuer_id(head);
119    if(debug)
120        print_abac_key("abac_attribute_create" , abac_id_keyptr(issuer_id));
121
122    char *name=abac_aspect_aspect_name(head);
123
124    if (!abac_id_has_privkey(issuer_id))
125        return ABAC_ATTRIBUTE_ISSUER_NOKEY;
126    if (!abac_validate_clean_aspect_name(name))
127        return ABAC_ATTRIBUTE_INVALID_ROLE;
128    if (validity < 0)
129        return ABAC_ATTRIBUTE_INVALID_VALIDITY;
130
131    abac_attribute_t *ptr = _abac_attribute_init();
132    ptr->issuer_id = abac_id_dup(issuer_id);
133    ptr->head = abac_aspect_dup(head);
134    if(tail)
135        ptr->tail = abac_aspect_dup(tail);
136    ptr->validity=(validity==0?(365 * 86400):validity);
137
138    *ret = ptr;
139    return ABAC_ATTRIBUTE_SUCCESS;
140}
141
142// validity is measured in seconds (as of 0.2.0)
143int abac_attribute_create_creddy(abac_attribute_t **ret, abac_id_t *issuer, 
144abac_aspect_t *head_aspect, abac_aspect_t *tail_aspect, char *name,
145int validity)
146{
147    if (!abac_id_has_privkey(issuer))
148        return ABAC_ATTRIBUTE_ISSUER_NOKEY;
149    if (!abac_validate_clean_aspect_name(name))
150        return ABAC_ATTRIBUTE_INVALID_ROLE;
151    if (validity < 0)
152        return ABAC_ATTRIBUTE_INVALID_VALIDITY;
153
154    abac_attribute_t *ptr = _abac_attribute_init();
155    ptr->issuer_id = abac_id_dup(issuer);
156    ptr->head=head_aspect;
157    ptr->tail=tail_aspect;
158    ptr->validity = validity;
159
160    *ret = ptr;
161    return ABAC_ATTRIBUTE_SUCCESS;
162}
163
164static void _check_cert_group(certificate_t *cert, char *estring)
165{
166    ietf_attributes_t *attr_cert = NULL;
167    int ret, i;
168
169    // get the attr
170    ac_t *ac = (ac_t *)cert;
171    attr_cert = ac->get_groups(ac);
172    if(attr_cert == NULL) {
173        fprintf(stderr,"BAD group from the cert !!!\n");
174        return;
175    }
176    char *encoded_attr_string=attr_cert->get_string(attr_cert);
177    if(encoded_attr_string==NULL) {
178        fprintf(stderr,"BAD empty, encoded attr string from the cert !!!\n");
179/*
180    chunk_t b64 = chunk_to_base64(chunk, NULL);
181    chunk_t chk = chunk_from_base64(base64, NULL);
182*/
183       int len = strlen(estring);
184       chunk_t b64 = { estring, len };
185       chunk_t chk= chunk_from_base64(b64, NULL);
186       chk.ptr[chk.len]='\0';
187       fprintf(stderr,"new convert: (%s)\n", chk.ptr);
188       chunk_t nb64 = chunk_to_base64(chk, NULL);
189       fprintf(stderr,"back again: (%d)(%s)\n", strlen(nb64.ptr), nb64.ptr);
190    }
191}
192
193int abac_attribute_bake(abac_attribute_t *ptr) {
194    assert(ptr);
195
196    char *cred_encoding = get_cred_encoding(ptr);
197
198    // create attribute cert
199    time_t not_before = time(NULL);
200    time_t not_after = not_before + ptr->validity;
201    chunk_t serial = abac_generate_serial();
202
203    private_key_t *private = abac_id_privkey(ptr->issuer_id);
204
205    if(private==NULL)
206        errx(1,"can not bake without a private key!!!"); 
207
208/**** XXX this needs to be removed !!!!! limitation from strongswan... ****/
209    if(strlen(cred_encoding) > 512) {
210        fprintf(stderr,"due to BUILD_IETF_GROUP_ATTR buffer size limit, can not bake this attribute (%d)!!\n", strlen(cred_encoding));
211        return 0;
212    }
213
214    certificate_t *attr_cert = lib->creds->create(lib->creds,
215        CRED_CERTIFICATE, CERT_X509_AC,
216        BUILD_CERT, abac_id_cert(ptr->issuer_id),
217        BUILD_NOT_BEFORE_TIME, not_before,
218        BUILD_NOT_AFTER_TIME, not_after,
219        BUILD_SERIAL, serial,
220        BUILD_IETF_GROUP_ATTR, cred_encoding,
221        BUILD_SIGNING_CERT, abac_id_cert(ptr->issuer_id),
222        BUILD_SIGNING_KEY, private,
223        BUILD_END
224    );
225
226    _check_cert_group(attr_cert, cred_encoding);
227
228    DESTROY_IF(private);
229
230    if (attr_cert == NULL)
231        return 0;
232
233    ptr->cert = attr_cert;
234// cert and issuer can be the same, in which case it is the self signing
235    ptr->issuer_cert= attr_cert->get_ref(attr_cert);
236 
237    free(cred_encoding);
238    free(serial.ptr);
239    return 1;
240}
241
242abac_chunk_t abac_attribute_cert_chunk(abac_attribute_t *ptr) {
243    assert(ptr->cert);
244    chunk_t encoding = chunk_empty;
245    int rc=ptr->cert->get_encoding(ptr->cert,CERT_ASN1_DER,&encoding);
246    abac_chunk_t ret = { encoding.ptr, encoding.len };
247    return ret;
248}
249
250/* just loading it without any verifying */
251certificate_t *abac_attribute_cert_from_file(char *filename) {
252
253    if(!file_exist(filename)) return NULL;
254
255    libabac_init();
256
257    certificate_t *cert = cert_get_attr_cert_from_file(filename);
258    if (cert == NULL)
259        errx(1, "Couldn't load attribute cert %s", filename);
260
261    return cert;
262}
263
264
265certificate_t *abac_attribute_cert_from_chunk(abac_chunk_t achunk) {
266
267    chunk_t chunk = { .ptr = achunk.ptr, .len = achunk.len };
268    if(achunk.len == 0) {
269        errx(1, "Couldn't load attribute chunk, size of 0");
270    }
271
272    libabac_init();
273    certificate_t *cert = cert_get_attr_cert_from_chunk(chunk);
274    if (cert == NULL)
275        errx(1, "Couldn't load attribute chunk");
276
277    return cert;
278}
279
280
281/**
282 * Load an attribute cert with a cert.
283 * Returns true only if the certificate is valid and is issued by the proper
284 * authority.
285 * attribute string is parsed via yyparse call
286 */
287static abac_attribute_t *_load_attribute_from_cert(certificate_t *cert)
288{
289    ietf_attributes_t *attr_cert = NULL;
290    int ret, i;
291    int using_this=0;
292
293    // get the attr
294    ac_t *ac = (ac_t *)cert;
295    attr_cert = ac->get_groups(ac);
296    if (attr_cert == NULL) {
297        ret = ABAC_CERT_INVALID;
298        goto error;
299    }
300
301    char *encoded_attr_string=attr_cert->get_string(attr_cert);
302    char *attr_string = abac_decode_string(encoded_attr_string);
303    if(debug)
304         fprintf(stderr, "string to be yyparse..(%d)(%s)\n",strlen(attr_string),attr_string);
305
306    if (attr_string == NULL) {
307        ret = ABAC_CERT_INVALID;
308        goto error;
309    }
310
311    abac_id_credential_t *id_cred;
312    abac_id_t *issuer_id;
313
314    /* reset lex input line, call into yacc parser */
315    abac_aspect_t *head_aspect = NULL;
316    abac_aspect_t *tail_aspect = NULL;
317    int rc=abac_yy_parse(NULL, attr_string, &head_aspect, &tail_aspect, &using_this);
318    if (rc) {
319        ret = ABAC_CERT_INVALID;
320        goto error;
321    }
322
323    // get the issuer based on keyid
324    char *principalname = abac_aspect_principal_principalname(head_aspect);
325    if(debug) fprintf(stderr, "LOOKING for %s\n", principalname);
326   
327    id_cred = abac_id_credential_lookup(principalname);
328    if(id_cred == NULL) {
329        ret = ABAC_CERT_MISSING_ISSUER;
330        if(debug)
331             fprintf(stderr, "can not find %s in id_creds\n", principalname);
332        goto error;
333    }
334
335    issuer_id=abac_id_credential_id(id_cred);
336    if (issuer_id == NULL) {
337        ret = ABAC_CERT_MISSING_ISSUER;
338        if(debug)
339             fprintf(stderr, "can not find %s in id_creds\n", principalname);
340        goto error;
341    }
342   // make sure the issuer's signed it
343    ret = verify_signature(abac_id_cert(issuer_id), cert);
344    if (!ret) {
345        abac_yy_set_error_code(ABAC_RT_CERT_BAD_SIG);
346        ret=ABAC_CERT_BAD_SIG;
347        goto error;
348    }
349
350    // at this point we know we have a good attribute cert baked it in
351    abac_attribute_t *attr=abac_attribute_new(issuer_id, cert, cert->get_ref(cert));
352    abac_attribute_set_head(attr, head_aspect);
353    abac_attribute_add_tail(attr, tail_aspect);
354    abac_attribute_set_using_this(attr, using_this);
355
356    // free up some stuff
357    attr_cert->destroy(attr_cert);
358
359    return attr;
360
361error:
362    if (cert) cert->destroy(cert);
363    errx(1, "fail to extract attribute from a cert properly\n");
364}
365
366abac_attribute_t *abac_attribute_from_chunk(abac_chunk_t achunk)
367{
368    certificate_t *cert=abac_attribute_cert_from_chunk(achunk);
369    abac_attribute_t *ret=_load_attribute_from_cert(cert);
370    return ret;
371}
372
373// returns 0 if the cert hasn't been baked
374int abac_attribute_baked(abac_attribute_t *ptr) {
375    return ptr->cert != NULL;
376}
377
378int abac_attribute_write_cert(abac_attribute_t *ptr, FILE *out) {
379    assert(ptr != NULL);
380
381    if (ptr->cert == NULL)
382        return 0;
383
384    // write to file
385    chunk_t encoding = chunk_empty;
386    int rc=ptr->cert->get_encoding(ptr->cert,CERT_ASN1_DER,&encoding);
387
388    if(rc) {
389        fwrite(encoding.ptr, encoding.len, 1, out);
390        free(encoding.ptr);
391        return 1;
392    }
393    return 0;
394}
395
396abac_attribute_t *abac_attribute_dup(abac_attribute_t *ptr)
397{
398    assert(ptr);
399    abac_id_dup(ptr->issuer_id);
400    ++ptr->refcount;
401    return ptr;
402}
403
404static certificate_t *_cert_copy(certificate_t *cert)
405{
406    if(cert==NULL) return NULL;
407    chunk_t encoding = chunk_empty;
408    int rc=cert->get_encoding(cert,CERT_ASN1_DER,&encoding);
409    certificate_t *ncert = cert_get_attr_cert_from_chunk(encoding);
410    return ncert;
411}
412
413/* deep copy of a attribute structure, this is used by libabac
414   api so that we can have a local control of the data within
415   libabac
416*/
417abac_attribute_t *abac_attribute_copy(abac_attribute_t *ptr)
418{
419    assert(ptr);
420    abac_aspect_t *tmp;
421    abac_attribute_t *nptr = _abac_attribute_init();
422    nptr->issuer_id = abac_id_copy(ptr->issuer_id);
423    nptr->head=abac_aspect_copy(abac_attribute_head(ptr));
424    nptr->tail=abac_aspect_copy(abac_attribute_tail(ptr));
425
426    nptr->validity= ptr->validity;
427    nptr->using_this = ptr->using_this;
428    certificate_t *attr_cert=_cert_copy(ptr->cert);
429    nptr->cert=attr_cert; // already baked..
430    if(attr_cert) 
431        nptr->issuer_cert= attr_cert->get_ref(attr_cert);
432    nptr->refcount=ptr->refcount+1;
433    return nptr;
434}
435
436void abac_attribute_free(abac_attribute_t *ptr) {
437    int i;
438
439    if (ptr == NULL)
440        return;
441
442    --ptr->refcount;
443    if (ptr->refcount > 0)
444        return;
445
446    if(ptr->issuer_id) abac_id_free(ptr->issuer_id);
447    if(ptr->head) abac_aspect_free(ptr->head);
448    if(ptr->tail) abac_aspect_free(ptr->tail);
449
450    if(ptr->cert) DESTROY_IF(ptr->cert);
451    if(ptr->issuer_cert) DESTROY_IF(ptr->issuer_cert);
452    free(ptr);
453}
454
455
456char *abac_attribute_string(abac_attribute_t *ptr) 
457{
458    char *head=abac_aspect_string_with_condition(ptr->head);
459    char *tail=abac_aspect_string_with_condition(ptr->tail);
460    if(head==NULL || tail==NULL)
461        errx(1, "attribute string, head and tail can not be NULL");
462    char *tmp=NULL;
463    asprintf(&tmp,"%s<-%s",head,tail);
464    return tmp;
465}
466char *abac_attribute_typed_string(abac_attribute_t *ptr) 
467{
468    char *head=abac_aspect_typed_string_with_condition(ptr->head);
469    char *tail=abac_aspect_typed_string_with_condition(ptr->tail);
470    if(head==NULL || tail==NULL)
471        errx(1, "attribute typed string, head and tail can not be NULL");
472    char *tmp=NULL;
473    asprintf(&tmp,"%s<-%s",head,tail);
474    return tmp;
475}
476
477/********************************************************************/
478certificate_t *abac_attribute_issuer_cert(abac_attribute_t *ptr)
479{
480   assert(ptr);
481   return ptr->issuer_cert;
482}
483
484abac_aspect_t *abac_attribute_head(abac_attribute_t *ptr)
485{
486    assert(ptr);
487    return ptr->head;
488}
489
490int abac_attribute_is_role(abac_attribute_t *ptr)
491{
492    assert(ptr);
493    assert(ptr->head);
494    return abac_aspect_is_role(ptr->head);
495}
496
497abac_attribute_t *abac_attribute_set_head(abac_attribute_t *ptr, abac_aspect_t *head)
498{
499    assert(ptr);
500    ptr->head=head;
501    return ptr;
502}
503
504void abac_attribute_set_using_this(abac_attribute_t *ptr, int using_this)
505{
506    assert(ptr);
507    ptr->using_this=using_this;
508}
509
510int abac_attribute_get_this(abac_attribute_t *ptr)
511{
512    assert(ptr);
513    return ptr->using_this;
514}
515
516abac_aspect_t *abac_attribute_tail(abac_attribute_t *ptr)
517{
518    assert(ptr);
519    return ptr->tail;
520}
521
522abac_attribute_t *abac_attribute_add_tail(abac_attribute_t *ptr, abac_aspect_t *tail)
523{
524    assert(ptr);
525    assert(tail);
526
527    /* type of head and tail has to match */
528    abac_aspect_t *head=abac_attribute_head(ptr);
529
530    if(debug) {
531        fprintf(stderr, "head->(%s)\n",abac_aspect_type_string(head));
532        fprintf(stderr, "tail->(%s)\n",abac_aspect_type_string(tail));
533    }
534    if(abac_aspect_is_intersecting(tail)) {
535        if(debug) {
536            fprintf(stderr, "tail is intersection \n");
537            fprintf(stderr, "tail is (%s)\n", abac_aspect_string_with_condition(tail));
538        }
539        if(abac_aspect_intersecting_aspect_type(tail) != abac_aspect_aspect_type(head))
540            errx(1, "head and intersecting tail's aspect type does not match");
541        } else {
542            if(abac_aspect_aspect_type(head) != abac_aspect_aspect_type(tail)) {
543                if(debug)
544                    fprintf(stderr, "tail is (%s)\n", abac_aspect_string_with_condition(tail));
545                errx(1, "head and tail's aspect type does not match");
546            }
547    }
548
549    if(ptr->tail == NULL) {
550        ptr->tail=abac_aspect_dup(tail);
551        } else {
552            if(abac_aspect_is_intersecting(ptr->tail)) {
553                abac_aspect_add_intersecting_aspect(ptr->tail, tail);
554                } else {
555    /* special case.. if there is a tail there already and it is not an intersecting
556       tail, need to turn this into an intersecting tails */
557                    abac_aspect_t *nptr=abac_aspect_intersection_new(ptr->tail);
558                    abac_aspect_add_intersecting_aspect(nptr, tail);
559                    ptr->tail=nptr;
560            }
561    }
562    return ptr;
563}
564
565certificate_t *abac_attribute_cert(abac_attribute_t *ptr)
566{
567    assert(ptr);
568    return ptr->cert;
569}
570
571int abac_attribute_lastone(abac_attribute_t *ptr)
572{
573    assert(ptr);
574    if(ptr->refcount == 1)
575        return 1;
576    return 0;
577}
578
579
580abac_aspect_t **abac_attribute_tail_vectorized(abac_attribute_t *ptr)
581{
582    abac_aspect_t **tails=NULL;
583    abac_aspect_t *tail=ptr->tail;
584    abac_list_t *list=NULL;
585    int cnt=0;
586    if(tail != NULL) {
587        if(!abac_aspect_is_intersecting(tail)) {
588            tails = abac_xmalloc(sizeof(abac_aspect_t *) * 2);
589            tails[0] = abac_aspect_dup(tail);
590            tails[1] = NULL;
591            if(debug) {
592               fprintf(stderr, "abac_attribute_tail_vectorized, only 1 tail\n");
593            }
594            return tails;
595            } else {
596                abac_list_t *list=abac_aspect_prereqs(tail);
597                cnt=abac_list_size(list);
598        }
599    }
600    // make the array (leave space to NULL terminate it)
601    //      n.b., even if the list is empty, we still return an array that
602    //            only contains the NULL terminator
603    tails = abac_xmalloc(sizeof(abac_aspect_t *) * (cnt + 1));
604    abac_aspect_t  *cur;
605    int i = 0;
606    if(i<cnt) {
607        abac_list_foreach(list, cur,
608            tails[i++] = abac_aspect_dup(cur);
609        );
610    }
611    tails[i] = NULL;
612    if(debug)
613        fprintf(stderr, "abac_attribute_tail_vectorized, %d tails\n", cnt);
614    return tails;
615}
616
617void abac_aspects_free(abac_aspect_t **aspects)
618{
619    /* always null terminating */
620    assert(aspects);
621    int i;
622    for (i = 0; aspects[i] != NULL; ++i) {
623        abac_aspect_free(aspects[i]);
624    }
625    free(aspects);
626}
Note: See TracBrowser for help on using the repository browser.