source: libabac/abac_xml.c @ 79f516b

abac0-leakabac0-meitvf-new-xml
Last change on this file since 79f516b was bc12f3d, checked in by Ted Faber <faber@…>, 11 years ago

Allow user to specify credential output format

  • Property mode set to 100644
File size: 47.0 KB
Line 
1/* abac_xml.c, specifically for GENI */
2
3/* in xml, rc in general is, 1 is good, 0 or -1 is bad */
4
5#define _GNU_SOURCE
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10
11#include <libxml/tree.h>
12#include <libxml/xmlmemory.h>
13#include <libxml/parser.h>
14
15#ifndef XMLSEC_NO_XSLT
16#include <libxslt/xslt.h>
17#include <libxslt/security.h>
18#endif /* XMLSEC_NO_XSLT */
19
20#include <xmlsec/xmlsec.h>
21#include <xmlsec/xmltree.h>
22#include <xmlsec/xmldsig.h>
23#include <xmlsec/base64.h>
24#include <xmlsec/templates.h>
25#include <xmlsec/crypto.h>
26#include <xmlsec/list.h>
27
28#include <openssl/sha.h>
29
30#include "abac.h"
31#include "abac_util.h"
32
33extern int abac_verifier_load_id_chars(void *, char*); 
34extern void* abac_get_sha_from_nake_pem(char *npem, char **sha1);
35extern void abac_split(char *string, char *delim, char **ret, int *num);
36static int debug=0;
37
38/* from Ted's reader */
39
40/* for accessing GENI privilege credentials */
41#define GENI_signed_credential "signed-credential"
42#define GENI_credential "credential"
43#define GENI_type "type"
44#define GENI_serial "serial"
45#define GENI_owner_gid "owner_gid"
46#define GENI_owner_urn "owner_urn"
47#define GENI_target_gid "target_gid"
48#define GENI_target_urn "target_urn"
49#define GENI_uuid "uuid"
50#define GENI_expires "expires"
51#define GENI_privileges "privileges"
52#define GENI_privilege "privilege"
53#define GENI_name "name"
54#define GENI_can_delegate "can_delegate"
55#define GENI_x509_certificate "X509Certificate"
56
57/* for accessing GENI abac credentials. signed-credential, credential, type and
58 * expires are present as well.  */
59#define GENI_rt0 "rt0"
60#define GENI_version "version"
61
62/* maximum credential stringlen */
63#define CREDLEN 1024
64/* Maximum version len */
65#define VERSIONLEN 256
66
67/* These templates are given in defines so that they can initialize the
68 * specialization structures. */
69
70/* XML template for a new RT0 v1.0 credential.  Fill in the RT0 to store (XML
71 * escaped) and the expiration time (formated using strftime_format and
72 * strftime). */
73#define template_v10 "<signed-credential>\n"\
74"    <credential xml:id=\"ref0\">\n"\
75"       <type>abac</type>\n"\
76"       <version>1.0</version>\n"\
77"       <expires>%s</expires>\n"\
78"       <rt0>%s</rt0>\n"\
79"    </credential>\n"\
80"    <signatures>\n"\
81"       <Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n"\
82"           <SignedInfo>\n"\
83"               <CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>\n"\
84"               <SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/>\n"\
85"               <Reference URI=\"#ref0\">\n"\
86"                   <Transforms>\n"\
87"                       <Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/>\n"\
88"                   </Transforms>\n"\
89"                   <DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/>\n"\
90"                   <DigestValue/>\n"\
91"               </Reference>\n"\
92"           </SignedInfo>\n"\
93"           <SignatureValue/>\n"\
94"           <KeyInfo>\n"\
95"             <KeyValue/>\n"\
96"               <X509Data>\n"\
97"                   <X509Certificate/>\n"\
98"                   <X509SubjectName/>\n"\
99"                   <X509IssuerSerial/>\n"\
100"               </X509Data>\n"\
101"           </KeyInfo>\n"\
102"       </Signature>\n"\
103"    </signatures>\n"\
104"</signed-credential>"
105
106/* XML template for a new RT0 v1.1 credential.  Fill in the RT0 to store (XML
107 * escaped) and the expiration time (formated using strftime_format and
108 * strftime). */
109#define template_v11 "<signed-credential>\n"\
110"    <credential xml:id=\"ref0\">\n"\
111"       <type>abac</type>\n"\
112"       <serial/>\n"\
113"       <owner_gid/>\n"\
114"       <target_gid/>\n"\
115"       <uuid/>\n"\
116"       <expires>%s</expires>\n"\
117"       <rt0>\n"\
118"           <version>1.1</version>\n"\
119"           %s\n"\
120"       </rt0>\n"\
121"    </credential>\n"\
122"    <signatures>\n"\
123"       <Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n"\
124"           <SignedInfo>\n"\
125"               <CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>\n"\
126"               <SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/>\n"\
127"               <Reference URI=\"#ref0\">\n"\
128"                   <Transforms>\n"\
129"                       <Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/>\n"\
130"                   </Transforms>\n"\
131"                   <DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/>\n"\
132"                   <DigestValue/>\n"\
133"               </Reference>\n"\
134"           </SignedInfo>\n"\
135"           <SignatureValue/>\n"\
136"           <KeyInfo>\n"\
137"             <KeyValue/>\n"\
138"               <X509Data>\n"\
139"                   <X509Certificate/>\n"\
140"                   <X509SubjectName/>\n"\
141"                   <X509IssuerSerial/>\n"\
142"               </X509Data>\n"\
143"           </KeyInfo>\n"\
144"       </Signature>\n"\
145"    </signatures>\n"\
146"</signed-credential>"
147
148/* Forward declarations of functions to parse and generate rt0 elements in
149 * various formats */
150xmlChar *encode_rt0_xml_v10(abac_attribute_t *);
151xmlChar *encode_rt0_xml_v11(abac_attribute_t *);
152xmlChar **parse_rt0_xml_v10(xmlNodePtr);
153xmlChar **parse_rt0_xml_v11(xmlNodePtr);
154
155/* Structure that specializes XML parsing */
156typedef struct {
157    /* Version to use these functions for */
158    char *version; 
159    /* Convert an ABAC attribute into an rt0 element */
160    xmlChar *(*rt0_to_xml)(abac_attribute_t *);
161    /* Convert an rt0 element into a list of RT0 strings */
162    xmlChar **(*xml_to_rt0)(xmlNodePtr);
163    /* The overall template to generate this version of credential */
164    char *out_template;
165} GENI_xml_processing_t;
166
167/* The processing specializations */
168GENI_xml_processing_t xml_proc[] = {
169    { "GENIv1.0", encode_rt0_xml_v10, parse_rt0_xml_v10, template_v10},
170    { "1.0", encode_rt0_xml_v10, parse_rt0_xml_v10, template_v10},
171    { "GENIv1.1", encode_rt0_xml_v11, parse_rt0_xml_v11, template_v11},
172    { "1.1", encode_rt0_xml_v11, parse_rt0_xml_v11, template_v11},
173    { NULL, NULL, NULL},
174};
175
176/* Query funtion to convert a processing version into the functions above */
177GENI_xml_processing_t *get_xml_processing(char *ver) {
178    int i ;
179
180    for (i = 0; xml_proc[i].version; i++) {
181        if (!strcmp(xml_proc[i].version, ver))
182            return &xml_proc[i];
183    }
184    return NULL;
185}
186
187
188/* Hex dump the contents of buf (length len) to stderr.  For debugging */
189static void dump_it(xmlChar *buf, int len) {
190    int i;
191
192    for (i=0; i < len; i++ ) 
193        fprintf(stderr, "%02x ", buf[i] & 0xff);
194    fprintf(stderr, "\n");
195}
196
197/* Convert a SHA1 hash to text for printing or use in strings.  keyid is the
198 * hash (SHA_DIGEST_LENGTH bytes long) and text is the output string (at least
199 * 2 * SHA_DIGEST_LENGTH +1 bytes long).  The caller is responsible for
200 * allocating and deallocating each of them. */
201static void sha1_to_text(xmlChar *keyid, xmlChar *text) {
202    int i = 0;
203
204    for (i=0; i < SHA_DIGEST_LENGTH; i++) 
205        snprintf((char *) text+2*i, 3, "%02x", keyid[i] & 0xff);
206}
207
208/*
209 * Returns the content pointer of the XML_TEXT node that is the child of the
210 * node passed in.  Node must point to an XML_ELEMENT node.  the return value
211 * is still part of node's XML document, so treat it as read only. */
212static xmlChar *get_element_content(xmlNodePtr node) {
213    xmlNodePtr text = NULL;
214
215    if ( node->type != XML_ELEMENT_NODE ) return NULL;
216    if ( !( text = node->children) ) return NULL;
217    if ( text->type != XML_TEXT_NODE ) return NULL;
218    return text->content;
219}
220
221/*Find the XML element named field that is a at or below node in the XML
222 * document and return a copy of the base64 decoded content of its content.
223 * For example, find key day in a signature and return it base64decoded.  buf
224 * is allocated and its length is returned in len.  Any values for buf and len
225 * are ignored and overwritten. */
226static int get_base64_field(xmlNodePtr node, xmlChar *field, 
227        xmlChar **buf, int *len) {
228    xmlChar *txt = NULL;
229
230    *buf = NULL;
231
232    if ( !(node = xmlSecFindNode(node, field, xmlSecDSigNs)))
233        goto fail;
234
235    if ( !(txt = get_element_content(node))) 
236            goto fail;
237   
238    *len = strlen((char *) txt);
239    if ( !(*buf = malloc(*len))) 
240        goto fail;
241
242    if ( (*len = xmlSecBase64Decode(txt, *buf, *len)) < 0 ) 
243        goto fail;
244
245    return 1;
246fail:
247    if ( *buf) free(*buf);
248    *len = 0;
249    return 0;
250}
251/* Construct an ASN.1 header for a field of type h that is len bytes long.
252 * Mosttly this creates the proper length encoding under ASN.1's length
253 * encoding rules. buf will contain the new header (and the caller is
254 * responsible for making sure it is at least 6 bytes long, though fewer are
255 * usually used.  The length of the constructed header is returned. This is
256 * used in creating a key hash from key data.*/
257static int make_asn1_header(char h, size_t len, xmlChar *buf) {
258    if ( len > 0x00ffffff) {
259        buf[0] = h;
260        buf[1] = 0x84;
261        buf[2] = (len >> 24) & 0xff;
262        buf[3] = (len >> 16) & 0xff;
263        buf[4] = (len >> 8) & 0xff;
264        buf[5] = (len) & 0xff;
265        return 6;
266    } else if ( len > 0x0000ffff ) {
267        buf[0] = h;
268        buf[1] = 0x83;
269        buf[2] = (len >> 16) & 0xff;
270        buf[3] = (len >> 8) & 0xff;
271        buf[4] = (len) & 0xff;
272        return 5;
273    } else if ( len > 0x000000ff ) {
274        buf[0] = h;
275        buf[1] = 0x82;
276        buf[2] = (len >> 8) & 0xff;
277        buf[3] = (len) & 0xff;
278        return 4;
279    } else if ( len > 0x80 ) {
280        buf[0] = h;
281        buf[1] = 0x81;
282        buf[2] = (len) & 0xff;
283        return 3;
284    } else {
285        buf[0] = h;
286        buf[1] = (len) & 0xff;
287        return 2;
288    }
289}
290
291/* Find the RSA key parameters in the KeyInfo section of the XML document
292 * pointed to by doc, construct the ASN.1 encoding of that key and SHA1 hash
293 * it.    This gives the standard keyid of that key.  keyid will be the binary
294 * encoding of that (the bits of the hash)  sha1_to_text will turn it to text.
295 * keyid must be at least SHA_DIGEST_LENGTH bytes long, and the caller is
296 * responsible for it. This routine returns 1 on success and 0 on failure. */
297static int get_keyid_from_keyinfo(xmlDocPtr doc, xmlChar *keyid) {
298    xmlNodePtr root = NULL; /* XML document root */
299    xmlNodePtr node = NULL; /* Scratch XML node */
300
301    xmlChar b0[20];         /* Header for the sequence */
302    xmlChar b1[20];         /* Header for the modulus */
303    xmlChar b2[20];         /* Header for the exponent */
304    int l0 = 0;             /* Header length for the sequence */
305    int l1 = 0;             /* Header length for the modulus */
306    int l2 = 0;             /* Header length for the exponent */
307
308    xmlChar *modBuf = NULL; /* Bytes of the modulus */
309    xmlChar *expBuf = NULL; /* Bytes of the exponent */
310    int modLen = 0;         /* Length of the modulus */
311    int expLen = 0;         /* Length of the exponent */
312
313    SHA_CTX sha;            /* SHA1 hash context */
314
315    int rv = 0;             /* return value */
316
317    if ( !SHA1_Init(&sha)) goto fail;
318
319    if ( !doc || !(root = xmlDocGetRootElement(doc)) ) 
320        goto fail;
321
322    /* Find the KeyInfo section to be the root of later searches */
323    if ( !(node = xmlSecFindNode(root, 
324                    xmlSecNodeKeyInfo, xmlSecDSigNs)))
325        goto fail;
326
327    /* Get the binary for the modulus and exponent */
328    if ( !get_base64_field(node, (xmlChar *) "Modulus", &modBuf, &modLen)) 
329        goto fail;
330    if ( !get_base64_field(node, (xmlChar *) "Exponent", &expBuf, &expLen)) 
331        goto fail;
332
333    /* Construct the headers for modulus and exponent.  Another weird fact
334     * about ASN.1 is that all the integers are signed, so if either the
335     * modulus or exponent has the high order bit of its first byte set, the
336     * ASN.1 encoding has a 0 byte prepended.  This code appends the 0 byte to
337     * the header, which results in the same hash. */
338    if ( modBuf[0] & 0x80 ) {
339        l1 = make_asn1_header(0x02, modLen +1, b1);
340        b1[l1++] = '\0';
341    } else {
342        l1 = make_asn1_header(0x02, modLen, b1);
343    }
344
345    if ( expBuf[0] & 0x80 ) {
346        l2 = make_asn1_header(0x02, expLen +1, b2);
347        b2[l2++] = '\0';
348    } else {
349        l2 = make_asn1_header(0x02, expLen, b2);
350    }
351
352    /* Sequence header: have to do it after we know the lengths of the inner
353     * headers. */
354    l0 = make_asn1_header(0x30, modLen + expLen + l1 + l2, b0);
355    /* Hash it all up in parts */
356    SHA1_Update(&sha, b0, l0);
357    SHA1_Update(&sha, b1, l1);
358    SHA1_Update(&sha, modBuf, modLen);
359    SHA1_Update(&sha, b2, l2);
360    SHA1_Update(&sha, expBuf, expLen);
361    SHA1_Final(keyid, &sha);
362    rv = 1;
363fail:
364
365    if (modBuf) free(modBuf);
366    if (expBuf) free(expBuf);
367    return rv;
368}
369
370/* Check the signature of either kind of credential - it'll work for basically
371 * any signed XML. Returns true if the signature checks and false otherwise.
372 * Takes a pointer to the XML document to check.  Similar to the examples at
373 * http://www.aleksey.com/xmlsec/api/xmlsec-examples.html */
374static int check_signature(xmlDocPtr doc) {
375    xmlNodePtr root = NULL;         /* Root XML node */
376    xmlNodePtr node = NULL;         /* Scratch XML node */
377    xmlSecKeyInfoCtxPtr keyCtx = NULL;/* Key info context.  Used to parse
378                                         KeyInfo */
379    xmlSecKeysMngrPtr keyMan = NULL;/* Key manager - used because we have
380                                       certificated. */
381    xmlSecKeyPtr key = NULL;        /* The key extracted */
382    xmlSecDSigCtxPtr dsigCtx = NULL;/* Signature context */
383    int rv = 0;                     /* Return value */
384
385    if ( doc && !(root = xmlDocGetRootElement(doc)) ) 
386        goto fail;
387
388    /* Find the KeyInfo section to pull the keys out. */
389    if ( !(node = xmlSecFindNode(root, 
390                    xmlSecNodeKeyInfo, xmlSecDSigNs)))
391        goto fail;
392
393    /* Create and initialize key, key manager, and context */
394    if ( !(key = xmlSecKeyCreate() ) )
395            goto fail;
396    if ( !(keyMan = xmlSecKeysMngrCreate()) ) 
397        goto fail;
398
399    if ( xmlSecCryptoAppDefaultKeysMngrInit(keyMan) < 0)
400        goto fail;
401
402    if ( !(keyCtx = xmlSecKeyInfoCtxCreate(keyMan)) ) 
403        goto fail;
404
405    /* Do not check certificate signatures */
406    keyCtx->flags |= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
407
408    /* Gather up the key data */
409    if ( xmlSecKeyInfoNodeRead(node, key, keyCtx) < 0 ) 
410        goto fail;
411
412    /* Set up the signature context and attack the keys */
413    if ( !(dsigCtx = xmlSecDSigCtxCreate(NULL)))
414        goto fail;
415
416    dsigCtx->signKey = key;
417
418    /* find the Signature section */
419    if ( !(node = xmlSecFindNode(root, 
420                    xmlSecNodeSignature, xmlSecDSigNs)))
421        goto fail;
422
423    /* Check it */
424    if ( (rv = xmlSecDSigCtxVerify(dsigCtx, node)) < 0 ) 
425        goto fail;
426
427    /* Strangely xmlSecDSigCtxVerify can return success even if the status is
428     * bad.  Check the status in the context explicitly and override the result
429     * above if necessary.*/
430    if ( dsigCtx->status != xmlSecDSigStatusSucceeded) 
431        goto fail;
432
433    return 1;
434fail:
435    if ( key ) xmlSecKeyDestroy(key);
436    if ( keyCtx ) xmlSecKeyInfoCtxDestroy(keyCtx);
437    if ( dsigCtx) xmlSecDSigCtxDestroy(dsigCtx);
438    return 0;
439}
440
441/* Extract a sha from PEM blob */
442static void extract_owner_sha1(xmlChar *pem, xmlChar **sha1) {
443    abac_get_sha_from_nake_pem((char *) pem, (char **)sha1); 
444    if(debug) fprintf(stderr,"owner sha1 is (%s)..\n", *sha1);
445}
446static void extract_target_sha1(xmlChar *pem, xmlChar **sha1) {
447    abac_get_sha_from_nake_pem((char *) pem,(char **)sha1); 
448    if(debug) fprintf(stderr,"group sha1 is (%s)..\n", *sha1);
449}
450
451/* Parse the content of the expires field and compare it to the time passed in
452 * n.  If expires is earlier, return false, else true.  If n is null, compare
453 * it to the current time. */
454static int check_GENI_expires(xmlChar *expires, struct tm *n) {
455    struct tm tv;   /* Parsed expires field */
456    time_t now;     /* Now in seconds since the epoch */
457    time_t exp;     /* expires in seconds since the epoch */
458
459    if (n) now = mktime(n);
460    else time(&now);
461
462    strptime((char *) expires, "%FT%TZ", &tv);
463    exp = timegm(&tv);
464
465    return difftime(exp, now) > 0.0;
466}
467
468/* Convert a parsed privilege in a GENI privilege string into one or more ABAC
469 * creds.  Rules are as in http://groups.geni.net/geni/wiki/TIEDCredentials .
470 * keyid is  the issuer's keyid, text_owner is the owners keyid (XXX:a
471 * placeholder) text_target is the target's keyid (XXX: a placeholder), priv is
472 * the privilege being assigned, and delegate is true if it can be delegated.
473 * carray is the output array of character strings that currently has *nc
474 * entries in it.  If nc has nothing in it, insert the "speaks_for" delegation
475 * rules.  Then add the privilege specific rules. On failure ***carray and its
476 * contents are freed and *nc is set to zero.*/
477static void add_privilege_credential_string(xmlChar *text_keyid, xmlChar *text_owner, 
478        xmlChar *text_target, xmlChar *priv, int delegate, xmlChar ***carray,
479        int *nc) {
480    xmlChar **rv = *carray;     /* Local pointer to the array of strings */
481    xmlChar **newrv = NULL;     /* Used to realloc the array of strings */
482    int ncred = *nc;            /* Local copy of the number of creds in rv */
483    int newc = (delegate) ? 3 : 1;  /* Number of new creds to add */
484    int base = ncred;           /* First new credential index.  This advances
485                                   as we add creds to rv. */
486    int i = 0;                  /* Scratch */
487
488    /* If rv is empty, add the speaks_for rules */
489    if (base == 0 ) newc += 2;
490
491    /* Resize rv */
492    if (!(newrv = realloc(rv, (base + newc) * sizeof(xmlChar *))))
493        goto fail;
494
495    for ( i = base; i < base +newc; i ++) { 
496        newrv[i] = NULL;
497    }
498
499    /* So fail works */
500    rv = newrv;
501    ncred = base + newc;
502
503    /* Add speaks_for rules  if needed */
504    if ( base == 0 ) {
505        if ( !(rv[base] = malloc(CREDLEN))) goto fail;
506        snprintf((char *) rv[base], CREDLEN, 
507                "%s.speaks_for_%s <- %s.speaks_for_%s",
508                text_keyid, text_owner, text_owner, text_owner);
509        base++;
510        if ( !(rv[base] = malloc(CREDLEN))) goto fail;
511        snprintf((char *) rv[base], CREDLEN, 
512                "%s.speaks_for_%s <- %s",
513                text_keyid, text_owner, text_owner);
514        base++;
515    }
516
517    /* The assignemnt of priv.  Always happens */
518    if ( !(rv[base] = malloc(CREDLEN))) goto fail;
519    snprintf((char *) rv[base], CREDLEN, 
520            "%s.%s_%s <- %s.speaks_for_%s",
521            text_keyid, priv, text_target, text_keyid, text_owner);
522    base++;
523    /* Add delegation rules */
524    if ( delegate ) {
525        if ( !(rv[base] = malloc(CREDLEN))) goto fail;
526        snprintf((char *) rv[base], CREDLEN, 
527                "%s.%s_%s <- %s.can_delegate_%s_%s.%s_%s",
528                text_keyid, priv, text_target, text_keyid, priv, 
529                text_target, priv, text_target);
530        base++;
531        if ( !(rv[base] = malloc(CREDLEN))) goto fail;
532        snprintf((char *) rv[base], CREDLEN, 
533                "%s.can_delegate_%s_%s <- %s",
534                text_keyid, priv, text_target, text_owner);
535        base++;
536    }
537    /* And return new values */
538    *carray = rv;
539    *nc = ncred;
540    return;
541fail:
542    if ( rv ) {
543        /* Delete all the allocations, ours or not, and clear the caller's
544         * variables */
545        for (i = 0; i < ncred; i++) 
546            if (rv[i]) free(rv[i]);
547        free(rv);
548    }
549    *carray = NULL;
550    *nc = 0;
551}
552
553
554/* Grab the issuer x509 blob */
555static xmlChar *get_issuer(xmlDocPtr doc) {
556    xmlNodePtr root = NULL;         /* Root XML node */
557    xmlNodePtr node = NULL;         /* Scratch XML node */
558    xmlNodePtr x509ptr = NULL;      /* XML X509Certificate node */
559    int rv = 0;                     /* Return value */
560    xmlChar *pem=NULL;
561
562    if (!(root = xmlDocGetRootElement(doc)) )
563        goto fail;
564
565    /* Find the KeyInfo section to be the root of later searches */
566    if ( !(node = xmlSecFindNode(root,
567                    xmlSecNodeKeyInfo, xmlSecDSigNs)))
568        goto fail;
569
570    if ( !(node = xmlSecFindNode(node,
571                    xmlSecNodeX509Data, xmlSecDSigNs)))
572        goto fail;
573
574    /* Find the X509Certificate from KeyInfo section */
575    if ( x509ptr = xmlSecFindNode(node, xmlSecNodeX509Certificate, xmlSecDSigNs)) {
576        pem=get_element_content(x509ptr);
577        } else {
578            goto fail;
579    }
580    return pem;
581fail:
582    return NULL;
583}
584
585/* Parse a GENI privilege credential (that has already had its signature
586 * checked) and return the RT0 strings that the credential is encoded as.  The
587 * return value is an array of strings, zero-terminated (like argv) that holds
588 * the RT0 strings.  It is NULL on failure. */
589static xmlChar **parse_privilege(xmlDocPtr doc, void *ctxt_id_certs) {
590    xmlNodePtr root = NULL;     /* XML root node */
591    xmlNodePtr node = NULL;     /* XML scratch node */
592    xmlNodePtr owner = NULL;    /* XML owner_gid node */
593    xmlNodePtr expires = NULL;  /* XML expires node */
594    xmlNodePtr target = NULL;   /* XML target_gid node */
595    xmlNodePtr privs = NULL;    /* XML privileges node */
596    xmlNodePtr priv = NULL;     /* XML privilege node - used to iterate */
597    xmlChar keyid[SHA_DIGEST_LENGTH];   /* Issuer key SHA1 */
598    xmlChar text_keyid[2*SHA_DIGEST_LENGTH+1];/* Issuer keyid as text */
599    xmlChar *owner_sha1 = NULL;         /* owner gid as text */
600    xmlChar *target_sha1 = NULL;        /* target gid as text */
601    xmlChar **newrv = NULL;     /* Used to realloc rv to add the NULL
602                                   terminator*/
603    xmlChar **rv = NULL;        /* return value */
604    int ncred = 0;              /* number of creds in rv, incase we need to
605                                   deallocate it */
606    int i = 0;                  /* scratch */
607
608    if ( doc && !(root = xmlDocGetRootElement(doc)) ) 
609        goto fail;
610
611    /* Get the issuer keyid */
612    if ( !get_keyid_from_keyinfo(doc, keyid)) 
613        goto fail;
614    sha1_to_text(keyid, text_keyid);
615
616    /* Find the various fields of interest */
617    if ( !(node = xmlSecFindNode(root, (xmlChar *) GENI_credential, NULL)))
618        goto fail;
619
620    /* Make sure this is not expired */
621    if ( !(expires = xmlSecFindNode(node, (xmlChar *) GENI_expires, NULL)))
622        goto fail;
623
624    if ( !check_GENI_expires(get_element_content(expires), NULL))
625        goto fail;
626
627    /* owner and target will be X.509 pem files from which we need to
628     * extract keyids for add_privilege_credential_string.  */
629    if ( !(owner = xmlSecFindNode(node, (xmlChar *) GENI_owner_gid, NULL)))
630        goto fail;
631    extract_owner_sha1(get_element_content(owner),&owner_sha1);
632
633    if ( !(target = xmlSecFindNode(node, (xmlChar *) GENI_target_gid, NULL)))
634        goto fail;
635    extract_target_sha1(get_element_content(target),&target_sha1);
636
637    /* extract issuer pem */
638    xmlChar *issuer_ptr=get_issuer(doc);
639
640    if ( !(privs = xmlSecFindNode(node, (xmlChar *) GENI_privileges, NULL)))
641        goto fail;
642
643    /* Iterate through the privileges, parsing out names and can_delegate and
644     * generating the strings from it. */
645    for (priv = privs->children; priv; priv = priv->next) {
646        /* reinitialized every time around */
647        xmlNodePtr n = NULL;
648        xmlChar *name = NULL;
649        int delegate = -1;
650
651        /* Ignore wayward text and other gook */
652        if ( priv->type != XML_ELEMENT_NODE) 
653            continue;
654
655        /* Ignore things that are not privilege nodes */
656        if ( strcmp((char *) priv->name, (char *) GENI_privilege) ) 
657            continue;
658
659        /* looking for name and can_delegate */
660        for (n = priv->children; n; n = n->next) {
661            if ( n->type != XML_ELEMENT_NODE ) 
662                continue;
663            if ( !strcmp((char *) n->name, (char *) GENI_name)) {
664                name = get_element_content(n);
665                continue;
666            }
667            if ( !strcmp((char *) n->name, (char *) GENI_can_delegate)) {
668                xmlChar *boolean = get_element_content(n);
669
670                if ( !strcmp((char *) boolean, "true") ||
671                        !strcmp((char *) boolean, "1") ) {
672                    delegate = 1;
673                } else if ( !strcmp((char *) boolean, "false") ||
674                        !strcmp((char *) boolean, "0") ) {
675                    delegate = 0;
676                } else {
677                    fprintf(stderr, "Unknown delegation value %s", boolean);
678                }
679            }
680        }
681        /* Found both name and can_delegate, add the RT0 to rv and ncred */
682        if ( name && delegate != -1 ) {
683            add_privilege_credential_string(text_keyid, 
684                    (xmlChar *) owner_sha1, (xmlChar *) target_sha1, name,
685                    delegate, &rv, &ncred);
686            if ( !rv ) goto fail;
687        }
688    }
689
690    /* Add the terminating NULL */
691    if (!(newrv = realloc(rv, sizeof(xmlChar*)*(ncred+1))))
692        goto fail;
693
694    newrv[ncred] = NULL;
695    /* able to extract some RT0s, load issuer credential as side-effect */
696    if(ncred !=1) {
697        /* load  issuer_ptr */ 
698        if(issuer_ptr && abac_verifier_load_id_chars(ctxt_id_certs, issuer_ptr) != 0 /*ABAC_CERT_SUCCESS*/)
699            goto fail;
700    }
701    return newrv;
702
703fail:
704    /* Throw away all of rv if there's an error */
705    if ( rv ) {
706        for (i = 0; i < ncred; i++) 
707            if (rv[i]) free(rv[i]);
708        free(rv);
709    }
710    return NULL;
711}
712
713/*
714 * If n has a child that is an element named name, return a pointer to it,
715 * other wise return NULL.
716 */
717static xmlNodePtr get_direct_child(xmlNodePtr n, xmlChar *name) {
718    xmlNodePtr c = NULL;
719
720    if ( !n ) return NULL;
721
722    for (c = n->children; c; c = c->next) {
723        if ( c->type != XML_ELEMENT_NODE ) 
724            continue;
725        if ( !strcmp((char *) c->name, (char *) name)) 
726            return c;
727    }
728    return NULL;
729}
730
731/*
732 * Convert a version 1.0 rt0 section to an RT0 string, returned in an array of
733 * strings.  This is just allocating the array and copying the string.  RT0 1.0
734 * has no structure.
735 */
736xmlChar **parse_rt0_xml_v10(xmlNodePtr n) {
737    xmlChar *txt;
738    xmlChar **rv = NULL;
739
740    /* read the RT0 and return it */
741    if ( !(txt = get_element_content(n)) ) return NULL;
742
743    if ( !(rv = malloc(2 * sizeof(xmlChar *)))) return NULL;
744    if (!(rv[0] = malloc(strlen((char *) txt)+1))) {
745        free(rv);
746        return NULL;
747    }
748    strcpy((char *) rv[0], (char *) txt);
749    rv[1] = NULL;
750    return rv;
751}
752
753/* Return the length of the string pointed to by rn, ignoring whitespace */
754static int role_len(xmlChar *rn) {
755    xmlChar *p;
756    int len = 0;
757
758    for (p = rn; *p; p++) 
759        if ( !isspace(*p) ) len++;
760    return len;
761}
762
763/* Return the length of the RT0 string represented bt the RT0 1.1 term.  That
764 * term looks like:
765 * <head>
766 *  <ABACprincipal><keyid>...</keyid><mnemonic>...</menmonic></ABACprincipal>
767 *  <role>...</role>
768 *  <linking_role>...</linking_role>
769 * </head>
770 * The container can be either a head or a tail, and the role and linking_role
771 * are optional.  The result is the number of non whitespace characters in the
772 * keyid, role, and linking_role fields (if present) plus a dot to separate
773 * each field.
774 */
775static int term_len(xmlNodePtr n) {
776    int len = 0;
777    xmlNodePtr c = NULL;/* Scratch */
778
779    for (c = n->children; c; c = c->next) {
780        if ( c->type != XML_ELEMENT_NODE ) 
781            continue;
782        if ( !strcmp((char *) c->name, "ABACprincipal")) {
783            xmlNodePtr k = get_direct_child(c, "keyid");
784            if ( !k ) return -1;
785            len += role_len(get_element_content(k));
786        } else if (!strcmp((char *) c->name, "role")) {
787            len += role_len(get_element_content(c)) +1;
788        } else if (!strcmp((char *) c->name, "linking_role")) {
789            len += role_len(get_element_content(c)) +1;
790        }
791    }
792    return len;
793}
794
795/* Copy non-whitespace characters from rn to dest.  Return the final vaue of
796 * dest, but no guarantees are made about it.  The caller must make sure there
797 * is enough space in dest.
798 */
799static xmlChar *role_copy(xmlChar *rn, xmlChar *dest) {
800    while (*rn) {
801        if (!isspace(*rn)) *dest++ = *rn;
802        rn++;
803    }
804    return dest;
805}
806
807/* Turn the contents of the node pointer into a dotted string representation of
808 * the RT0 term.  For example
809 * <tail>
810 *  <ABACprincipal><keyid>P</keyid><mnemonic>...</menmonic></ABACprincipal>
811 *  <role>r2</role>
812 *  <linking_role>r1</linking_role>
813 * </tail>
814 * becomes P.r1.r2.
815 */
816static xmlChar *term_copy(xmlNodePtr n, xmlChar *dest) {
817    xmlNodePtr p = get_direct_child(n, "ABACprincipal");
818
819    if ( !p ) return NULL;
820    if ( !(p = get_direct_child(p, "keyid"))) return NULL;
821    if ( !(dest = role_copy(get_element_content(p), dest))) return NULL;
822    if ( (p = get_direct_child(n, "linking_role"))) {
823        *dest++ = '.';
824        if ( !(dest = role_copy(get_element_content(p), dest))) return NULL;
825    }
826    if ( (p = get_direct_child(n, "role"))) {
827        *dest++ = '.';
828        if ( !(dest = role_copy(get_element_content(p), dest))) return NULL;
829    }
830    return dest;
831}
832
833/*
834 * Append at most sz characters from a to d and advance d by sz characters.  No
835 * checking is done.
836 */
837static xmlChar *append_and_move(xmlChar *d, xmlChar *a, int sz) {
838    int i = 0; 
839    for ( i = 0; i < sz && a[i] != '\0'; i++) 
840        *d++ = a[i];
841    return d;
842}
843
844static void partial_string_dump(char *s, char *e) {
845    for (; s!= e; s++) 
846        fprintf(stderr, "%c", *s);
847    fprintf(stderr, "\n");
848}
849
850
851/*
852 * Parse a structured RT0 v 1.1 xml into an RT0 string.  For example
853 * <head>
854 *  <ABACprincipal><keyid>A</keyid><mnemonic>...</menmonic></ABACprincipal>
855 *  <role>r</role>
856 * </head>
857 * <tail>
858 *  <ABACprincipal><keyid>B</keyid><mnemonic>...</menmonic></ABACprincipal>
859 *  <role>r2</role>
860 *  <linking_role>r1</linking_role>
861 * </tail>
862 * <tail>
863 *  <ABACprincipal><keyid>C</keyid><mnemonic>...</menmonic></ABACprincipal>
864 *  <role>r2</role>
865 * </tail>
866 *
867 * Converts to A.r<-B.r1.r2 & C.r2
868 */
869xmlChar **parse_rt0_xml_v11(xmlNodePtr n) {
870    int len = 3;    /* Length of the RT0 string we're building. Initially 3 for
871                       the <- and end-of-string */
872    int heads = 0;  /* number of tails so far */
873    int tails = 0;  /* number of tails so far */
874    xmlNodePtr c = NULL;/* Scratch */
875    xmlChar **rv = NULL;
876    xmlChar *d = NULL;
877
878    /* Compute the length of the new string and make sure we have a head and at
879     * least one tail.
880     */
881    if ( !n ) return NULL;
882
883    for (c = n->children; c; c = c->next) {
884        if ( c->type != XML_ELEMENT_NODE ) 
885            continue;
886        if ( !strcmp((char *) c->name, "head") ) {
887            len += term_len(c);
888            heads ++;
889        } else if (!strcmp((char *) c->name, "tail")) {
890            len += term_len(c);
891            /* if more than one tail, add space for " & " */
892            if ( tails++) len += 3; 
893        }
894    }
895    if ( heads != 1 || tails < 1) return NULL;
896
897    /* Allocate the return value */
898    if ( !(rv = malloc(2 * sizeof(xmlChar *)))) return NULL;
899    if (!(rv[0] = malloc(len)) ) {
900        free(rv);
901        return NULL;
902    }
903
904    /* Translate term by term */
905    d = rv[0];
906    if ( !( c = get_direct_child(n, "head"))) goto fail;
907    if ( !(d = term_copy(c, d))) goto fail;
908    d = append_and_move(d, "<-", 2);
909    tails = 0;
910    for (c = n->children; c; c = c->next) {
911        if ( c->type != XML_ELEMENT_NODE ) 
912            continue;
913        if ( !strcmp((char *) c->name, "tail") ) {
914            /* if more than one tail, add " & " */
915            if ( tails++) 
916                d = append_and_move(d, " & ", 3);
917            if ( !(d = term_copy(c, d))) goto fail;
918        }
919    }
920    *d++ = '\0';
921    return rv;
922
923fail:
924    free(rv[0]);
925    free(rv);
926    return NULL;
927} 
928/*
929 * Parse an ABAC credential (that has had its signature checked.  Make sure it
930 * has not expired and that its version is one we know.  Return the RT0 it
931 * encodes as the only entry in an NULL-terminated array of strings (just like
932 * parse_privilege). On failure return NULL.  In addition to parsing the
933 * certificate, we add the issuer's identity from the signature to the
934 * controlling context, if any.  ctxt_id_certs is the list of certificates to
935 * which the new certificate is added.
936 */
937xmlChar **parse_abac(xmlDocPtr doc, void *ctxt_id_certs) {
938    xmlNodePtr root = NULL;     /* XML root node */
939    xmlNodePtr node = NULL;     /* XML credential node */
940    xmlNodePtr rt0 = NULL;      /* XML rt0 node */
941    xmlNodePtr expires = NULL;  /* XML expires node */
942    xmlNodePtr version = NULL;  /* XML version node */
943    xmlChar keyid[SHA_DIGEST_LENGTH];/* issuer SHA1 hash */
944    xmlChar text_keyid[2*SHA_DIGEST_LENGTH+1];/* Issuer keyid in text */
945    xmlChar *txt;               /* rt0 content */
946    xmlChar **rv = NULL;        /* return value */
947    xmlChar *issuer_ptr=NULL;   /* Issuer certificate to add to ctxt_id_certs */
948    GENI_xml_processing_t *proc = NULL; /* Specialization for version number */
949    int ncred = 0;              /* number of creds in rv */
950    int i = 0;                  /* Scratch (used only in fail:)  */
951
952    if ( doc && !(root = xmlDocGetRootElement(doc)) ) 
953        goto fail;
954
955    /* Get the issuer keyid */
956    if ( !get_keyid_from_keyinfo(doc, keyid)) 
957        goto fail;
958    sha1_to_text(keyid, text_keyid);
959    /* get the various nodes of interest */
960    if ( !(node = xmlSecFindNode(root, (xmlChar *) GENI_credential, NULL)))
961        goto fail;
962    if ( !(expires = get_direct_child(node, (xmlChar *) GENI_expires)))
963        goto fail;
964    if ( !check_GENI_expires(get_element_content(expires), NULL))
965        goto fail;
966
967    if ( !(rt0 = get_direct_child(node, (xmlChar *) GENI_rt0))) 
968        goto fail;
969    /* There are two places to look for a version.  The credential node and the
970     * rt0 node that is a child of the credential node.  The version element is
971     * only under the credential in the misdefined GENI abac v1.0. */
972    if ( !(version = get_direct_child(node, (xmlChar *) GENI_version))) {
973        if ( !(version = get_direct_child(rt0, (xmlChar *) GENI_version))) 
974            goto fail;
975    }
976
977    /* Pick parsing specialization based on the version.  If we can't resolve a
978     * processor, this is an unknown version. */
979    if ( !(proc = get_xml_processing(get_element_content(version))))
980        goto fail;
981
982    /* read the RT0 and return it */
983    if ( !(rv = proc->xml_to_rt0(rt0)) ) goto fail;
984    ncred=1;
985
986    /* extract issuer pem and insert */
987    issuer_ptr=get_issuer(doc);
988    if( issuer_ptr && 
989            abac_verifier_load_id_chars(ctxt_id_certs,issuer_ptr) != 
990            ABAC_CERT_SUCCESS) {
991        goto fail;
992    }
993
994    return rv;
995fail:
996    if ( rv ) {
997        for (i = 0; i < ncred; i++) 
998            if (rv[i]) free(rv[i]);
999        free(rv);
1000    }
1001    return NULL;
1002}
1003
1004/* Check and parse a GENI credential.  Return the new RT0 rules in a
1005 * NULL-terminated array of strings.  If the signature or parsing fails, return
1006 * NULL. Demultiplexed to parse_privilege or parse_abac to do the parsing and
1007 * uses check_signature to confirm the sig. If ctxt_id_certs is a list of
1008 * identities known to a context.  If it is not NULL and identity certs appear
1009 * (as they do in GENI credentials) add them to that list, which adds them to
1010 * the ABAC context. */
1011char **read_credential(void *ctxt_id_certs, char *infile, 
1012        char **in_xml) {
1013    xmlChar **xml = (xmlChar **) in_xml;    /* Cast */
1014    xmlDocPtr doc = xmlParseFile(infile);   /* Parse the document */
1015    xmlNodePtr node = NULL;                 /* XML scratch node */
1016    xmlChar *text = NULL;                   /* Text of the type field */
1017    xmlChar **rv = NULL;                    /* return value from parse_* */
1018
1019    if ( !check_signature(doc) ) 
1020        goto fail;
1021    /* Parse out the type field */
1022    if ( !(node = xmlDocGetRootElement(doc)) ) 
1023        goto fail;
1024    if ( !(node = xmlSecFindNode(node, (xmlChar *) GENI_credential, NULL)))
1025        goto fail;
1026    if ( !(node = xmlSecFindNode(node, (xmlChar *) GENI_type, NULL)))
1027        goto fail;
1028
1029    if ( !(text = get_element_content(node)) ) 
1030        goto fail;
1031
1032    /* Demux on type */
1033    if ( !strcmp((char *) text, "privilege")) {
1034        rv = parse_privilege(doc, ctxt_id_certs);
1035    } else if ( !strcmp((char *) text, "abac")) {
1036        rv = parse_abac(doc, ctxt_id_certs);
1037    } else { 
1038        goto fail;
1039    }
1040    int len=0;
1041    xmlDocDumpMemoryEnc(doc, xml, &len, "UTF-8");
1042    if(len == 0)
1043       goto fail;
1044
1045fail:
1046    xmlFreeDoc(doc);
1047    return (char **) rv;
1048}
1049
1050
1051/* format for dates in <expires> */
1052char *strftime_fmt = "%FT%TZ";
1053#define EXPIRESLEN 20
1054
1055/* Return a copy of str with > < and & replaced by &gt; &lt; and &amp; for
1056 * embedding in XML.  Caller is responsible for deallocating the return value
1057 * using xmlFree().
1058 */
1059static xmlChar *minimal_xml_escaping(xmlChar *str) {
1060    /* A quickie translation table with the character to escape, the output
1061     * string and the length of the output in it. The table is initialized with
1062     * the three translations we want. */
1063    static struct esc {
1064        xmlChar c;
1065        xmlChar *esc;
1066        int l;
1067    } escapes[] = {
1068        { (xmlChar) '<', (xmlChar *) "&lt;", 4 }, 
1069        { (xmlChar) '>', (xmlChar *) "&gt;", 4},
1070        { (xmlChar) '&', (xmlChar *) "&amp;", 5},
1071        { (xmlChar) '\0', NULL, 0 },
1072    };
1073
1074    xmlChar *rv = NULL;     /* Return value */
1075    xmlChar *p = NULL;      /* Scratch (walking str) */
1076    xmlChar *q = NULL;      /* Scratch (walking rv) */
1077    struct esc *e = NULL;   /* Scratch for walking escapes */
1078    int len = 0;            /* Length of rv */
1079
1080    /* Walk str and calculate how long the escaped version is */
1081    for ( p = str; *p ; p++) {
1082        int foundit = 0;
1083        for ( e = escapes; !foundit && e->c ; e++ ) {
1084            if ( *p == e->c ) {
1085                len += e->l;
1086                foundit = 1;
1087            }
1088        }
1089        if ( !foundit ) len++;
1090    }
1091    /* Allocate the new string */
1092    q = rv = (xmlChar *) xmlMalloc(len+1);
1093    /* copy str to rv, escaping when necessary */
1094    for ( p = str; *p ; p++) {
1095        int foundit = 0;
1096        for ( e = escapes; !foundit && e->c ; e++ ) {
1097            if ( *p == e->c ) {
1098                strncpy((char *) q, (char *) e->esc, e->l);
1099                q += e->l;
1100                foundit = 1;
1101            }
1102        }
1103        if ( !foundit ) *q++ = *p;
1104    }
1105    /* terminate rv */
1106    *q = '\0';
1107    return rv;
1108}
1109
1110xmlChar *encode_rt0_xml_v10(abac_attribute_t *a) {
1111    return minimal_xml_escaping(abac_attribute_role_string(a));
1112}
1113
1114/* Template to create a head element in structured XML for RT0 (v1.1).  All
1115 * heads are a single role element */
1116static char *head_template = 
1117"<head>\n"
1118"   <ABACprincipal><keyid>%s</keyid></ABACprincipal>\n"
1119"   <role>%s</role>\n"
1120"</head>\n";
1121
1122/* Templates to create a tail in structured XML  based on how many of
1123 * principal, role, and linking role are present. */
1124static char *tail_template[] = {
1125"<tail>\n"
1126"   <ABACprincipal><keyid>%s</keyid></ABACprincipal>\n"
1127"</tail>\n",
1128"<tail>\n"
1129"   <ABACprincipal><keyid>%s</keyid></ABACprincipal>\n"
1130"   <role>%s</role>\n"
1131"</tail>\n",
1132"<tail>\n"
1133"   <ABACprincipal><keyid>%s</keyid></ABACprincipal>\n"
1134"   <role>%s</role>\n"
1135"   <linking_role>%s</linking_role>\n"
1136"</tail>\n",
1137};
1138
1139/* Convert the given attribute to the RT0 structured XML representation used by
1140 * version 1.1 credentials.
1141 */
1142xmlChar *encode_rt0_xml_v11(abac_attribute_t *a) {
1143    int htlen = strlen(head_template);      /* head template length */
1144    int ttlen = strlen(tail_template[2]);   /* length of the longest tail
1145                                               template */
1146    /* Size of the string we'll need - start with a head template and string */
1147    int sz = strlen(abac_attribute_get_head(a)) + htlen;
1148    /* Number of tails in the sttribute */
1149    int ntails = abac_attribute_get_ntails(a);
1150    char *princ_role[2];    /* Used to split the head role */
1151    char *copy = abac_xstrdup(abac_attribute_get_head(a)); /* splitting */
1152    int npr = 2;            /* Number of parts in the head role */
1153    char *tmp = NULL;       /* A temporary to build each tail element */
1154    char *rv = NULL;        /* The return value */
1155    int i;                  /* Scratch */
1156
1157    /* Add the tail lengths to the total length (assume all tails will need the
1158     * largest template for slop). */
1159    for ( i = 0 ; i < ntails; i++)
1160        sz += strlen(abac_attribute_get_tail_n(a, i)) + ttlen;
1161
1162    /* Get the rv and scratch string.  Since tmp is as long as the whole
1163     * string, it's big enough for any substring */
1164    if ( !(rv = (char *) xmlMalloc(sz)) ) goto fail;
1165    if ( !(tmp = (char *) xmlMalloc(sz)) ) goto fail;
1166
1167    abac_split(copy, ".", princ_role, &npr);
1168    if ( npr != 2) 
1169        goto fail;
1170
1171    /* Put the head in */
1172    sz -= snprintf(rv, sz, head_template, princ_role[0], princ_role[1]);
1173
1174    for ( i = 0 ; i < ntails; i++) {
1175        /* Make a role for each tail and use those functions to write out the
1176         * structures for the different kinds of role. */
1177        abac_role_t *r = abac_role_from_string(abac_attribute_get_tail_n(a,i));
1178        int ts;
1179
1180        if ( !r )
1181            goto fail;
1182
1183        if ( abac_role_is_principal(r)) {
1184            char *p = minimal_xml_escaping(abac_role_principal(r));
1185
1186            ts = snprintf(tmp, sz, tail_template[0], p);
1187            free(p);
1188        } else if (abac_role_is_role(r)) {
1189            char *p = minimal_xml_escaping(abac_role_principal(r));
1190            char *ro = minimal_xml_escaping(abac_role_role_name(r));
1191
1192            ts = snprintf(tmp, sz, tail_template[1], p, ro);
1193            free(p);
1194            free(ro);
1195        } else if (abac_role_is_linking(r)) {
1196            char *p = minimal_xml_escaping(abac_role_principal(r));
1197            char *ro = minimal_xml_escaping(abac_role_role_name(r));
1198            char *li = minimal_xml_escaping(abac_role_linking_role(r));
1199
1200            ts = snprintf(tmp, sz, tail_template[2], p, ro, li);
1201            free(p);
1202            free(ro);
1203            free(li);
1204        }
1205
1206        free(r);
1207
1208        if ( ts < 0 ) 
1209            goto fail;
1210
1211        strncat(rv, tmp, sz);
1212        sz -= ts;
1213    }
1214    free(tmp);
1215    return (xmlChar *) rv;
1216
1217fail:
1218    if (rv ) free(rv);
1219    if (tmp) free(tmp);
1220    return NULL;
1221}
1222
1223/* Make an new GENI abac credential with the rt0 rule that expires secs from
1224 * now.  cert is the PEM encoded X.509 of the issuer's certificate as a string.
1225 * certlen is the length of cert.  Returns the XML. Caller is responsible for
1226 * freeing it. */
1227char *make_credential(abac_attribute_t *attr, int secs, char *in_cert, 
1228        int in_certlen) {
1229    xmlSecByte *cert = (xmlSecByte *) in_cert; /* Cast of certificate */
1230    xmlSecSize certlen = (xmlSecSize) in_certlen; /* Cast of len */
1231    xmlDocPtr doc = NULL;       /* parsed XML document */
1232    xmlNodePtr root = NULL;     /* Root of the document */
1233    xmlNodePtr signNode = NULL; /* <Signature> element */
1234    xmlSecDSigCtxPtr dsigCtx = NULL;  /* Signing context */
1235    /*xmlChar *rt0_escaped = minimal_xml_escaping(rt0); /* RT0, escaped */
1236    xmlChar *rt0_xml = NULL;    /* attr's RT0 as xml */
1237    xmlChar *rv = NULL;         /* return value */
1238    time_t exp;                 /* expriation time (seconds since epoch) */
1239    struct tm exp_tm;           /* expiration for formatting */
1240    char estr[EXPIRESLEN+1];    /* String with formatted expiration */
1241    char *temp = NULL;          /* populated XML template */
1242    int len = 0;                /* length of the populated template (temp) */
1243
1244    GENI_xml_processing_t *proc = get_xml_processing(
1245            abac_attribute_get_output_format(attr));
1246
1247    if ( !proc ) goto fail;
1248    if ( !(rt0_xml = proc->rt0_to_xml(attr))) goto fail;
1249
1250    /* Calculate the length of the populated template and allocate it */
1251    len = strlen((char *) proc->out_template)+EXPIRESLEN+
1252        strlen((char *) rt0_xml)+1;
1253
1254    if ( !(temp = malloc(len)) )
1255        goto fail;
1256
1257    /* format expiration */
1258    time(&exp);
1259    exp += secs;
1260    gmtime_r(&exp, &exp_tm);
1261
1262    if (strftime(estr, EXPIRESLEN+1, strftime_fmt, &exp_tm) == 0 ) 
1263        goto fail;
1264
1265    /* Populate template with  expiration and escaped rt0 */
1266    snprintf(temp, len, proc->out_template, estr, (char *) rt0_xml);
1267
1268    /* parse the populated template */
1269    if ( !(doc = xmlParseMemory(temp, len))) 
1270        goto fail;
1271
1272    if (!(root = xmlDocGetRootElement(doc)) )
1273        goto fail;
1274
1275    /* Find the signature element for the Signing call */
1276    signNode = xmlSecFindNode(root, xmlSecNodeSignature, xmlSecDSigNs);
1277
1278    /* Create the context */
1279    if ( !(dsigCtx = xmlSecDSigCtxCreate(NULL))) 
1280        goto fail;
1281
1282    /* Assign the key (a PEM key) */
1283    if (!(dsigCtx->signKey = xmlSecCryptoAppKeyLoadMemory(cert, certlen,
1284                    xmlSecKeyDataFormatPem, NULL, NULL, NULL)) )
1285        goto fail;
1286
1287    /* Load the certificate */
1288    if ( xmlSecCryptoAppKeyCertLoadMemory(dsigCtx->signKey, cert, certlen,
1289                xmlSecKeyDataFormatPem) < 0)
1290        goto fail;
1291
1292    /* Sign it */
1293    if ( xmlSecDSigCtxSign(dsigCtx, signNode) < 0)
1294        goto fail;
1295
1296    /* Store the signed credential to rv */
1297    xmlDocDumpMemoryEnc(doc, &rv, &len, "UTF-8");
1298fail:
1299    /* clean up */
1300    if (dsigCtx) 
1301        xmlSecDSigCtxDestroy(dsigCtx);
1302    if ( doc) xmlFreeDoc(doc);
1303    if (rt0_xml) xmlFree(rt0_xml);
1304    if ( temp) free(temp);
1305    return (char *) rv;
1306}
1307
1308#define CERTSIZE 4096
1309/* Read a file into a the dynamically allocated array buf.  Whatever was in buf
1310 * is discarded w/o freeing so it should initially be NULL and len 0. On return
1311 * buf contains as much of the contents of filename as possible and len is the
1312 * length of it.  The caller must free() buf. buf is zero terminated.*/
1313static void read_cert(char *filename, char **buf, int *len) {
1314    FILE *cert = NULL;
1315    char *nbuf = NULL;
1316    int cap = CERTSIZE;
1317    int r = 0;
1318
1319    *len = 0; 
1320    if (!(*buf = malloc(CERTSIZE))) return;
1321
1322    if ( !(cert = fopen(filename, "r"))) 
1323        goto fail;
1324
1325    /* Read cert, expanding buf as necessary */
1326    while ( (r = fread(*buf + *len, 1, cap - *len, cert)) != 0) {
1327        *len += r;
1328        if ( *len == cap ) {
1329            if ( !(nbuf = realloc(*buf, cap + CERTSIZE)) ) 
1330                goto fail;
1331            memcpy(nbuf, *buf, cap);
1332            cap += CERTSIZE;
1333            *buf = nbuf;
1334        }
1335    }
1336    /* Extend if we read exactly cap bytes so we can terminate the string */
1337    if ( *len == cap ) {
1338        if ( !(nbuf = realloc(*buf, cap + CERTSIZE)) ) 
1339            goto fail;
1340        memcpy(nbuf, *buf, cap);
1341        cap += CERTSIZE;
1342        *buf = nbuf;
1343    }
1344    (*buf)[*len] = '\0';
1345    return;
1346fail:
1347    if ( *buf) free(*buf);
1348    *buf = NULL;
1349    *len = 0;
1350    return;
1351}
1352
1353
1354/******** helper functions used by libabac **********************/
1355
1356/* Function to disable libXML2's debugging */
1357static void _nullGenericErrorFunc(void* ctxt, const char* msg, ...) { return; }
1358
1359/* Straight off http://www.aleksey.com/xmlsec/api/xmlsec-examples.html .
1360 * Voodoo.  But call it. */
1361int init_xmlsec() {
1362    /* Init xmlsec library */
1363    if(xmlSecInit() < 0) {
1364        fprintf(stderr, "Error: xmlsec initialization failed.\n");
1365        return(-1);
1366    }
1367
1368    /* Check loaded library version */
1369    if(xmlSecCheckVersion() != 1) {
1370        fprintf(stderr,
1371                "Error: loaded xmlsec library version is not compatible.\n");
1372        return(-1);
1373    }
1374
1375    /* Load default crypto engine if we are supporting dynamic
1376     * loading for xmlsec-crypto libraries. Use the crypto library
1377     * name ("openssl", "nss", etc.) to load corresponding
1378     * xmlsec-crypto library.
1379     */
1380#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
1381    if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
1382        fprintf(stderr, "Error: unable to load default xmlsec-crypto library. "
1383                "Make sure\n" 
1384                "that you have it installed and check shared libraries path\n"
1385                "(LD_LIBRARY_PATH) envornment variable.\n");
1386        return(-1);     
1387    }
1388#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */
1389
1390    /* Init crypto library */
1391    if(xmlSecCryptoAppInit(NULL) < 0) {
1392        fprintf(stderr, "Error: crypto initialization failed.\n");
1393        return(-1);
1394    }
1395
1396    /* Init xmlsec-crypto library */
1397    if(xmlSecCryptoInit() < 0) {
1398        fprintf(stderr, "Error: xmlsec-crypto initialization failed.\n");
1399        return(-1);
1400    }
1401    /* Turn off the built in debugging */
1402    xmlThrDefSetGenericErrorFunc(NULL, _nullGenericErrorFunc);
1403    xmlSetGenericErrorFunc(NULL, _nullGenericErrorFunc);
1404
1405    return 0;
1406}
1407
1408int deinit_xmlsec() {
1409  /* no op for now */
1410    return 0;
1411}
1412
1413
1414/* parse the xml blob and extract keyid */ 
1415char *get_keyid_from_xml(char *xml) {
1416    xmlDocPtr doc=xmlParseMemory(xml,strlen(xml));
1417    xmlChar keyid[SHA_DIGEST_LENGTH];   /* Issuer key SHA1 */
1418    xmlChar text_keyid[2*SHA_DIGEST_LENGTH+1];/* Issuer keyid as text */
1419    char *ret=NULL;
1420
1421    /* Get the issuer keyid */
1422    if ( !get_keyid_from_keyinfo(doc, keyid))
1423        goto fail;
1424    sha1_to_text(keyid, text_keyid);
1425    ret=strdup((char *)text_keyid);
1426fail:
1427    xmlFreeDoc(doc);
1428    return ret;
1429}
1430
1431/* parse xml and get the expected expiration time and returns
1432 * (expiration time-current time)
1433 */
1434long get_validity_from_xml(char *xml) {
1435    xmlDocPtr doc=xmlParseMemory(xml,strlen(xml));
1436    xmlNodePtr node = NULL;                 /* XML scratch node */
1437    xmlNodePtr expires = NULL;  /* XML expires node */
1438    struct tm tv;   /* Parsed expires field */
1439    time_t now;     /* Now in seconds since the epoch */
1440    time_t exp;     /* expires in seconds since the epoch */
1441    long dtime=0;
1442
1443    if ( !(node = xmlDocGetRootElement(doc)) )
1444        goto fail;
1445
1446    if ( !(expires = xmlSecFindNode(node, (xmlChar *) GENI_expires, NULL)))
1447        goto fail;
1448
1449    xmlChar *etime=get_element_content(expires);
1450    time(&now);
1451
1452    strptime((char *) etime, "%FT%TZ", &tv);
1453    exp = timegm(&tv);
1454    dtime=difftime(exp, now);
1455
1456fail:
1457    xmlFreeDoc(doc);
1458    return dtime;
1459}
1460
1461/* parse xml structure and extract the attribute rules */
1462char **get_rt0_from_xml(void *ctxt_id_certs,char *xml) {
1463    xmlDocPtr doc=xmlParseMemory(xml,strlen(xml));
1464    xmlNodePtr node = NULL;                 /* XML scratch node */
1465    xmlChar *text = NULL;                   /* Text of the type field */
1466    xmlChar **rv = NULL;                    /* return value from parse_* */
1467   
1468    if ( !check_signature(doc) )
1469        goto fail;
1470    /* Parse out the type field */
1471    if ( !(node = xmlDocGetRootElement(doc)) )
1472        goto fail;
1473    if ( !(node = xmlSecFindNode(node, (xmlChar *) GENI_credential, NULL)))
1474        goto fail;
1475    if ( !(node = xmlSecFindNode(node, (xmlChar *) GENI_type, NULL)))
1476        goto fail;
1477
1478    if ( !(text = get_element_content(node)) )
1479        goto fail;
1480
1481    /* Demux on type */
1482    if ( !strcmp((char *) text, "privilege")) {
1483        rv = parse_privilege(doc,ctxt_id_certs);
1484    } else if ( !strcmp((char *) text, "abac")) {
1485        rv = parse_abac(doc, ctxt_id_certs);
1486    } else {
1487        goto fail;
1488    }
1489fail:
1490    xmlFreeDoc(doc);
1491    return (char **)rv;
1492}
1493
1494
Note: See TracBrowser for help on using the repository browser.