source: libabac/abac_xml.c @ f6576c4

abac0-leak
Last change on this file since f6576c4 was f2622ee, checked in by Mei-Hui Su <mei@…>, 11 years ago

1) ran with valgrind and did some leak patching

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