source: libabac/abac_xml.c @ f70a129

Last change on this file since f70a129 was f70a129, checked in by Ted Faber <faber@…>, 10 years ago

Merge branch 'master' of git://abac.deterlab.net/abac

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