source: libabac/abac_attribute.c @ 461541a

abac0-leakabac0-meimei-idmei-rt0-nmei_rt0tvf-new-xml
Last change on this file since 461541a was 461541a, checked in by Mei <mei@…>, 11 years ago

1) updated original rt0 to remove libstrongswan dependency

a) identity credential being made/accessed with openssl api calls

(X509/EVP_PKEY pem)

b) attribute credential being made/access via xmlsec1 (custom XML

structure)

2) refactored libcreddy into libabac and now one ABAC namespace for

libabac

3) added attribute_rule suboption to creddy's attribute as another way

to insert access rule

4) added some regression tests into example directory
5) updated some docs.

  • Property mode set to 100644
File size: 9.8 KB
Line 
1
2/* abac_attribute.c */
3
4#define _GNU_SOURCE
5#include <stdio.h>
6#include <assert.h>
7#include <ctype.h>
8#include <string.h>
9#include <time.h>
10
11#include "libabac_common.h"
12#include "abac_util.h"
13#include "abac_xml.h"
14
15#define ROLE_SEPARATOR " <- "
16#define INTERSECTION_SEP " & "
17#define SHA1_LENGTH 40
18
19static int debug=0;
20
21// a GENI XML attribute chunk might contain multiple
22// attribute rules. It will be translate into multiple
23// abac_attribute structures but with cert ptr pointing
24// to the same xml chunk
25// issuer can be missing but then it won't be bakable
26// unless it is baked just for creddy's roles call
27struct _abac_attribute_t {
28    abac_id_t *issuer_id; 
29    char *role;
30    long validity;
31
32    char *head_string;
33    char *tail_string;
34
35    abac_chunk_t cert; // the XML chunk
36};
37
38char *abac_attribute_role_string(abac_attribute_t *attr);
39extern abac_id_t *abac_verifier_lookup_id(char *keyid);
40static char *_validate_principal(char *keyid);
41
42/************************************************************/
43abac_chunk_t abac_attribute_cert(abac_attribute_t *ptr)
44{
45    assert(ptr);
46    return ptr->cert;
47}
48
49abac_id_t *abac_attribute_issuer_id(abac_attribute_t *ptr)
50{
51    assert(ptr);
52    return ptr->issuer_id;
53}
54
55// validity is measured in seconds (as of 0.2.0)
56// Acme.customer
57int abac_attribute_create(abac_attribute_t **ret, abac_id_t *issuer_id, char *role, long validity) {
58    if (!abac_id_has_privkey(issuer_id))
59        return ABAC_ATTRIBUTE_ISSUER_NOKEY;
60    if (!abac_clean_name(role))
61        return ABAC_ATTRIBUTE_INVALID_ROLE;
62    if (validity < 0)
63        return ABAC_ATTRIBUTE_INVALID_VALIDITY;
64    if (!abac_id_still_valid(issuer_id))
65        return ABAC_ATTRIBUTE_INVALID_ISSUER;
66
67    abac_attribute_t *attr = abac_xmalloc(sizeof(abac_attribute_t));
68    if(issuer_id) attr->issuer_id = abac_id_dup(issuer_id);
69        else attr->issuer_id = NULL;
70    attr->role = abac_xstrdup(role);
71    attr->validity = validity;
72
73    attr->head_string = NULL;
74    attr->tail_string = NULL;
75
76    // NULL until baked
77    attr->cert.ptr=NULL;
78    attr->cert.len=0;
79
80    *ret = attr;
81    return ABAC_SUCCESS;
82}
83
84/**
85 * Get the validity period.(xml module returns the diff from expire time - now()
86 */
87int abac_attribute_validity(abac_attribute_t *attr,struct tm *not_before,struct tm *not_after) {
88    assert(attr);
89    memset(not_before, 0, sizeof(struct tm));
90    memset(not_after, 0, sizeof(struct tm));
91
92    time_t now;
93    time(&now);
94    gmtime_r(&now, not_before);
95    char *xml=attr->cert.ptr;
96    long validity=get_validity_from_xml(xml);
97
98    time_t etime = now + validity;
99    gmtime_r(&etime, not_after);
100
101    fprintf(stderr,"validity from the xml blob is %ld\n",validity);
102    if(validity == 0)
103        return ABAC_FAILURE;
104    return ABAC_SUCCESS;
105}
106
107int abac_attribute_still_valid(abac_attribute_t *attr)
108{
109    assert(attr);
110    assert(attr->cert.ptr);
111    long v=get_validity_from_xml(attr->cert.ptr);
112    if (v > 0.0)
113        return 1;
114    else return 0;
115}
116
117void abac_attribute_set_head(abac_attribute_t *attr, char *string)
118{
119    assert(attr);
120    attr->head_string=string;
121}
122
123char *abac_attribute_get_head(abac_attribute_t *attr)
124{
125    assert(attr);
126    return attr->head_string;
127}
128
129void abac_attribute_set_tail(abac_attribute_t *attr, char *string)
130{
131    assert(attr);
132    attr->tail_string=string;
133}
134
135char *abac_attribute_get_tail(abac_attribute_t *attr)
136{
137    assert(attr);
138    return attr->tail_string;
139}
140
141/* A.b->C, return copy of a A */
142char *abac_attribute_get_principal(abac_attribute_t *attr)
143{
144    char *role_string=abac_attribute_role_string(attr);
145    /* make an copy */
146    char *tmp=strdup(role_string);
147    char *head_tail[2];
148    int ret;
149    abac_split(tmp, "<-", head_tail, &ret);
150    if (ret != 2) goto err;
151    abac_split(head_tail[0], ".", head_tail, &ret);
152    if (ret != 2) goto err;
153    char *prin=strdup(head_tail[0]);
154    free(tmp);
155    return prin;
156
157err:     
158     free(tmp);
159     return NULL;
160}
161
162int abac_attribute_principal(abac_attribute_t *attr, char *keyid) {
163    char *copy = _validate_principal(keyid);
164    if (copy == NULL)
165        return 0;
166
167    abac_attribute_set_tail(attr,copy);
168    return 1;
169}
170
171int abac_attribute_role(abac_attribute_t *attr, char *keyid, char *role) {
172    if (!abac_clean_name(role))
173        return 0;
174
175    char *copy = _validate_principal(keyid);
176    if (copy == NULL)
177        return 0;
178
179    int len = strlen(copy) + strlen(role) + strlen(ROLE_SEPARATOR) + 1;
180    copy = abac_xrealloc(copy, len);
181    strcat(copy, ".");
182    strcat(copy, role);
183
184    abac_attribute_set_tail(attr,copy);
185    return 1;
186}
187
188int abac_attribute_linking_role(abac_attribute_t *attr, char *keyid, char *role, char *linked) {
189    if (!abac_clean_name(role) || !abac_clean_name(linked))
190        return 0;
191
192    char *copy = _validate_principal(keyid);
193    if (copy == NULL)
194        return 0;
195
196    int len = strlen(copy) + strlen(role) + strlen(linked) + strlen(ROLE_SEPARATOR) + 2;
197    copy = abac_xrealloc(copy, len);
198    strcat(copy, ".");
199    strcat(copy, role);
200    strcat(copy, ".");
201    strcat(copy, linked);
202
203    abac_attribute_set_tail(attr,copy);
204    return 1;
205}
206
207
208
209// 0 for fail to bake, 1 is baked okay
210int abac_attribute_bake(abac_attribute_t *attr) {
211    assert(attr);
212    assert(attr->head_string);
213    assert(attr->tail_string);
214
215    abac_chunk_t id_chunk = { NULL, 0 };
216    int ret=abac_id_PEM(attr->issuer_id, &id_chunk);
217    if(ret != ABAC_CERT_SUCCESS)
218        return 0; 
219
220    char *role_string = abac_attribute_role_string(attr);
221
222/* Make an new GENI abac credential with the rt0 rule that expires secs from
223 * now.  cert is the PEM encoded X.509 of the issuer's certificate as a string.
224 * certlen is the length of cert.  Returns the XML. Caller is responsible for
225 * freeing it. */
226    char *attr_cert=my_make_credential(role_string, attr->validity, id_chunk.ptr, id_chunk.len);
227
228    if (attr_cert == NULL)
229        return 0;
230
231    attr->cert.ptr = (unsigned char *)attr_cert;
232    attr->cert.len = strlen(attr_cert);
233
234    free(role_string);
235    return 1;
236}
237
238// make an explicit copy
239int abac_attribute_cert_chunk(abac_attribute_t *attr, abac_chunk_t *chunk) {
240
241    chunk->ptr=NULL;
242    chunk->len=0;
243
244    if (attr->cert.ptr == NULL)
245        return 0;
246
247    /* return the xml chunk */
248    chunk->ptr= (unsigned char *)abac_xstrdup((char *)attr->cert.ptr);
249    chunk->len=attr->cert.len;
250    return chunk->len;
251}
252
253int abac_attribute_baked(abac_attribute_t *attr) {
254    return (attr->cert.ptr != NULL);
255}
256
257
258static abac_attribute_t *_load_attr(char *role_string, char *xml)
259{
260
261if(debug) fprintf(stderr,"loading -> %s \n", role_string);
262
263    char *head_tail[2];
264    int ret;
265    abac_split(role_string, "<-", head_tail, &ret);
266    if (ret != 2) return NULL; 
267
268    char *keyid=get_keyid_from_xml(xml);
269    abac_id_t *issuer_id=abac_verifier_lookup_id(keyid);
270
271    long validity=get_validity_from_xml(xml);
272   
273    abac_attribute_t *attr = abac_xmalloc(sizeof(abac_attribute_t));
274    if(issuer_id)
275        attr->issuer_id = abac_id_dup(issuer_id);
276        else attr->issuer_id=NULL;
277    attr->validity = validity;
278
279    attr->head_string = abac_xstrdup(head_tail[0]);
280    attr->tail_string = abac_xstrdup(head_tail[1]);
281    char *tmp=strstr(attr->head_string,".");
282    attr->role =abac_xstrdup(tmp+1);
283
284    attr->cert.ptr=(unsigned char *)xml;
285    attr->cert.len=strlen(xml);
286
287    return attr;
288}
289
290abac_list_t *abac_attribute_certs_from_file(char *filename)
291{
292    abac_list_t *alist=abac_list_new();
293    char *xml=NULL;
294    char *rt0=NULL;
295
296    char **rt0s=my_read_credential(filename, &xml);
297    if(xml == NULL) return alist;
298
299    int len=strlen(xml);
300    if(len==0) return alist;
301
302    abac_attribute_t *attr;
303
304    int i=0;
305    do {
306        rt0 = rt0s[i]; 
307        if(rt0 == NULL) break;
308        attr=_load_attr(rt0, xml);
309        if(attr)
310            abac_list_add(alist, attr);
311        free(rt0);
312        i++;
313    } while (rt0s[i] !=NULL);
314
315    free(rt0s);
316    free(xml);
317
318    return alist;
319}
320
321abac_list_t *abac_attribute_certs_from_chunk(abac_chunk_t chunk) {
322
323    abac_list_t *alist=abac_list_new();
324    char *xml=(char *)chunk.ptr;
325    char **rt0s=get_rt0_from_xml(xml);
326    char *rt0=NULL;
327    int len=strlen(xml);
328    if(len==0) return alist;
329
330    abac_attribute_t *attr;
331    int i=0;
332    do {
333        rt0 = rt0s[i]; 
334        if(rt0 == NULL) break;
335        attr=_load_attr(rt0, xml);
336        if(attr)
337            abac_list_add(alist, attr);
338        free(rt0);
339        i++;
340    } while (rt0s[i] !=NULL);
341
342    free(rt0s);
343    return alist;
344}
345
346// returns 0 if the cert hasn't been baked
347int abac_attribute_write(abac_attribute_t *attr, FILE *out) {
348    assert(attr != NULL);
349
350    if (attr->cert.ptr == NULL)
351        return 0;
352
353    // write to file
354    fwrite(attr->cert.ptr, attr->cert.len, 1, out);
355
356    return 1;
357}
358
359void abac_attribute_free(abac_attribute_t *attr) {
360
361if(debug) fprintf(stderr,"calling abac_attribute_free on %s\n", attr->head_string);
362
363    if (attr == NULL)
364        return;
365
366    if(attr->issuer_id) abac_id_free(attr->issuer_id);
367
368    free(attr->role);
369    free(attr->head_string);
370    free(attr->tail_string);
371
372/* XXX this can not be free as if it is a char string
373    free(attr->cert.ptr);
374*/
375
376    free(attr);
377}
378
379//
380// Helper functions below
381//
382
383// validate a princpal's name
384// makes sure it's a valid SHA1 identifier
385// return values:
386//  success: malloc'd copy with all hex digits lowercase
387//  fail: NULL
388static char *_validate_principal(char *keyid) {
389    int i;
390    char *copy = NULL;
391
392    if (strlen(keyid) != SHA1_LENGTH)
393        return NULL;
394
395    copy = abac_xstrdup(keyid);
396    for (i = 0; i < SHA1_LENGTH; ++i) {
397        copy[i] = tolower(copy[i]);
398        if (!isxdigit(copy[i]))
399            goto error;
400    }
401
402    return copy;
403
404error:
405    free(copy);
406    return NULL;
407}
408
409// combine up the attribute's rule string, explicit copy
410char *abac_attribute_role_string(abac_attribute_t *attr) {
411    assert(attr);
412
413    char *role_string=NULL;
414    asprintf(&role_string,"%s<-%s",attr->head_string,attr->tail_string);
415    return role_string;
416}
417
418
Note: See TracBrowser for help on using the repository browser.