source: libabac/abac_xml.c @ 8164e70

abac0-leak
Last change on this file since 8164e70 was 8164e70, checked in by Mei <mei@…>, 11 years ago

1) tweak with changes for handling abac_chunk_t

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