source: libabac/abac_xml.c @ e50f807

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

Parse and produce 1.1 credentials. Small tweaks, too.

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