source: libabac/abac_attribute.c @ e97d2e2

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