Index: libabac/abac.c
===================================================================
--- libabac/abac.c	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/abac.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -1,7 +1,7 @@
+/* abac.c */
+
 #include <assert.h>
 #include <err.h>
 #include <glob.h>
-
-#include <chunk.h>
 
 #include "abac.h"
@@ -80,7 +80,6 @@
  * Load an ID cert from a chunk.
  */
-int abac_context_load_id_chunk(abac_context_t *ctx, abac_chunk_t cert) {
-    assert(ctx != NULL);
-    chunk_t cert_chunk = { cert.ptr, cert.len };
+int abac_context_load_id_chunk(abac_context_t *ctx, abac_chunk_t cert_chunk) {
+    assert(ctx != NULL);
     return abac_verifier_load_id_chunk(cert_chunk);
 }
@@ -91,15 +90,22 @@
 int abac_context_load_attribute_file(abac_context_t *ctx, char *filename) {
     int ret, add_ret;
+    abac_list_t *cred_list=abac_list_new(); // could be more than 1
     abac_credential_t *cred;
 
     assert(ctx != NULL); assert(filename != NULL);
 
-    ret = abac_verifier_load_attribute_cert_file(filename, &cred);
+    ret = abac_verifier_load_attribute_cert_file(filename, cred_list);
+
     if (ret == ABAC_CERT_SUCCESS) {
-        add_ret = abac_graph_add_credential(ctx->graph, cred);
-        assert(add_ret != ABAC_GRAPH_CRED_INVALID);
-        abac_credential_free(cred);
-    }
-
+        int size = abac_list_size(cred_list);
+        if(size) {
+            abac_list_foreach(cred_list, cred,
+                add_ret = abac_graph_add_credential(ctx->graph, cred);
+                assert(add_ret != ABAC_GRAPH_CRED_INVALID);
+                abac_credential_free(cred);
+            );
+            abac_list_free(cred_list);
+        }
+    }
     return ret;
 }
@@ -108,17 +114,22 @@
  * Load an attribute cert from a chunk.
  */
-int abac_context_load_attribute_chunk(abac_context_t *ctx, abac_chunk_t cert) {
+int abac_context_load_attribute_chunk(abac_context_t *ctx, abac_chunk_t cert_chunk) {
     int ret, add_ret;
+    abac_list_t  *cred_list=NULL;
     abac_credential_t *cred;
 
     assert(ctx != NULL);
 
-    chunk_t cert_chunk = { cert.ptr, cert.len };
-
-    ret = abac_verifier_load_attribute_cert_chunk(cert_chunk, &cred);
+    ret = abac_verifier_load_attribute_cert_chunk(cert_chunk, cred_list);
     if (ret == ABAC_CERT_SUCCESS) {
-        add_ret = abac_graph_add_credential(ctx->graph, cred);
-        assert(add_ret != ABAC_GRAPH_CRED_INVALID);
-        abac_credential_free(cred);
+        int size = abac_list_size(cred_list);
+        if(size) {
+            abac_list_foreach(cred_list, cred,
+                add_ret = abac_graph_add_credential(ctx->graph, cred);
+                assert(add_ret != ABAC_GRAPH_CRED_INVALID);
+                abac_credential_free(cred);
+            );
+            abac_list_free(cred_list);
+        }
     }
 
@@ -127,5 +138,5 @@
 
 #define ID_PAT "/*_ID.{der,pem}"
-#define ATTR_PAT "/*_attr.der"
+#define ATTR_PAT "/*_attr.xml"
 
 /**
Index: libabac/abac.h
===================================================================
--- libabac/abac.h	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/abac.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -2,9 +2,19 @@
 #define __ABAC_H__
 
-#include <abac_common.h>
+#include <time.h>  // for struct tm 
+#include <stdio.h> // for FILE
+#include "abac_list.h"
 
 typedef struct _abac_context_t abac_context_t;
 typedef struct _abac_credential_t abac_credential_t;
 typedef struct _abac_role_t abac_role_t;
+
+typedef struct _abac_id_t abac_id_t;
+typedef struct _abac_attribute_t abac_attribute_t;
+
+typedef struct _abac_chunk_t {
+    unsigned char *ptr;
+    int len;
+} abac_chunk_t;
 
 /*
@@ -69,4 +79,148 @@
 
 /*
+ * Operations on ID
+ */
+// create an ID from an X.509 certificate
+abac_id_t *abac_id_from_file(char *);
+
+// create an ID from a X.509 certificate PEM chunk
+abac_id_t *abac_id_from_chunk(abac_chunk_t chunk);
+
+// load an X.509 private key from a file
+int abac_id_privkey_from_file(abac_id_t *id, char *filename);
+
+// generate an ID
+// returns one of ABAC_SUCCESS or ABAC_GENERATE_* (see top)
+int abac_id_generate(abac_id_t **ret, char *cn, long validity);
+
+// get the SHA1 keyid, pointer is valid for the lifetime of the object
+char *abac_id_keyid(abac_id_t *id);
+
+// get the name of the issuer
+// caller must free the returned string
+char *abac_id_issuer(abac_id_t *id);
+
+// get the DN of the subject
+// caller must free the returned string
+char *abac_id_subject(abac_id_t *id);
+
+// check if the cert is still valid
+int abac_id_still_valid(abac_id_t *id);
+
+// check if the principal cert's keyid is specified
+int abac_id_has_keyid(abac_id_t *id, char *);
+
+// check if the cert is has a private key
+int abac_id_has_privkey(abac_id_t *id);
+
+// get the validity period of the cert
+int abac_id_validity(abac_id_t *id, struct tm *not_before, struct tm *not_after);
+
+// default filename for the cert: ${CN}_ID.pem
+// caller must free the returned string
+char *abac_id_cert_filename(abac_id_t *id);
+
+// write the cert fo an open file pointer
+int abac_id_write_cert(abac_id_t *id, FILE *out);
+
+// default filename for the private key: ${CN}_key.pem
+// caller must free the return value
+char *abac_id_privkey_filename(abac_id_t *id);
+
+// write the private key to a file
+// it is recommended that you open this file mode 0600
+// returns false if there's no private key loaded
+int abac_id_write_privkey(abac_id_t *id, FILE *out);
+
+// get a chunk representing the cert
+// you must free the ptr of the chunk when done
+abac_chunk_t abac_id_cert_chunk(abac_id_t *id);
+
+// dup an ID (increases its refcount)
+abac_id_t *abac_id_dup(abac_id_t *id);
+
+// destroy the id
+// decreases refcount and destroys when it hits 0
+void abac_id_free(abac_id_t *id);
+
+/*
+ * Operations on Attribute
+ */
+//
+// Here's the skinny:
+//  Attribute cert objects don't contain an actual cert until they're baked.
+//  First you construct the object using abac_attribute_create, then you add
+//  subjects to it using abac_attribute_{principal,role,linking_role}.
+//  Finally you bake it. Once you've done that, you can keep it as XML chunk
+//  or write it to a file.
+//
+
+// create an attribute cert
+// validity is in days
+// returns one of CREDDY_SUCCESS or CREDDY_ATTRIBUTE_* (see top)
+int abac_attribute_create(abac_attribute_t **attr, abac_id_t *issuer, char *role, long validity);
+
+// add a head string to the cert
+void abac_attribute_set_head(abac_attribute_t *attr, char *string);
+
+// return the head string of the attribute
+char *abac_attribute_get_head(abac_attribute_t *);
+
+// add a tail role string to the cert
+void abac_attribute_set_tail(abac_attribute_t *attr, char *string);
+
+// return the tail string of the attribute
+char *abac_attribute_get_tail(abac_attribute_t *);
+
+// add a principal subject to the cert
+int abac_attribute_principal(abac_attribute_t *attr, char *keyid);
+
+// add a role subject
+int abac_attribute_role(abac_attribute_t *attr, char *keyid, char *role);
+
+// add a linking role subject
+int abac_attribute_linking_role(abac_attribute_t *attr, char *keyid, char *role, char *linked);
+
+// create the attribute cert once all the subjects have been added
+// can return 0 if there are no subjects or there's a problem building the cert
+int abac_attribute_bake(abac_attribute_t *attr);
+
+// returns true iff the cert's been baked
+int abac_attribute_baked(abac_attribute_t *attr);
+
+// write the cert to a file. returns 0 if the cert hasn't been baked
+int abac_attribute_write(abac_attribute_t *attr, FILE *out);
+
+// get chunked cert
+// returns 0 if the cert isn't baked
+int abac_attribute_cert_chunk(abac_attribute_t *, abac_chunk_t *);
+
+// destroy the cert
+void abac_attribute_free(abac_attribute_t *);
+
+// load a list of attr cert from file (aborts on fail)
+abac_list_t *abac_attribute_certs_from_file(char *);
+
+// load a list of attr cert from chunk (aborts on fail)
+abac_list_t *abac_attribute_certs_from_chunk(abac_chunk_t);
+
+// get the attribute role string
+char *abac_attribute_role_string(abac_attribute_t *attr);
+
+// get the issuer id of an attribute
+abac_id_t *abac_attribute_issuer_id(abac_attribute_t *ptr);
+
+// get the validity period of the attribute cert
+int abac_attribute_validity(abac_attribute_t *attr, struct tm *not_before, struct tm *not_after);
+
+// return the principal from an attribute's role string
+// callee must free the space
+char *abac_attribute_get_principal(abac_attribute_t *attr);
+
+// check if the attribute cert is still valid
+int abac_attribute_still_valid(abac_attribute_t *attr);
+
+
+/*
  * Error codes for loading certificates.
  */
@@ -75,4 +229,21 @@
 #define ABAC_CERT_BAD_SIG           -2  // invalid signature
 #define ABAC_CERT_MISSING_ISSUER    -3  // missing ID cert that issued the attribute cert
+#define ABAC_CERT_BAD_PRINCIPAL     -4  // Principal of attribute cert issuer has mismatch keyid
+#define ABAC_CERT_INVALID_ISSUER    -5  // Issuer of attribute cert is invalid
+#define ABAC_CERT_SIGNER_NOKEY      -6  // Signer of attribute cert is missing private key
+
+/*
+ * Error codes for IDs and Attributes
+ */
+#define ABAC_SUCCESS                          0
+#define ABAC_FAILURE                          1 /* catch all */
+#define ABAC_GENERATE_INVALID_CN             -1
+#define ABAC_GENERATE_INVALID_VALIDITY       -2
+#define ABAC_ATTRIBUTE_ISSUER_NOKEY          -3
+#define ABAC_ATTRIBUTE_INVALID_ROLE          -4
+#define ABAC_ATTRIBUTE_INVALID_VALIDITY      -5
+#define ABAC_ATTRIBUTE_INVALID_ISSUER        -6
+
+
 
 #endif /* __ABAC_H__ */
Index: libabac/abac.hh
===================================================================
--- libabac/abac.hh	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/abac.hh	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -2,4 +2,6 @@
 #define __ABAC_HH__
 
+#include <cstdio>
+#include <stdexcept>
 #include <string>
 #include <vector>
@@ -108,4 +110,159 @@
             abac_context_t *m_ctx;
     };
+
+    class ID {
+        public:
+            ID() : m_id(NULL) { } // do not use: required by swig
+
+            // load an ID from a file
+            ID(char *filename) : m_id(NULL) {
+                m_id = abac_id_from_file(filename);
+                if (m_id == NULL)
+                    throw std::invalid_argument("Could not load ID cert");
+            }
+
+            // load an ID from a chunk
+            ID(abac_chunk_t chunk) : m_id(NULL) {
+                m_id = abac_id_from_chunk(chunk);
+                if (m_id == NULL)
+                    throw std::invalid_argument("Could not load ID cert");
+            }
+
+            // generate an ID with a given CN and validity
+            ID(char *cn, int validity) : m_id(NULL) {
+                int ret = abac_id_generate(&m_id, cn, validity);
+                if (ret == ABAC_GENERATE_INVALID_CN)
+                    throw std::invalid_argument("CN must be alphanumeric and start with a letter");
+                if (ret == ABAC_GENERATE_INVALID_VALIDITY)
+                    throw std::invalid_argument("Validity must be > 0 days");
+            }
+
+            ID(const ID &id) { m_id = abac_id_dup(id.m_id); }
+
+            ~ID() { abac_id_free(m_id); }
+
+            // load private key from a file
+            void load_privkey(char *filename) {
+                int ret = abac_id_privkey_from_file(m_id, filename);
+                if (!ret)
+                    throw std::invalid_argument("Could not load private key");
+            }
+
+            char *keyid() { return abac_id_keyid(m_id); }
+            char *cert_filename() { return abac_id_cert_filename(m_id); }
+            void write_cert(std::FILE *out) { abac_id_write_cert(m_id, out); }
+            void write_cert(const std::string &name) {
+                std::FILE *out = fopen(name.c_str(), "w");
+                if (out == NULL)
+                    throw std::invalid_argument("Could not open cert file for writing");
+                write_cert(out);
+                fclose(out);
+            }
+            // Simplifies access from swig
+            void write_cert(const char *n) {
+                write_cert(std::string(n));
+            }
+            char *privkey_filename() { return abac_id_privkey_filename(m_id); }
+
+            // write the private ket
+            // throws a std::logic_error if no private key is loaded
+            void write_privkey(std::FILE *out) {
+                int ret = abac_id_write_privkey(m_id, out);
+                if (!ret) throw std::logic_error("No private key loaded");
+            }
+            void write_privkey(const std::string &name) {
+                std::FILE *out = fopen(name.c_str(), "w");
+                if (out == NULL)
+                    throw std::invalid_argument("Could not open privkey file for writing");
+                write_privkey(out);
+                fclose(out);
+            }
+            // Simplifies access from swig
+            void write_privkey(const char *name) {
+                write_privkey(std::string(name));
+            }
+
+            abac_chunk_t cert_chunk() { return abac_id_cert_chunk(m_id); }
+
+            friend class Attribute;
+
+        private:
+            abac_id_t *m_id;
+    };
+
+    class Attribute {
+        public:
+            Attribute() : m_attr(NULL) { } // do not use: required by swig
+
+            // create a cert
+            Attribute(ID &issuer, char *role, int validity) : m_attr(NULL) {
+                int ret = abac_attribute_create(&m_attr, issuer.m_id, role, validity);
+                if (ret == ABAC_ATTRIBUTE_ISSUER_NOKEY)
+                    throw std::invalid_argument("Issuer has no private key");
+                if (ret == ABAC_ATTRIBUTE_INVALID_ROLE)
+                    throw std::invalid_argument("Role name must be alphanumeric");
+                if (ret == ABAC_ATTRIBUTE_INVALID_VALIDITY)
+                    throw std::invalid_argument("Validity must be > 0 days");
+                if (ret == ABAC_ATTRIBUTE_INVALID_ISSUER)
+                    throw std::invalid_argument("Issuer's validity expired");
+            }
+
+            ~Attribute() { abac_attribute_free(m_attr); }
+
+            // these return false if there's a bad keyid or role name
+            // they'll throw a std::logic_error if the cert's been baked
+            bool principal(char *keyid) {
+                if (baked()) throw std::logic_error("Cert is already baked");
+                return abac_attribute_principal(m_attr, keyid);
+            }
+            bool role(char *keyid, char *role) {
+                if (baked()) throw std::logic_error("Cert is already baked");
+                return abac_attribute_role(m_attr, keyid, role);
+            }
+            bool linking_role(char *keyid, char *role, char *linked) {
+                if (baked()) throw std::logic_error("Cert is already baked");
+                return abac_attribute_linking_role(m_attr, keyid, role, linked);
+            }
+
+            // returns false if there are no subjects or libstrongswan fails
+            // throws a std::logic_error if the cert's already been baked
+            bool bake() {
+                if (baked()) throw std::logic_error("Cert is already baked");
+                return abac_attribute_bake(m_attr);
+            }
+
+            // returns true iff the cert's been baked
+            bool baked() { return abac_attribute_baked(m_attr); }
+
+            // throws a std::logic_error if the cert isn't baked
+            void write(std::FILE *out) {
+                int ret = abac_attribute_write(m_attr, out);
+                if (!ret) throw std::logic_error("Cert is not baked");
+            }
+
+            void write(const std::string &name) {
+                std::FILE *out = fopen(name.c_str(), "w");
+                if (out == NULL)
+                    throw std::invalid_argument("Could not open cert file for writing");
+                write(out);
+                fclose(out);
+            }
+
+            // Simplifies access from swig
+            void write(const char *name) {
+                write(std::string(name));
+            }
+
+            // throws a std::logic_error if the cert isn't baked
+            abac_chunk_t cert_chunk() {
+                abac_chunk_t ret;
+                if (!baked()) throw std::logic_error("Cert is not baked");
+                abac_attribute_cert_chunk(m_attr, &ret);
+                return ret;
+            }
+
+        private:
+            abac_attribute_t *m_attr;
+    };
 }
 
Index: libabac/abac_attribute.c
===================================================================
--- libabac/abac_attribute.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
+++ libabac/abac_attribute.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -0,0 +1,418 @@
+
+/* abac_attribute.c */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+
+#include "libabac_common.h"
+#include "abac_util.h"
+#include "abac_xml.h"
+
+#define ROLE_SEPARATOR " <- "
+#define INTERSECTION_SEP " & "
+#define SHA1_LENGTH 40
+
+static int debug=0;
+
+// a GENI XML attribute chunk might contain multiple 
+// attribute rules. It will be translate into multiple
+// abac_attribute structures but with cert ptr pointing
+// to the same xml chunk
+// issuer can be missing but then it won't be bakable
+// unless it is baked just for creddy's roles call
+struct _abac_attribute_t {
+    abac_id_t *issuer_id; 
+    char *role;
+    long validity;
+
+    char *head_string;
+    char *tail_string;
+
+    abac_chunk_t cert; // the XML chunk
+};
+
+char *abac_attribute_role_string(abac_attribute_t *attr);
+extern abac_id_t *abac_verifier_lookup_id(char *keyid);
+static char *_validate_principal(char *keyid);
+
+/************************************************************/
+abac_chunk_t abac_attribute_cert(abac_attribute_t *ptr)
+{
+    assert(ptr);
+    return ptr->cert;
+}
+
+abac_id_t *abac_attribute_issuer_id(abac_attribute_t *ptr)
+{
+    assert(ptr);
+    return ptr->issuer_id;
+}
+
+// validity is measured in seconds (as of 0.2.0)
+// Acme.customer
+int abac_attribute_create(abac_attribute_t **ret, abac_id_t *issuer_id, char *role, long validity) {
+    if (!abac_id_has_privkey(issuer_id))
+        return ABAC_ATTRIBUTE_ISSUER_NOKEY;
+    if (!abac_clean_name(role))
+        return ABAC_ATTRIBUTE_INVALID_ROLE;
+    if (validity < 0)
+        return ABAC_ATTRIBUTE_INVALID_VALIDITY;
+    if (!abac_id_still_valid(issuer_id))
+        return ABAC_ATTRIBUTE_INVALID_ISSUER;
+
+    abac_attribute_t *attr = abac_xmalloc(sizeof(abac_attribute_t));
+    if(issuer_id) attr->issuer_id = abac_id_dup(issuer_id);
+        else attr->issuer_id = NULL;
+    attr->role = abac_xstrdup(role);
+    attr->validity = validity;
+
+    attr->head_string = NULL;
+    attr->tail_string = NULL;
+
+    // NULL until baked
+    attr->cert.ptr=NULL;
+    attr->cert.len=0;
+
+    *ret = attr;
+    return ABAC_SUCCESS;
+}
+
+/**
+ * Get the validity period.(xml module returns the diff from expire time - now()
+ */
+int abac_attribute_validity(abac_attribute_t *attr,struct tm *not_before,struct tm *not_after) {
+    assert(attr);
+    memset(not_before, 0, sizeof(struct tm));
+    memset(not_after, 0, sizeof(struct tm));
+
+    time_t now;
+    time(&now);
+    gmtime_r(&now, not_before);
+    char *xml=attr->cert.ptr;
+    long validity=get_validity_from_xml(xml);
+
+    time_t etime = now + validity;
+    gmtime_r(&etime, not_after);
+
+    fprintf(stderr,"validity from the xml blob is %ld\n",validity);
+    if(validity == 0)
+        return ABAC_FAILURE;
+    return ABAC_SUCCESS;
+}
+
+int abac_attribute_still_valid(abac_attribute_t *attr)
+{
+    assert(attr);
+    assert(attr->cert.ptr);
+    long v=get_validity_from_xml(attr->cert.ptr);
+    if (v > 0.0)
+        return 1;
+    else return 0;
+}
+
+void abac_attribute_set_head(abac_attribute_t *attr, char *string)
+{
+    assert(attr);
+    attr->head_string=string;
+}
+
+char *abac_attribute_get_head(abac_attribute_t *attr)
+{
+    assert(attr);
+    return attr->head_string;
+}
+
+void abac_attribute_set_tail(abac_attribute_t *attr, char *string)
+{
+    assert(attr);
+    attr->tail_string=string;
+}
+
+char *abac_attribute_get_tail(abac_attribute_t *attr)
+{
+    assert(attr);
+    return attr->tail_string;
+}
+
+/* A.b->C, return copy of a A */
+char *abac_attribute_get_principal(abac_attribute_t *attr)
+{
+    char *role_string=abac_attribute_role_string(attr);
+    /* make an copy */
+    char *tmp=strdup(role_string);
+    char *head_tail[2];
+    int ret;
+    abac_split(tmp, "<-", head_tail, &ret);
+    if (ret != 2) goto err;
+    abac_split(head_tail[0], ".", head_tail, &ret);
+    if (ret != 2) goto err;
+    char *prin=strdup(head_tail[0]);
+    free(tmp);
+    return prin;
+
+err:     
+     free(tmp);
+     return NULL;
+}
+
+int abac_attribute_principal(abac_attribute_t *attr, char *keyid) {
+    char *copy = _validate_principal(keyid);
+    if (copy == NULL)
+        return 0;
+
+    abac_attribute_set_tail(attr,copy);
+    return 1;
+}
+
+int abac_attribute_role(abac_attribute_t *attr, char *keyid, char *role) {
+    if (!abac_clean_name(role))
+        return 0;
+
+    char *copy = _validate_principal(keyid);
+    if (copy == NULL)
+        return 0;
+
+    int len = strlen(copy) + strlen(role) + strlen(ROLE_SEPARATOR) + 1;
+    copy = abac_xrealloc(copy, len);
+    strcat(copy, ".");
+    strcat(copy, role);
+
+    abac_attribute_set_tail(attr,copy);
+    return 1;
+}
+
+int abac_attribute_linking_role(abac_attribute_t *attr, char *keyid, char *role, char *linked) {
+    if (!abac_clean_name(role) || !abac_clean_name(linked))
+        return 0;
+
+    char *copy = _validate_principal(keyid);
+    if (copy == NULL)
+        return 0;
+
+    int len = strlen(copy) + strlen(role) + strlen(linked) + strlen(ROLE_SEPARATOR) + 2;
+    copy = abac_xrealloc(copy, len);
+    strcat(copy, ".");
+    strcat(copy, role);
+    strcat(copy, ".");
+    strcat(copy, linked);
+
+    abac_attribute_set_tail(attr,copy);
+    return 1;
+}
+
+
+
+// 0 for fail to bake, 1 is baked okay
+int abac_attribute_bake(abac_attribute_t *attr) {
+    assert(attr);
+    assert(attr->head_string);
+    assert(attr->tail_string);
+
+    abac_chunk_t id_chunk = { NULL, 0 };
+    int ret=abac_id_PEM(attr->issuer_id, &id_chunk);
+    if(ret != ABAC_CERT_SUCCESS)
+        return 0; 
+
+    char *role_string = abac_attribute_role_string(attr);
+
+/* Make an new GENI abac credential with the rt0 rule that expires secs from
+ * now.  cert is the PEM encoded X.509 of the issuer's certificate as a string.
+ * certlen is the length of cert.  Returns the XML. Caller is responsible for
+ * freeing it. */
+    char *attr_cert=my_make_credential(role_string, attr->validity, id_chunk.ptr, id_chunk.len);
+
+    if (attr_cert == NULL)
+        return 0;
+
+    attr->cert.ptr = (unsigned char *)attr_cert;
+    attr->cert.len = strlen(attr_cert);
+
+    free(role_string);
+    return 1;
+}
+
+// make an explicit copy
+int abac_attribute_cert_chunk(abac_attribute_t *attr, abac_chunk_t *chunk) {
+
+    chunk->ptr=NULL;
+    chunk->len=0;
+
+    if (attr->cert.ptr == NULL)
+        return 0;
+
+    /* return the xml chunk */
+    chunk->ptr= (unsigned char *)abac_xstrdup((char *)attr->cert.ptr);
+    chunk->len=attr->cert.len;
+    return chunk->len;
+}
+
+int abac_attribute_baked(abac_attribute_t *attr) {
+    return (attr->cert.ptr != NULL);
+}
+
+
+static abac_attribute_t *_load_attr(char *role_string, char *xml)
+{
+
+if(debug) fprintf(stderr,"loading -> %s \n", role_string);
+
+    char *head_tail[2];
+    int ret;
+    abac_split(role_string, "<-", head_tail, &ret);
+    if (ret != 2) return NULL; 
+
+    char *keyid=get_keyid_from_xml(xml);
+    abac_id_t *issuer_id=abac_verifier_lookup_id(keyid);
+
+    long validity=get_validity_from_xml(xml);
+    
+    abac_attribute_t *attr = abac_xmalloc(sizeof(abac_attribute_t));
+    if(issuer_id)
+        attr->issuer_id = abac_id_dup(issuer_id);
+        else attr->issuer_id=NULL;
+    attr->validity = validity;
+
+    attr->head_string = abac_xstrdup(head_tail[0]);
+    attr->tail_string = abac_xstrdup(head_tail[1]);
+    char *tmp=strstr(attr->head_string,".");
+    attr->role =abac_xstrdup(tmp+1);
+
+    attr->cert.ptr=(unsigned char *)xml;
+    attr->cert.len=strlen(xml);
+
+    return attr;
+}
+
+abac_list_t *abac_attribute_certs_from_file(char *filename)
+{
+    abac_list_t *alist=abac_list_new();
+    char *xml=NULL;
+    char *rt0=NULL;
+
+    char **rt0s=my_read_credential(filename, &xml);
+    if(xml == NULL) return alist;
+
+    int len=strlen(xml);
+    if(len==0) return alist;
+
+    abac_attribute_t *attr;
+
+    int i=0;
+    do {
+        rt0 = rt0s[i]; 
+        if(rt0 == NULL) break;
+        attr=_load_attr(rt0, xml);
+        if(attr)
+            abac_list_add(alist, attr);
+        free(rt0);
+        i++;
+    } while (rt0s[i] !=NULL);
+
+    free(rt0s);
+    free(xml);
+
+    return alist;
+}
+
+abac_list_t *abac_attribute_certs_from_chunk(abac_chunk_t chunk) {
+
+    abac_list_t *alist=abac_list_new();
+    char *xml=(char *)chunk.ptr;
+    char **rt0s=get_rt0_from_xml(xml);
+    char *rt0=NULL;
+    int len=strlen(xml);
+    if(len==0) return alist;
+
+    abac_attribute_t *attr;
+    int i=0;
+    do {
+        rt0 = rt0s[i]; 
+        if(rt0 == NULL) break;
+        attr=_load_attr(rt0, xml);
+        if(attr)
+            abac_list_add(alist, attr);
+        free(rt0);
+        i++;
+    } while (rt0s[i] !=NULL);
+
+    free(rt0s);
+    return alist;
+}
+
+// returns 0 if the cert hasn't been baked
+int abac_attribute_write(abac_attribute_t *attr, FILE *out) {
+    assert(attr != NULL);
+
+    if (attr->cert.ptr == NULL)
+        return 0;
+
+    // write to file
+    fwrite(attr->cert.ptr, attr->cert.len, 1, out);
+
+    return 1;
+}
+
+void abac_attribute_free(abac_attribute_t *attr) {
+
+if(debug) fprintf(stderr,"calling abac_attribute_free on %s\n", attr->head_string);
+
+    if (attr == NULL)
+        return;
+
+    if(attr->issuer_id) abac_id_free(attr->issuer_id);
+
+    free(attr->role);
+    free(attr->head_string);
+    free(attr->tail_string);
+
+/* XXX this can not be free as if it is a char string
+    free(attr->cert.ptr);
+*/
+
+    free(attr);
+}
+
+//
+// Helper functions below
+//
+
+// validate a princpal's name
+// makes sure it's a valid SHA1 identifier
+// return values:
+//  success: malloc'd copy with all hex digits lowercase
+//  fail: NULL
+static char *_validate_principal(char *keyid) {
+    int i;
+    char *copy = NULL;
+
+    if (strlen(keyid) != SHA1_LENGTH)
+        return NULL;
+
+    copy = abac_xstrdup(keyid);
+    for (i = 0; i < SHA1_LENGTH; ++i) {
+        copy[i] = tolower(copy[i]);
+        if (!isxdigit(copy[i]))
+            goto error;
+    }
+
+    return copy;
+
+error:
+    free(copy);
+    return NULL;
+}
+
+// combine up the attribute's rule string, explicit copy
+char *abac_attribute_role_string(abac_attribute_t *attr) {
+    assert(attr);
+
+    char *role_string=NULL;
+    asprintf(&role_string,"%s<-%s",attr->head_string,attr->tail_string);
+    return role_string;
+}
+
+
Index: libabac/abac_common.h
===================================================================
--- libabac/abac_common.h	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ 	(revision )
@@ -1,9 +1,0 @@
-#ifndef __ABAC_COMMON_H__
-#define __ABAC_COMMON_H__
-
-typedef struct _abac_chunk_t {
-    unsigned char *ptr;
-    int len;
-} abac_chunk_t;
-
-#endif
Index: libabac/abac_id.c
===================================================================
--- libabac/abac_id.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
+++ libabac/abac_id.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -0,0 +1,354 @@
+
+/* abac_id.c */
+
+// include the GNU extension of asprintf
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+
+#include <assert.h>
+#include <err.h>
+#include <time.h>
+
+#include "libabac_common.h"
+#include "abac_util.h"
+#include "abac_openssl.h"
+
+#define KEY_SUFFIX  "_private.pem"
+#define CERT_SUFFIX "_ID.pem"
+
+// ID object
+//
+struct _abac_id_t {
+    char *keyid;
+    char *cn;
+    X509 *cert;
+    EVP_PKEY *key;
+
+    int refcount;
+};
+
+/**************************************************************/
+/**
+ * Helper function for building a ID from a cert. Used by
+ * abac_id_from_*
+ */
+abac_id_t *_id_from_cert(X509 *cert) {
+    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
+    id->keyid = NULL;
+    id->cn = NULL;
+    id->cert = cert;
+    id->key = NULL;
+
+    id->keyid = abac_get_keyid(id->cert);
+    id->cn = abac_get_cn(cert);
+
+    id->refcount = 1;
+
+    return id;
+}
+
+/**
+ * Load an ID cert from a file.
+ */
+abac_id_t *abac_id_from_file(char *filename) {
+
+    FILE *fp=fopen(filename,"r");
+    if(fp==NULL)
+        return NULL;
+
+    X509 *cert = abac_load_id_from_fp(fp);
+    fclose(fp);
+
+    if (cert == NULL)
+        return NULL;
+
+    return _id_from_cert(cert);
+}
+
+/**
+ * Load an ID cert from a chunk.
+ */
+abac_id_t *abac_id_from_chunk(abac_chunk_t chunk) {
+
+    X509 *cert= abac_load_id_from_chunk(chunk.ptr, chunk.len);
+
+    if (cert == NULL)
+        return NULL;
+
+    return _id_from_cert(cert);
+}
+
+/**
+ * Load private key for a cert.
+ */
+int abac_id_privkey_from_file(abac_id_t *id, char *filename) {
+    assert(id != NULL);
+
+    FILE *fp=fopen(filename,"r");
+    if(fp==NULL) return ABAC_FAILURE;
+
+    EVP_PKEY *key=abac_load_privkey_from_fp(fp);
+    fclose(fp);
+
+    if (key == NULL) return ABAC_FAILURE;
+
+/* needs to make sure that the key matches up with the id */
+    /* extract the pub key from the id */
+    EVP_PKEY *pubkey=extract_pubkey_from_cert(id->cert);
+    /* cmp will just compare the pub key part of the key to see
+       if they are the same */
+    if(!EVP_PKEY_cmp(pubkey, key)) {
+        fprintf(stderr,"wrong private key for the cert!!\n");
+        return ABAC_FAILURE;
+    }
+
+    id->key = key;
+    return ABAC_SUCCESS;
+}
+
+/**
+ * Generate an ID with the specified CN and validity.
+ *
+ * validity is measured in seconds (as of 0.2.0)
+ */
+int abac_id_generate(abac_id_t **ret, char *cn, long validity) {
+    if (cn == NULL || !abac_clean_name(cn))
+        return ABAC_GENERATE_INVALID_CN;
+
+    if (validity < 0)
+        return ABAC_GENERATE_INVALID_VALIDITY;
+
+    abac_id_t *id = abac_xmalloc(sizeof(abac_id_t));
+
+    id->cn = abac_xstrdup(cn);
+    id->key = abac_generate_key();
+    id->cert = abac_generate_cert(id->key, cn, validity);
+    id->keyid = abac_get_keyid(id->cert);
+
+    id->refcount = 1;
+
+    *ret = id;
+    return ABAC_SUCCESS;
+}
+
+char *abac_id_keyid(abac_id_t *id) {
+    if(id) return id->keyid;
+        return NULL;
+}
+
+/**
+ * Get the issuer of an ID cert.
+ * Returns a malloc'd string that must be free'd.
+ */
+char *abac_id_issuer(abac_id_t *id) {
+    if(id) return abac_get_issuer(id->cert);
+        else return NULL;
+}
+
+/**
+ * Gets the subject DN of an ID cert.
+ * Returns a malloc'd string that must be free'd.
+ */
+char *abac_id_subject(abac_id_t *id) {
+    if(id) return abac_get_subject(id->cert);
+        else return NULL;
+}
+
+/**
+ * Get the validity period.
+ */
+int abac_id_validity(abac_id_t *id,struct tm *not_before,struct tm *not_after) {
+    assert(id);
+    if(abac_check_validity(id->cert, not_before, not_after)==0)
+        return ABAC_SUCCESS;
+    return ABAC_FAILURE;
+}
+
+X509 *abac_id_cert(abac_id_t *id) {
+    assert(id);
+    return id->cert;
+}
+
+// get the private key from the ID
+// will return NULL if no key has been loaded
+EVP_PKEY *abac_id_privkey(abac_id_t *id) {
+    assert(id);
+    return id->key;
+}
+
+int abac_id_has_privkey(abac_id_t *id) {
+    if(id && (id->key !=NULL))
+        return 1;
+    return 0;
+}
+
+// see if keyid is the same as id's
+int abac_id_has_keyid(abac_id_t *id, char *keyid)
+{
+    assert(id); assert(keyid);
+    if(strcmp(id->keyid, keyid) == 0)
+        return 1;
+    return 0;
+}
+
+/*
+   return a chunk with both id and key info,
+   err if missing privkey
+*/
+int abac_id_PEM(abac_id_t *id, abac_chunk_t *chunk) {
+    if(id==NULL)
+        return ABAC_CERT_MISSING_ISSUER;
+    if(id->key == NULL)
+        return ABAC_CERT_SIGNER_NOKEY;
+
+    unsigned char *kptr=NULL;
+    unsigned char *ptr=abac_string_cert(id->cert);
+    if(id->key)
+        kptr=abac_string_privkey(id->key);
+    int len=0;
+    
+    char *tmp=NULL;
+    if(kptr)  {
+        asprintf(&tmp,"%s%s", ptr,kptr);
+        free(ptr);
+        free(kptr);
+        } else {
+            tmp=ptr;
+    }
+    len=strlen(tmp);
+
+    chunk->ptr=tmp;
+    chunk->len=len;
+    return ABAC_CERT_SUCCESS;
+}
+
+abac_chunk_t abac_id_in_PEM(abac_id_t *id) {
+    assert(id);
+    unsigned char *ptr=abac_string_cert(id->cert);
+    int len=0;
+    if(ptr)
+        len=strlen((char *)ptr);
+    abac_chunk_t ret = {ptr, len };
+    return ret;
+}
+
+
+int abac_id_still_valid(abac_id_t *id) {
+    assert(id);
+    return abac_still_valid(id->cert);
+}
+
+/**
+ * Get the default filename for the cert. Value must be freed by caller.
+ */
+char *abac_id_cert_filename(abac_id_t *id) {
+    assert(id != NULL);
+    assert(id->cn != NULL);
+
+    // malloc the filename
+    int len = strlen(id->cn) + strlen(CERT_SUFFIX) + 1;
+    char *filename = abac_xmalloc(len);
+    sprintf(filename, "%s" CERT_SUFFIX, id->cn);
+
+    return filename;
+}
+
+/**
+ * Write the ID cert to an open file pointer.
+ * pem format
+ */
+int abac_id_write_cert(abac_id_t *id, FILE *out) {
+    assert(id != NULL);
+
+    int ret=abac_write_id_to_fp(id->cert, out);
+    if(ret) return ABAC_FAILURE; 
+    return ABAC_SUCCESS;
+}
+
+/**
+ * Default private key filename. Value must be freed by caller.
+ */
+char *abac_id_privkey_filename(abac_id_t *id) {
+    assert(id != NULL);
+    assert(id->cn != NULL);
+
+    // malloc the filename
+    int len = strlen(id->cn) + strlen(KEY_SUFFIX) + 1;
+    char *filename = abac_xmalloc(len);
+    sprintf(filename, "%s" KEY_SUFFIX, id->cn);
+
+    return filename;
+}
+
+/**
+ * Write the private key to a file.
+ * Returns false if there's no private key loaded
+ * PEM format
+ */
+int abac_id_write_privkey(abac_id_t *id, FILE *out) {
+    assert(id != NULL);
+    if (id->key == NULL)
+        return ABAC_FAILURE;
+
+    int ret=abac_write_privkey_to_fp(id->key, out);
+    if (ret)
+        return ABAC_FAILURE;
+
+    return ABAC_SUCCESS;
+}
+
+/**
+ * Get a abac_chunk representing the id cert.
+ */
+abac_chunk_t abac_id_cert_chunk(abac_id_t *id) {
+
+    assert(id); assert(id->cert);
+    unsigned char *ptr=abac_string_cert(id->cert);
+    int len=0;
+    if(ptr) len=strlen( (char *)ptr);
+
+    abac_chunk_t ret = { ptr, len };
+    return ret;
+}
+
+/**
+ * Get a abac_chunk representing the privkey cert.
+ */
+abac_chunk_t abac_id_privkey_chunk(abac_id_t *id) {
+
+    assert(id); assert(id->key);
+    unsigned char *ptr=abac_string_privkey(id->key);
+    int len=0;
+    if(ptr) len=strlen( (char *)ptr);
+
+    abac_chunk_t ret = { ptr, len };
+    return ret;
+}
+
+
+/**
+ * Copy a ID. Actually just increases its reference count.
+ */
+abac_id_t *abac_id_dup(abac_id_t *id) {
+    assert(id);
+    ++id->refcount;
+    return id;
+}
+
+void abac_id_free(abac_id_t *id) {
+    if (id == NULL)
+        return;
+
+    --id->refcount;
+    if (id->refcount > 0)
+        return;
+
+    // free once the reference count reaches 0
+    X509_free(id->cert);
+    EVP_PKEY_free(id->key);
+
+    free(id->keyid);
+    free(id);
+}
+
Index: libabac/abac_openssl.c
===================================================================
--- libabac/abac_openssl.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
+++ libabac/abac_openssl.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -0,0 +1,719 @@
+
+/* abac_openssl.c */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <time.h>
+
+#include <stdbool.h>
+
+#include <openssl/conf.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+
+
+#ifdef HAVE_READPASSPHRASE
+# include <readpassphrase.h>
+#else
+# include "compat/readpassphrase.h"
+#endif
+
+#define SHA1_LENGTH 40
+
+static int debug=0;
+
+int _potato_cb(char *buf, int sz, int rwflag, void *u);
+
+/***********************************************************************/
+int init_openssl() {
+    ERR_load_crypto_strings();
+    OpenSSL_add_all_algorithms();
+    return 0;
+}
+
+int deinit_openssl() {
+    CRYPTO_cleanup_all_ex_data();
+    return 0;
+}
+
+/* int RAND_bytes(unsigned char *buf, int num); */
+unsigned char *abac_generate_serial() {
+    unsigned char *serial=(unsigned char *) malloc(sizeof(unsigned char)*8);
+
+    memset(serial, '\0', 8);
+
+    if(!RAND_bytes(serial,8)) {
+        fprintf(stderr,"RAT, RAN^D out of seeds!!!\n");
+        assert(0);
+    }
+    // zap leading 0's
+    while (serial[0] == 0)
+        RAND_bytes(&serial[0],1);
+
+    RAND_cleanup();
+    return serial;
+}
+
+
+static BIGNUM *_make_bn_from_string(unsigned char *str)
+{
+    assert(str);
+    BIGNUM *tmp;
+    tmp=BN_bin2bn(str,8,NULL);
+/* BN_print_fp(stderr,tmp); */
+    int n=BN_num_bytes(tmp);
+    if(n) return tmp;
+        return NULL;
+}
+
+unsigned char *_encode_m64(unsigned char *orig_ptr, int orig_len)
+{
+    BIO *mbio,*b64bio,*bio;
+
+    unsigned char *m64_ptr=NULL;
+    int m64_len=0;
+
+    unsigned char *ptr=NULL;
+
+    if(orig_len==0) return NULL;
+
+    /*bio pointing at b64->mem, the base64 bio encodes on
+      write and decodes on read */
+    mbio=BIO_new(BIO_s_mem());
+    b64bio=BIO_new(BIO_f_base64());
+    bio=BIO_push(b64bio,mbio);
+
+    BIO_write(bio,orig_ptr,orig_len);
+
+    /* We need to 'flush' things to push out the encoding of the
+    * last few bytes.  There is special encoding if it is not a
+    * multiple of 3
+    */
+    BIO_flush(bio);
+
+    /* pointer to the data and the number of elements. */
+    m64_len=(int)BIO_ctrl(mbio,BIO_CTRL_INFO,0,ptr);
+
+    if(m64_len!=0) {
+       m64_ptr=malloc(m64_len+1);
+       if(m64_ptr) {
+           strcpy((char *)m64_ptr, (char *)ptr);
+           } else { 
+               fprintf(stderr,"ERROR: malloc failed\n");
+       }
+    }
+
+    /* This call will walk the chain freeing all the BIOs */
+    BIO_free_all(bio);
+    return m64_ptr;
+}
+
+unsigned char *_decode_m64(unsigned char *m64_ptr, int m64_len)
+{
+    unsigned char *orig_ptr=NULL;
+    int orig_len=0;
+
+    BIO *b64bio, *mbio, *bio;
+    char *ptr=NULL;
+
+    if(m64_len==0) return NULL;
+
+    ptr = (char *)malloc(sizeof(char)*m64_len);
+    memset(ptr, '\0', m64_len);
+
+    b64bio = BIO_new(BIO_f_base64());
+    mbio = BIO_new_mem_buf(m64_ptr, m64_len);
+    bio = BIO_push(b64bio, mbio);
+
+    orig_len=BIO_read(bio, ptr, m64_len);
+    
+    if(orig_len) {
+        orig_ptr=malloc(orig_len+1);
+        if(orig_ptr)
+            strcpy((char *)orig_ptr, ptr);
+            else fprintf(stderr,"ERROR: malloc failed..\n");
+    }
+
+    BIO_free_all(bio);
+    return orig_ptr;
+}
+
+static char *_read_blob_from_file(char *fname, int *len)
+{
+    struct stat sb;
+    char *dptr=NULL;
+
+    int fd = open(fname, O_RDONLY);
+    if (fd == -1) { return NULL; }
+    if(stat(fname, &sb) == -1) {
+        close(fd);
+        return NULL;
+    }
+    dptr= (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    close(fd);
+
+    if(dptr == MAP_FAILED) {
+        return NULL;
+    }
+    *len=sb.st_size;
+    return dptr;
+}
+
+/* Read ID in PEM */
+X509 *abac_load_id_from_fp(FILE *fp)
+{
+    X509 *cert=PEM_read_X509(fp,NULL,NULL,NULL);
+
+    if (cert == NULL) {
+        ERR_print_errors_fp (stderr);
+        return NULL;
+    }
+    return cert;
+}
+
+X509 *abac_load_id_from_chunk(unsigned char *chunk_ptr, int chunk_len)
+{
+    X509 *n509=NULL;
+    BIO *mbio=BIO_new(BIO_s_mem());
+
+    BIO_write(mbio,chunk_ptr,chunk_len);
+    BIO_flush(mbio);
+
+    PEM_read_bio_X509(mbio,&n509,NULL,NULL);
+
+    BIO_free_all(mbio);
+
+    if (n509 == NULL) {
+        ERR_print_errors_fp (stderr);
+        return NULL;
+    }
+    return n509;
+}
+
+int abac_write_id_to_fp(X509 *cert, FILE *fp)
+{
+    assert(cert);
+
+    int ret=PEM_write_X509(fp,cert);
+
+    if (ret) {
+        ERR_print_errors_fp (stderr);
+        return ret;
+    }
+    return 0;
+}
+
+/* make stringfy a private key PEM struct */
+unsigned char *abac_string_privkey(EVP_PKEY *key)
+{
+    unsigned char *ptr=NULL;
+    unsigned char *tmp=NULL;
+
+    assert(key);
+
+    BIO *mbio=BIO_new(BIO_s_mem());
+    /* PEM_write_PrivateKey(fp,key,NULL,NULL,0,_potato_cb, "privateKey to file"); */
+    PEM_write_bio_PrivateKey(mbio,key,NULL,NULL,0,_potato_cb,"stringify privateKey");
+    BIO_flush(mbio);
+    int len=(int)BIO_ctrl(mbio,BIO_CTRL_INFO,0,tmp);
+
+    if(debug) fprintf(stderr,"CHUNKING PrivateKey... %d\n",len);
+
+    if(len) {
+        ptr=(unsigned char *)malloc(sizeof(unsigned char *)*(len+1));
+        int ret=BIO_read(mbio, (void *)ptr, len);
+        if(ret==0)
+            fprintf(stderr," abac_string_privkey failed!!\n");
+        ptr[len]='\0';
+    }
+    BIO_free_all(mbio);
+    return ptr;
+}
+
+/* make stringfy a x509 PEM struct */
+unsigned char *abac_string_cert(X509 *cert) {
+    unsigned char *ptr=NULL;
+    unsigned char *tmp=NULL;
+
+    assert(cert);
+
+    BIO *mbio=BIO_new(BIO_s_mem());
+    PEM_write_bio_X509(mbio,cert);
+    BIO_flush(mbio);
+    int len=(int)BIO_ctrl(mbio,BIO_CTRL_INFO,0,tmp);
+    if(debug) fprintf(stderr,"CHUNKING X509... %d\n",len);
+
+    if(len) {
+        ptr=(unsigned char *)malloc(sizeof(unsigned char *)*(len+1));
+        int ret=BIO_read(mbio, (void *)ptr, len);
+        if(ret==0)
+            fprintf(stderr," abac_string_cert failed!!\n");
+        ptr[len]='\0';
+    }
+    
+    BIO_free_all(mbio);
+    return ptr;
+}
+
+
+/* sign data with privkey */ 
+static int _sign_with_privkey(EVP_PKEY *privkey, char *data,
+unsigned char* signed_buf)
+{
+  int err;
+  unsigned int signed_len;
+  EVP_MD_CTX     md_ctx;
+
+  EVP_SignInit   (&md_ctx, EVP_md5());
+  EVP_SignUpdate (&md_ctx, data, strlen(data));
+  signed_len = sizeof(signed_buf);
+  err = EVP_SignFinal (&md_ctx,
+                       signed_buf,
+                       &signed_len,
+                       privkey);
+  if (err != 1) {
+      ERR_print_errors_fp (stderr);
+      return 1;
+  }
+  return 0;
+}
+
+/* verify the signature.. */
+static int _verify_with_pubkey(EVP_PKEY *pubkey, char *data,
+unsigned char* signed_buf )
+{
+  int err;
+  int signed_len;
+  EVP_MD_CTX     md_ctx;
+
+  EVP_VerifyInit   (&md_ctx, EVP_sha1());
+  EVP_VerifyUpdate (&md_ctx, data, strlen((char*)data));
+  signed_len=sizeof(signed_buf);
+  err = EVP_VerifyFinal (&md_ctx,
+                         signed_buf,
+                         signed_len,
+                         pubkey);
+
+  if (err != 1) {
+        ERR_print_errors_fp (stderr);
+        return 1;
+  }
+  fprintf(stderr, "Signature Verified Ok.\n");
+  return 0;
+}
+
+
+#define PWLEN 128
+/* EVP_PKEY *PEM_read_PrivateKey(FILE *,EVP_PKEY **,pem_cb *,void *) */
+int _potato_cb(char *buf, int sz, int rwflag, void *u)
+{
+   int len;
+   char *prompt=NULL;
+   if(u)
+       asprintf(&prompt,"Enter passphrase for %s:", (char *)u);
+       else asprintf(&prompt,"Enter passphrase :");
+   char *secret = malloc(PWLEN);
+   memset(secret, '\0', PWLEN);
+   if(!secret) {
+        perror("malloc()");
+        free(prompt);
+        return 0;
+   }
+   if (readpassphrase( prompt, secret, PWLEN, RPP_ECHO_OFF) == NULL) {
+       perror("readpassphrase()");
+       memset(secret, '\0', PWLEN);
+       len=0;
+       } else {
+           len=strlen(secret);
+           memcpy(buf, secret, len);
+           memset(secret, '\0', len);
+   }
+   free(secret);
+   free(prompt);
+   return len;
+}
+
+EVP_PKEY *abac_load_privkey_from_fp(FILE *fp)
+{
+    assert(fp);
+
+    EVP_PKEY *privkey = PEM_read_PrivateKey(fp, NULL, _potato_cb, "privateKey from file");
+
+    if (privkey == NULL) {
+        ERR_print_errors_fp (stderr);
+        return NULL;
+    }
+    return privkey;
+}
+
+/* not adding passphrase */
+int abac_write_privkey_to_fp(EVP_PKEY *key, FILE *fp) {
+    assert(key);
+
+    int ret=PEM_write_PrivateKey(fp,key,NULL,NULL,0,NULL, NULL);
+    if(ret) return ret;
+    return 0;
+}
+
+/* adding passphrase */
+int abac_write_encrypt_privkey_to_fp(EVP_PKEY *key, FILE *fp) {
+    assert(key);
+
+    int ret=PEM_write_PrivateKey(fp,key,NULL,NULL,0,_potato_cb, "privateKey to file");
+    if(ret) return ret;
+    return 0;
+}
+
+EVP_PKEY *extract_pubkey_from_cert(X509 *cert)
+{
+    EVP_PKEY *pubkey=X509_get_pubkey(cert);
+    return pubkey;
+}
+
+
+static void _callback(int p, int n, void *arg)
+{
+    char c='B';
+
+    if (p == 0) c='.';
+    if (p == 1) c='+';
+    if (p == 2) c='*';
+    if (p == 3) c='\n';
+    fputc(c,stderr);
+}
+
+/* 
+RSA *RSA_generate_key(int num, unsigned long e,
+   void (*callback)(int,int,void *), void *cb_arg);
+The exponent is an odd number, typically 3, 17 or 65537
+*/
+EVP_PKEY* abac_generate_key()
+{
+    EVP_PKEY *pk=NULL;
+    int keysize=2048;
+
+    if((pk=EVP_PKEY_new()) == NULL){
+        ERR_print_errors_fp (stderr);
+        return NULL;
+    }
+
+//    RSA *rsa=RSA_generate_key(keysize,RSA_F4,_callback,NULL); 
+    RSA *rsa=RSA_generate_key(keysize,RSA_F4,NULL,NULL); 
+    if (!EVP_PKEY_assign_RSA(pk,rsa)) {
+        ERR_print_errors_fp (stderr);
+        return NULL;
+    }
+    rsa=NULL;
+
+    return pk;
+}
+
+/* Add extension using V3 code: we can set the config file as NULL
+ * because we wont reference any other sections.
+ */
+static int _add_ext(X509 *cert, int nid, char *value)
+{
+    X509_EXTENSION *ex;
+    X509V3_CTX ctx;
+    /* This sets the 'context' of the extensions. */
+    /* No configuration database */
+    X509V3_set_ctx_nodb(&ctx);
+    /* Issuer and subject certs: both the target since it is self signed,
+     * no request and no CRL
+     */
+    X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
+    ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
+    if (!ex)
+        return 0;
+
+    X509_add_ext(cert,ex,-1);
+    X509_EXTENSION_free(ex);
+    return 1;
+}
+
+
+/**
+ * Generate ID certificate.
+ *
+ * validity is measured in seconds (as of 0.2.0)
+ */
+X509 *abac_generate_cert(EVP_PKEY *pkey, char *cn, long validity) {
+
+    /* must have a privkey before generating an ID cert?? */
+    assert(pkey);
+    X509 *cert=NULL;
+
+    if((cert=X509_new()) == NULL)
+            goto error;
+
+    unsigned char *serial=abac_generate_serial();
+
+    if(validity == 0) validity=(long)(60*60*24*(365));
+
+    X509_set_version(cert,2);
+
+    BIGNUM *bn=_make_bn_from_string(serial);
+    BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(cert));
+    /* this is prone to problem with very big days on 32 bit machines,
+       In newer openssl, can migrate to X509_time_adj_ex */ 
+    X509_gmtime_adj(X509_get_notBefore(cert),0);
+    X509_gmtime_adj(X509_get_notAfter(cert),validity);
+    X509_set_pubkey(cert,pkey);
+
+    X509_NAME *name=X509_get_subject_name(cert);
+
+    if(!name) goto error;
+
+    /* This function creates and adds the entry, working out the
+     * correct string type and performing checks on its length.
+     */
+    if(!(X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_ASC, (unsigned char *)cn, -1, -1, 0)))
+        goto error; // fail to add cn to cert 
+
+    /* Self signed, set the issuer name to be the same as the subject. */
+    if(!(X509_set_issuer_name(cert,name)))
+        goto error; // fail to set issuer name on cert 
+
+    /* Add various extensions: standard extensions */
+    if(!(_add_ext(cert, NID_basic_constraints, "critical,CA:TRUE")))
+        goto error; // fail to set basic constraint
+    if(!(_add_ext(cert, NID_key_usage, "critical,keyCertSign,cRLSign")))
+        goto error; // fail to set key usage
+    if(!(_add_ext(cert, NID_subject_key_identifier, "hash")))
+        goto error; // fail to set subject key identifier
+    if(!(_add_ext(cert, NID_authority_key_identifier, "keyid:always")))
+        goto error; // fail to set authority key identifier (self-signing)
+
+    /* make sure it is signed */
+    if (!X509_sign(cert,pkey,EVP_sha1()))
+        goto error;
+
+    return cert;
+
+error:
+    if(cert) X509_free(cert);
+    if(serial) free(serial);
+    if(bn) BN_free(bn);
+    return NULL;
+}
+
+static char *_time_in_string(ASN1_TIME *tm)
+{
+    char *ptr=NULL;
+    BIO *mbio=BIO_new(BIO_s_mem());
+    ASN1_TIME_print(mbio, tm);
+    BIO_flush(mbio);
+    int len=BIO_number_written(mbio);
+    ptr=(char *) malloc(sizeof(char *)*(len+1));
+    int ret=BIO_read(mbio, (void *)ptr, len);
+
+    BIO_free_all(mbio);
+    if(ret)
+        return ptr; 
+        else return NULL;
+} 
+
+
+/* atime->data, YYmmddHHMMSS or YYYYmmddHHMMSSZZ 
+ *  V_ASN1_UTCTIME, V_ASN1_GENERALIZEDTIME 
+ */
+static int _convert_time(struct tm *ttime, ASN1_TIME *atime) {
+    assert(atime); assert(atime->data);
+
+    int type=atime->type;
+    int len=strlen((char *)atime->data);
+    if(len==0) return 0;
+
+    char *astring=strndup((char *)atime->data,len);
+
+    /* setting ttime structure */
+    if (type == V_ASN1_UTCTIME) {
+           strptime(astring, "%y%m%d%H%M%S", ttime);
+        } else {
+        if (type == V_ASN1_GENERALIZEDTIME)
+           strptime(astring, "%Y%m%d%H%M%S", ttime);
+           else fprintf(stderr,"ERROR,.. unknown type in ASN1_TIME struct\n");
+    }
+
+    if(debug) {
+        char *tstring=asctime(ttime);
+        fprintf(stderr,"PPP final time string is %s\n",tstring);
+    }
+    return 1;
+}
+
+/* check whether the cert is still valid or not and also extract what its 
+   not_before and not_after field */
+int abac_check_validity(X509 *cert, struct tm *not_before, struct tm *not_after) {
+    assert(cert);
+
+    int valid=0;
+    int ret=0;
+    memset(not_before, 0, sizeof(struct tm));
+    memset(not_after, 0, sizeof(struct tm));
+    ASN1_TIME *notAfter= X509_get_notAfter(cert);
+    ASN1_TIME *notBefore=X509_get_notBefore(cert);
+
+    ret=_convert_time(not_before, notBefore);
+    if(ret==0) return 0;
+    ret=_convert_time(not_after, notAfter);
+    if(ret==0) return 0;
+
+    if((X509_cmp_current_time(notBefore) >=0) ||
+                  (X509_cmp_current_time(notAfter) <=0) )
+      valid=1;
+
+    if(valid) return 0;
+       else return 1;
+}
+
+/* check if cert is still valid at current time, 1 for yes, 0 for no*/
+int abac_still_valid(X509 *cert)
+{
+    ASN1_TIME *notAfter= X509_get_notAfter(cert);
+    ASN1_TIME *notBefore=X509_get_notBefore(cert);
+    if(0) {
+        fprintf(stderr,"((X509_cmp_current_time(notBefore) is %d\n", 
+                                  X509_cmp_current_time(notBefore));
+        fprintf(stderr,"((X509_cmp_current_time(notAfter) is %d\n", 
+                                  X509_cmp_current_time(notAfter));
+    }
+    if((X509_cmp_current_time(notBefore) >=0) ||
+                   (X509_cmp_current_time(notAfter) <=0) )
+      return 0;
+    return 1;
+}
+
+int abac_self_signed(X509 *cert)
+{
+    int selfsigned=0;
+    X509_STORE *store=X509_STORE_new();
+    X509_STORE_CTX *ctx=X509_STORE_CTX_new();
+    /* Check selfsigned CA signature */
+    X509_STORE_set_flags(store,X509_V_FLAG_CHECK_SS_SIGNATURE);
+    X509_STORE_CTX_init(ctx,store,cert,NULL);
+    int ret=X509_verify_cert(ctx);
+    if(ret!=1) { /* 1 is okay, 0 or negative value are failures */
+        if(debug) fprintf(stderr,"error %d at %d depth lookup:%s\n",
+                ctx->error, ctx->error_depth, X509_verify_cert_error_string(ctx->error));
+        } else {
+            selfsigned=1;
+    }
+
+    X509_STORE_CTX_free(ctx);
+    X509_STORE_free(store);
+    return selfsigned;
+}
+
+int abac_signed_by(X509 *cert, X509 *root)
+{
+    int signedby=0;
+    X509_STORE *store=X509_STORE_new();
+    X509_STORE_add_cert(store,root);
+    X509_STORE_CTX *ctx=X509_STORE_CTX_new();
+    X509_STORE_CTX_init(ctx,store,cert,NULL);
+    int ret=X509_verify_cert(ctx);
+    if(ret!=1) { /* 1 is okay, 0 or negative value are failures */
+        if(debug) fprintf(stderr,"error %d at %d depth lookup:%s\n",
+                ctx->error, ctx->error_depth, X509_verify_cert_error_string(ctx->error));
+        } else {
+            signedby=1;
+    }
+
+    X509_STORE_CTX_free(ctx);
+    X509_STORE_free(store);
+    return signedby;
+}
+
+
+
+char *abac_get_cn(X509 *cert)
+{
+   X509_NAME *nptr=X509_get_subject_name (cert);
+   int pos=X509_NAME_get_index_by_NID(nptr, NID_commonName,-1);
+   X509_NAME_ENTRY *ent=X509_NAME_get_entry(nptr,pos); 
+   ASN1_STRING *adata=X509_NAME_ENTRY_get_data(ent);
+   unsigned char *val=ASN1_STRING_data(adata);
+   if(debug) fprintf(stderr," cn:(%d)(%s)\n", strlen((char *)val), val);
+   return (char *) val;
+}
+
+char *abac_get_serial(X509 *cert)
+{
+   char *ret=NULL;
+   ASN1_INTEGER *num=X509_get_serialNumber(cert);
+   BIGNUM *bnser=ASN1_INTEGER_to_BN(num,NULL);
+   int n=BN_num_bytes(bnser);
+   unsigned char buf[n];
+   int b=BN_bn2bin(bnser,buf);
+   if(debug) { 
+       fprintf(stderr," extract serial number:->(%d)",b);
+       BN_print_fp(stderr,bnser);
+   } 
+   if(n)
+       ret=strndup((char *)buf,n);
+   return ret;
+}
+
+char *abac_get_subject(X509 *cert) 
+{
+   char *ptr=X509_NAME_oneline(X509_get_subject_name(cert),0,0);
+   return ptr;
+}
+
+char *abac_get_issuer(X509 *cert) 
+{   
+   char *ptr=X509_NAME_oneline(X509_get_issuer_name(cert),0,0);
+   return ptr;
+}
+
+//  success: malloc'd copy with all hex digits lowercase
+//  fail: NULL
+unsigned char *abac_get_keyid(X509 *cert)
+{
+    ASN1_OCTET_STRING *ptr=X509_get_ext_d2i(cert,NID_subject_key_identifier,NULL,NULL);
+    char *str=i2s_ASN1_OCTET_STRING(NULL, ptr);
+    unsigned char *sha=(unsigned char *) malloc(sizeof(unsigned char)*SHA1_LENGTH+1);
+    memset(sha, '\0', SHA1_LENGTH);
+
+    int len=strlen(str);
+    int i=0;
+    int j=0;
+    for (j = 0; j < len; j++) {
+        if(str[j]==':')
+            continue;
+        sha[i] = tolower(str[j]);
+        if (!isxdigit(sha[i]))
+            goto error;
+        i++;
+        if(i>SHA1_LENGTH) 
+            goto error;
+    }
+    free(str);
+    sha[i]='\0';
+    
+    return sha;
+
+error:
+    free(str);
+    if(debug) fprintf(stderr,"SHA1 -> %s\n",sha);
+    free(sha);
+    return NULL;
+}
Index: libabac/abac_openssl.h
===================================================================
--- libabac/abac_openssl.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
+++ libabac/abac_openssl.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -0,0 +1,46 @@
+/* abac_openssl.h */
+
+#ifndef __ABAC_OPENSSL_H__
+#define __ABAC_OPENSSL_H__
+
+#include <stdio.h>
+#include <openssl/x509.h>
+#include <openssl/err.h>
+
+/* ID */
+EVP_PKEY* abac_generate_key();
+X509 *abac_generate_cert(EVP_PKEY *, char*, long);
+
+// 8 bytes
+unsigned char *abac_generate_serial();
+
+// 
+int init_openssl();
+int deinit_openssl();
+
+X509 *abac_load_id_from_fp(FILE *);
+EVP_PKEY *abac_load_privkey_from_fp(FILE *);
+X509 *abac_load_id_from_chunk(unsigned char *, int);
+int abac_write_id_to_fp(X509 *cert, FILE *fp);
+int abac_write_privkey_to_fp(EVP_PKEY *key, FILE *fp);
+
+EVP_PKEY *extract_pubkey_from_cert(X509 *);
+
+unsigned char *abac_string_cert(X509 *);
+EVP_PKEY *extract_pubkey_from_cert(X509 *);
+unsigned char *abac_string_privkey(EVP_PKEY *);
+
+char *abac_get_serial(X509 *);
+char *abac_get_cn(X509 *);
+char *abac_get_subject(X509 *); 
+char *abac_get_issuer(X509 *);
+
+// sha of cert
+char *abac_get_keyid(X509 *);
+
+int abac_check_validity(X509 *, struct tm *, struct tm *);
+int abac_still_valid(X509 *);
+int abac_self_signed(X509 *);
+int abac_signed_by(X509 *, X509 *);
+
+#endif /*__ABAC_OPENSSL_H__ */
Index: libabac/abac_util.c
===================================================================
--- libabac/abac_util.c	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/abac_util.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -1,5 +1,10 @@
+
+/* abac_util.c */
+
 #include <err.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
+#include <ctype.h>
 
 /**
@@ -32,4 +37,11 @@
 }
 
+void *abac_xrealloc(void *ptr, size_t size) {
+    void *ret = realloc(ptr, size);
+    if (ret == NULL)
+        err(1, "couldn't realloc %d bytes\n", size);
+    return ret;
+}
+
 /**
  * Split a string based on the given delimiter.
@@ -50,2 +62,20 @@
     *num = count;
 }
+
+int abac_clean_name(char *string) {
+    int i;
+
+    assert(string != NULL);
+
+    // must start with a letter/number
+    if (!isalnum(string[0])) return 0;
+
+    // Name must be alphanumeric or - or _ or :
+    for (i = 1; string[i] != '\0'; ++i)
+        if (!isalnum(string[i]) && string[i] != '-' && string[i] != '_' &&
+                string[i] != ':')
+            return 0;
+
+    return 1;
+}
+
Index: libabac/abac_util.h
===================================================================
--- libabac/abac_util.h	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/abac_util.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -3,7 +3,9 @@
 
 #include <sys/types.h>
+#include <stdlib.h>
 
 void *abac_xmalloc(size_t);
 char *abac_xstrdup(char *);
+void *abac_xrealloc(void *, size_t);
 void abac_split(char *string, char *delim, char **ret, int *num);
 
Index: libabac/abac_verifier.c
===================================================================
--- libabac/abac_verifier.c	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/abac_verifier.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -1,17 +1,16 @@
+
+/* abac_verifier.c */
 #include <assert.h>
 
-#include <library.h>
-#include <credentials/certificates/certificate.h>
-#include <credentials/certificates/x509.h>
-#include <credentials/certificates/ac.h>
-
-#include "abac_verifier.h"
+#include "libabac_common.h"
+#include "abac.h"
 
 #include "abac_list.h"
+#include "uthash.h"
 #include "abac_util.h"
 
 typedef struct _abac_id_cert_t {
-    char *keyid;
-    certificate_t *cert;
+    char *keyid; // using cert's keyid
+    abac_id_t *cert;
 
     UT_hash_handle hh;
@@ -21,15 +20,17 @@
     abac_role_t *head;
     abac_role_t *tail;
-    certificate_t *cert;
-    certificate_t *issuer;
+    abac_id_t *issuer; /* Acme of Acme.customer <- Coyote */
+    abac_attribute_t *cert;
 
     int refcount;
 };
 
+/* hash table of all the principal id credentials */
 abac_id_cert_t *id_certs = NULL;
 
+/***********************************************************************/
 // convert a chunk to a lowercase binary string
 // malloc's the string
-static char *_chunk_to_string(chunk_t chunk) {
+static char *_chunk_to_string(abac_chunk_t chunk) {
     int i;
 
@@ -44,9 +45,10 @@
 // verify that cert was issued by issuer
 // cert and issuer can be the same, in which case the self-sig is validated
-static int _verify_signature(certificate_t *issuer, certificate_t *cert) {
-    if (cert->issued_by(cert, issuer))
-        if (cert->get_validity(cert, NULL, NULL, NULL))
-            return 1;
-    return 0;
+static int _verify_cert(abac_id_t *cert) {
+
+    assert(cert); 
+    if(!abac_id_still_valid(cert))
+        return 0;
+    return 1;
 }
 
@@ -55,13 +57,6 @@
  */
 void abac_verifier_init(void) {
-    // silence all debugging
-    dbg_default_set_level(-1);
-
-    if (!library_init(NULL))
-        exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
-
-    if (!lib->plugins->load(lib->plugins, NULL,
-            lib->settings->get_str(lib->settings, "pki.load", PLUGINS)))
-        exit(SS_RC_INITIALIZATION_FAILED);
+    init_openssl();
+    init_xmlsec();
 }
 
@@ -76,9 +71,9 @@
 
         free(id->keyid);
-        id->cert->destroy(id->cert);
+        abac_id_free(id->cert);
         free(id);
     }
-
-    library_deinit();
+    deinit_xmlsec();
+    deinit_openssl();
 }
 
@@ -86,16 +81,13 @@
  * Load an ID certificate.
  */
-static int _load_id(certificate_t *cert) {
+static int _load_id(abac_id_t *cert) {
     abac_id_cert_t *id_cert = NULL;
     char *keyid = NULL;
-    chunk_t id;
     int ret;
-    x509_t *x509 = (x509_t *)cert;
-
-    assert(cert != NULL);
+
+    assert(cert);
 
     // get the key ID
-    id = x509->get_subjectKeyIdentifier(x509);
-    keyid = _chunk_to_string(id);
+    keyid = abac_id_keyid(cert);
 
     // if we already have this cert 'error' with success
@@ -106,8 +98,7 @@
     }
 
-    // validate sig
-    ret = _verify_signature(cert, cert);
+    ret = abac_id_still_valid(cert);
     if (!ret) {
-        ret = ABAC_CERT_BAD_SIG;
+        ret = ABAC_CERT_INVALID;
         goto error;
     }
@@ -115,5 +106,5 @@
     // success, add the key to the map of certificates
     id_cert = abac_xmalloc(sizeof(abac_id_cert_t));
-    id_cert->keyid = keyid;
+    id_cert->keyid = abac_xstrdup(keyid);
     id_cert->cert = cert;
     HASH_ADD_KEYPTR(hh, id_certs, id_cert->keyid, strlen(id_cert->keyid), id_cert);
@@ -123,24 +114,25 @@
 error:
     if (keyid != NULL) free(keyid);
-
     return ret;
 }
 
+abac_id_t *abac_verifier_lookup_id(char *keyid)
+{
+    abac_id_cert_t *id_cert;
+    HASH_FIND_STR(id_certs, keyid, id_cert);
+    if(id_cert == NULL) return NULL;
+    return id_cert->cert;
+}
+
 /**
  * Load an ID cert from a file.
  */
 int abac_verifier_load_id_file(char *filename) {
-    if (lib == NULL)
-        errx(1, "looks like you didn't call libabac_init() (lib is NULL)");
-
     // load the cert
-    certificate_t *cert = lib->creds->create(
-        lib->creds, CRED_CERTIFICATE, CERT_X509,
-        BUILD_FROM_FILE, filename,
-        BUILD_X509_FLAG, X509_AA, // attribute authority, dumb
-        BUILD_END
-    );
+    abac_id_t *cert = abac_id_from_file(filename);
+
     if (cert == NULL)
         return ABAC_CERT_INVALID;
+
     return _load_id(cert);
 }
@@ -149,12 +141,9 @@
  * Load an ID cert from a chunk.
  */
-int abac_verifier_load_id_chunk(chunk_t chunk) {
+int abac_verifier_load_id_chunk(abac_chunk_t chunk) {
+
     // load the cert
-    certificate_t *cert = lib->creds->create(
-        lib->creds, CRED_CERTIFICATE, CERT_X509,
-        BUILD_BLOB_ASN1_DER, chunk,
-        BUILD_X509_FLAG, X509_AA, // attribute authority, dumb
-        BUILD_END
-    );
+    abac_id_t *cert= abac_id_from_chunk(chunk);
+
     if (cert == NULL)
         return ABAC_CERT_INVALID;
@@ -167,28 +156,20 @@
  * authority.
  */
-static int _load_attribute_cert(certificate_t *cert, abac_credential_t **cred_ret) {
-    ietf_attributes_t *attr_cert = NULL;
+static int _load_attribute_cert(abac_attribute_t *cert, abac_credential_t **cred_ret) {
     abac_role_t *head_role = NULL;
     abac_role_t *tail_role = NULL;
-    abac_id_cert_t *issuer;
-    int ret, i;
-
-    // get the attr
-    ac_t *ac = (ac_t *)cert;
-    attr_cert = ac->get_groups(ac);
-    if (attr_cert == NULL) {
-        ret = ABAC_CERT_INVALID;
-        goto error;
-    }
-
-    char *attr_string = attr_cert->get_string(attr_cert);
-    if (attr_string == NULL) {
-        ret = ABAC_CERT_INVALID;
-        goto error;
+    abac_id_cert_t *issuer=NULL;
+    int ret;
+
+    char *attr_string=abac_attribute_role_string(cert);
+
+    if(attr_string == NULL) {
+       ret = ABAC_CERT_INVALID;
+       goto error;
     }
 
     // split into head/tail parts
     char *head_tail[2];
-    abac_split(attr_string, " <- ", head_tail, &ret);
+    abac_split(attr_string, "<-", head_tail, &ret);
     if (ret != 2) {
         ret = ABAC_CERT_INVALID;
@@ -211,5 +192,4 @@
     }
 
-    // get the issuer based on keyid
     char *principal = abac_role_principal(head_role);
     HASH_FIND_STR(id_certs, principal, issuer);
@@ -219,11 +199,16 @@
     }
 
-    // make sure the issuer's signed it
-    ret = _verify_signature(issuer->cert, cert);
-    if (!ret) {
-        ret = ABAC_CERT_BAD_SIG;
-        goto error;
-    }
-
+    // check if issuer is still valid
+    if (!abac_id_still_valid(issuer->cert)) {
+        ret = ABAC_CERT_INVALID_ISSUER;
+        goto error;
+    }
+
+    // make sure principal match up with keyid
+    if(!abac_id_has_keyid(issuer->cert,principal)) {
+        ret = ABAC_CERT_BAD_PRINCIPAL;
+        goto error;
+    }
+    
     // at this point we know we have a good attribute cert
     abac_credential_t *cred = abac_xmalloc(sizeof(abac_credential_t));
@@ -231,16 +216,12 @@
     cred->tail = tail_role;
     cred->cert = cert;
-    cred->issuer = issuer->cert->get_ref(issuer->cert);
+    /* acme's cert */
+    cred->issuer = abac_id_dup(issuer->cert);
     cred->refcount = 1;
     *cred_ret = cred;
 
-    // free up some crap
-    attr_cert->destroy(attr_cert);
-
     return ABAC_CERT_SUCCESS;
 
 error:
-    if (cert != NULL) cert->destroy(cert);
-    if (attr_cert != NULL) attr_cert->destroy(attr_cert);
     if (head_role != NULL) abac_role_free(head_role);
     if (tail_role != NULL) abac_role_free(tail_role);
@@ -249,17 +230,35 @@
 }
 
+static int _load_attribute_certs(abac_list_t *attr_list, abac_list_t *cred_list) {
+
+    int sz=abac_list_size(attr_list);
+    abac_credential_t *cred_ret=NULL;
+    abac_attribute_t *attr;
+    if(sz) { 
+        abac_list_foreach(attr_list, attr,
+            int ret=_load_attribute_cert(attr, &cred_ret);
+            if(ret==ABAC_CERT_SUCCESS) {
+                abac_list_add(cred_list, cred_ret);
+            }
+        );
+    }
+    return sz;
+}
+
 /**
  * Load an attribute cert from a file.
  */
-int abac_verifier_load_attribute_cert_file(char *filename, abac_credential_t **cred) {
+int abac_verifier_load_attribute_cert_file(char *filename, abac_list_t *cred_list) {
+
     // load the cert
-    certificate_t *cert = lib->creds->create(
-        lib->creds, CRED_CERTIFICATE, CERT_X509_AC,
-        BUILD_FROM_FILE, filename,
-        BUILD_END
-    );
-    if (cert == NULL)
-        return ABAC_CERT_INVALID;
-    return _load_attribute_cert(cert, cred);
+    abac_list_t *attr_list = abac_attribute_certs_from_file(filename);
+
+    if (abac_list_size(attr_list) == 0)
+        return ABAC_CERT_INVALID;
+
+    int ret=_load_attribute_certs(attr_list, cred_list);
+
+    if(ret) return ABAC_CERT_SUCCESS;
+        return ABAC_CERT_INVALID;
 }
 
@@ -267,14 +266,12 @@
  * Load an attribute cert from a chunk.
  */
-int abac_verifier_load_attribute_cert_chunk(chunk_t chunk, abac_credential_t **cred) {
+int abac_verifier_load_attribute_cert_chunk(abac_chunk_t chunk, abac_list_t *cred_list) {
+
     // load the cert
-    certificate_t *cert = lib->creds->create(
-        lib->creds, CRED_CERTIFICATE, CERT_X509_AC,
-        BUILD_BLOB_ASN1_DER, chunk,
-        BUILD_END
-    );
-    if (cert == NULL)
-        return ABAC_CERT_INVALID;
-    return _load_attribute_cert(cert, cred);
+    abac_list_t *attr_list = abac_attribute_certs_from_chunk(chunk);
+
+    if (abac_list_size(attr_list) == 0)
+        return ABAC_CERT_INVALID;
+    return _load_attribute_certs(attr_list,cred_list);
 }
 
@@ -294,18 +291,17 @@
 
 /**
- * Return the encoding of the attribute cert.
+ * Return the xml chunk of the attribute cert.
  */
 abac_chunk_t abac_credential_attribute_cert(abac_credential_t *cred) {
-    chunk_t encoding = cred->cert->get_encoding(cred->cert);
-    abac_chunk_t ret = { encoding.ptr, encoding.len };
-    return ret;
-}
-
-/**
- * Return the encoding of the issuer cert.
+    assert(cred); assert(cred->cert);
+    return abac_attribute_cert(cred->cert);
+}
+
+/**
+ * Return the chunk of the issuer cert.
  */
 abac_chunk_t abac_credential_issuer_cert(abac_credential_t *cred) {
-    chunk_t encoding = cred->issuer->get_encoding(cred->issuer);
-    abac_chunk_t ret = { encoding.ptr, encoding.len };
+    assert(cred); assert(cred->issuer);
+    abac_chunk_t ret= abac_id_in_PEM(cred->issuer);
     return ret;
 }
@@ -334,6 +330,6 @@
     abac_role_free(cred->head);
     abac_role_free(cred->tail);
-    cred->cert->destroy(cred->cert);
-    cred->issuer->destroy(cred->issuer); // reference counted
+    abac_attribute_free(cred->cert);
+    abac_id_free(cred->issuer);
 
     free(cred);
Index: libabac/abac_verifier.h
===================================================================
--- libabac/abac_verifier.h	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/abac_verifier.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -1,6 +1,4 @@
 #ifndef __VERIFIER_H__
 #define __VERIFIER_H__
-
-#include <chunk.h>
 
 #include "abac.h"
@@ -12,7 +10,7 @@
 
 int abac_verifier_load_id_file(char *filename);
-int abac_verifier_load_id_chunk(chunk_t chunk);
-int abac_verifier_load_attribute_cert_file(char *filename, abac_credential_t **cred);
-int abac_verifier_load_attribute_cert_chunk(chunk_t chunk, abac_credential_t **cred);
+int abac_verifier_load_id_chunk(abac_chunk_t chunk);
+int abac_verifier_load_attribute_cert_file(char *filename, abac_list_t *clist);
+int abac_verifier_load_attribute_cert_chunk(abac_chunk_t chunk, abac_list_t  *clist);
 
 #endif /* __VERIFIER_H__ */
Index: libabac/abac_xml.c
===================================================================
--- libabac/abac_xml.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
+++ libabac/abac_xml.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -0,0 +1,1013 @@
+
+/* abac_xml.c, specifically for GENI */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+
+#ifndef XMLSEC_NO_XSLT
+#include <libxslt/xslt.h>
+#include <libxslt/security.h>
+#endif /* XMLSEC_NO_XSLT */
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/xmldsig.h>
+#include <xmlsec/base64.h>
+#include <xmlsec/templates.h>
+#include <xmlsec/crypto.h>
+#include <xmlsec/list.h>
+
+#include <openssl/sha.h>
+
+/* from Ted's reader */
+
+/* for accessing GENI privilege credentials */
+#define GENI_signed_credential "signed-credential"
+#define GENI_credential "credential"
+#define GENI_type "type"
+#define GENI_serial "serial"
+#define GENI_owner_gid "owner_gid"
+#define GENI_owner_urn "owner_urn"
+#define GENI_target_gid "target_gid"
+#define GENI_target_urn "target_urn"
+#define GENI_uuid "uuid"
+#define GENI_expires "expires"
+#define GENI_privileges "privileges"
+#define GENI_privilege "privilege"
+#define GENI_name "name"
+#define GENI_can_delegate "can_delegate"
+
+/* for accessing GENI abac credentials. signed-credential, credential, type and
+ * expires are present as well.  */
+#define GENI_rt0 "rt0"
+#define GENI_version "version"
+
+/* maximum credential stringlen */
+#define CREDLEN 1024
+/* Maximum version len */
+#define VERSIONLEN 256
+
+/* Call perror on str and exit */
+void fatal(const char *str) {
+    perror(str);
+    exit(20);
+}
+
+/* Hex dump the contents of buf (length len) to stderr.  For debugging */
+void dump_it(xmlChar *buf, int len) {
+    int i;
+
+    for (i=0; i < len; i++ ) 
+	fprintf(stderr, "%02x ", buf[i] & 0xff);
+    fprintf(stderr, "\n");
+}
+
+/* Convert a SHA1 hash to text for printing or use in strings.  keyid is the
+ * hash (SHA_DIGEST_LENGTH bytes long) and text is the output string (at least
+ * 2 * SHA_DIGEST_LENGTH +1 bytes long).  The caller is responsible for
+ * allocating and deallocating each of them. */
+void sha1_to_text(xmlChar *keyid, xmlChar *text) {
+    int i = 0;
+
+    for (i=0; i < SHA_DIGEST_LENGTH; i++) 
+	snprintf((char *) text+2*i, 3, "%02x", keyid[i] & 0xff);
+}
+
+/*
+ * Returns the content pointer of the XML_TEXT node that is the child of the
+ * node passed in.  Node must point to an XML_ELEMENT node.  the return value
+ * is still part of node's XML document, so treat it as read only. */
+xmlChar *get_element_content(xmlNodePtr node) {
+    xmlNodePtr text = NULL;
+
+    if ( node->type != XML_ELEMENT_NODE ) return NULL;
+    if ( !( text = node->children) ) return NULL;
+    if ( text->type != XML_TEXT_NODE ) return NULL;
+    return text->content;
+}
+
+/*Find the XML element named field that is a at or below node in the XML
+ * document and return a copy of the base64 decoded content of its content.
+ * For example, find key daya in a signature and return it base64decoded.  buf
+ * is allocated and its length is returned in len.  Any values for buf and len
+ * are ignored and overwritten. */
+int get_base64_field(xmlNodePtr node, xmlChar *field, 
+	xmlChar **buf, int *len) {
+    xmlChar *txt = NULL;
+
+    *buf = NULL;
+
+    if ( !(node = xmlSecFindNode(node, field, xmlSecDSigNs)))
+	goto fail;
+
+    if ( !(txt = get_element_content(node))) 
+	    goto fail;
+    
+    *len = strlen((char *) txt);
+    if ( !(*buf = malloc(*len))) 
+	goto fail;
+
+    if ( (*len = xmlSecBase64Decode(txt, *buf, *len)) < 0 ) 
+	goto fail;
+
+    return 1;
+fail:
+    if ( *buf) free(*buf);
+    *len = 0;
+    return 0;
+}
+/* Construct an ASN.1 header for a field of type h that is len bytes long.
+ * Mosttly this creates the proper length encoding under ASN.1's length
+ * encoding rules. buf will contain the new header (and the caller is
+ * responsible for making sure it is at least 6 bytes long, though fewer are
+ * usually used.  The length of the constructed header is returned. This is
+ * used in creating a key hash from key data.*/
+int make_asn1_header(char h, size_t len, xmlChar *buf) {
+    if ( len > 0x00ffffff) {
+	buf[0] = h;
+	buf[1] = 0x84;
+	buf[2] = (len >> 24) & 0xff;
+	buf[3] = (len >> 16) & 0xff;
+	buf[4] = (len >> 8) & 0xff;
+	buf[5] = (len) & 0xff;
+	return 6;
+    } else if ( len > 0x0000ffff ) {
+	buf[0] = h;
+	buf[1] = 0x83;
+	buf[2] = (len >> 16) & 0xff;
+	buf[3] = (len >> 8) & 0xff;
+	buf[4] = (len) & 0xff;
+	return 5;
+    } else if ( len > 0x000000ff ) {
+	buf[0] = h;
+	buf[1] = 0x82;
+	buf[2] = (len >> 8) & 0xff;
+	buf[3] = (len) & 0xff;
+	return 4;
+    } else if ( len > 0x80 ) {
+	buf[0] = h;
+	buf[1] = 0x81;
+	buf[2] = (len) & 0xff;
+	return 3;
+    } else {
+	buf[0] = h;
+	buf[1] = (len) & 0xff;
+	return 2;
+    }
+}
+
+/* Find the RSA key parameters in the KeyInfo section of the XML document
+ * pointed to by doc, construct the ASN.1 encoding of that key and SHA1 hash
+ * it.    This gives the standard keyid of that key.  keyid will be the binary
+ * encoding of that (the bits of the hash)  sha1_to_text will turn it to text.
+ * keyid must be at least SHA_DIGEST_LENGTH bytes long, and the caller is
+ * responsible for it. This routine returns 1 on success and 0 on failure. */
+int get_keyid_from_keyinfo(xmlDocPtr doc, xmlChar *keyid) {
+    xmlNodePtr root = NULL; /* XML document root */
+    xmlNodePtr node = NULL; /* Scratch XML node */
+
+    xmlChar b0[20];	    /* Header for the sequence */
+    xmlChar b1[20];	    /* Header for the modulus */
+    xmlChar b2[20];	    /* Header for the exponent */
+    int l0 = 0;		    /* Header length for the sequence */
+    int l1 = 0;		    /* Header length for the modulus */
+    int l2 = 0;		    /* Header length for the exponent */
+
+    xmlChar *modBuf = NULL; /* Bytes of the modulus */
+    xmlChar *expBuf = NULL; /* Bytes of the exponent */
+    int modLen = 0;	    /* Length of the modulus */
+    int expLen = 0;	    /* Length of the exponent */
+
+    SHA_CTX sha;	    /* SHA1 hash context */
+
+    int rv = 0;		    /* return value */
+
+    if ( !SHA1_Init(&sha)) goto fail;
+
+    if ( !doc || !(root = xmlDocGetRootElement(doc)) ) 
+	goto fail;
+
+    /* Find the KeyInfo section to be the root of later searches */
+    if ( !(node = xmlSecFindNode(root, 
+		    xmlSecNodeKeyInfo, xmlSecDSigNs)))
+	goto fail;
+
+    /* Get the binary for the modulus and exponent */
+    if ( !get_base64_field(node, (xmlChar *) "Modulus", &modBuf, &modLen)) 
+	goto fail;
+    if ( !get_base64_field(node, (xmlChar *) "Exponent", &expBuf, &expLen)) 
+	goto fail;
+
+    /* Construct the headers for modulus and exponent.  Another weird fact
+     * about ASN.1 is that all the integers are signed, so if either the
+     * modulus or exponent has the high order bit of its first byte set, the
+     * ASN.1 encoding has a 0 byte prepended.  This code appends the 0 byte to
+     * the header, which results in the same hash. */
+    if ( modBuf[0] & 0x80 ) {
+	l1 = make_asn1_header(0x02, modLen +1, b1);
+	b1[l1++] = '\0';
+    } else {
+	l1 = make_asn1_header(0x02, modLen, b1);
+    }
+
+    if ( expBuf[0] & 0x80 ) {
+	l2 = make_asn1_header(0x02, expLen +1, b2);
+	b2[l2++] = '\0';
+    } else {
+	l2 = make_asn1_header(0x02, expLen, b2);
+    }
+
+    /* Sequence header: have to do it after we know the lengths of the inner
+     * headers. */
+    l0 = make_asn1_header(0x30, modLen + expLen + l1 + l2, b0);
+    /* Hash it all up in parts */
+    SHA1_Update(&sha, b0, l0);
+    SHA1_Update(&sha, b1, l1);
+    SHA1_Update(&sha, modBuf, modLen);
+    SHA1_Update(&sha, b2, l2);
+    SHA1_Update(&sha, expBuf, expLen);
+    SHA1_Final(keyid, &sha);
+    rv = 1;
+fail:
+
+    if (modBuf) free(modBuf);
+    if (expBuf) free(expBuf);
+    return rv;
+}
+
+/* Check the signature of either kind of credential - it'll work for basically
+ * any signed XML. Returns true if the signature checks and false otherwise.
+ * Takes a pointer to the XML document to check.  Similar to the examples at
+ * http://www.aleksey.com/xmlsec/api/xmlsec-examples.html */
+int check_signature(xmlDocPtr doc) {
+    xmlNodePtr root = NULL;	    /* Root XML node */
+    xmlNodePtr node = NULL;	    /* Scratch XML node */
+    xmlSecKeyInfoCtxPtr keyCtx = NULL;/* Key info context.  Used to parse
+					 KeyInfo */
+    xmlSecKeysMngrPtr keyMan = NULL;/* Key manager - used because we have
+				       certificated. */
+    xmlSecKeyPtr key = NULL;	    /* The key extracted */
+    xmlSecDSigCtxPtr dsigCtx = NULL;/* Signature context */
+    int rv = 0;			    /* Return value */
+
+    if ( doc && !(root = xmlDocGetRootElement(doc)) ) 
+	goto fail;
+
+    /* Find the KeyInfo section to pull the keys out. */
+    if ( !(node = xmlSecFindNode(root, 
+		    xmlSecNodeKeyInfo, xmlSecDSigNs)))
+	goto fail;
+
+    /* Create and initialize key, key manager, and context */
+    if ( !(key = xmlSecKeyCreate() ) )
+	    goto fail;
+    if ( !(keyMan = xmlSecKeysMngrCreate()) ) 
+	goto fail;
+
+    if ( xmlSecCryptoAppDefaultKeysMngrInit(keyMan) < 0)
+	goto fail;
+
+    if ( !(keyCtx = xmlSecKeyInfoCtxCreate(keyMan)) ) 
+	goto fail;
+
+    /* Do not check certificate signatures */
+    keyCtx->flags |= XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS;
+
+    /* Gather up the key data */
+    if ( xmlSecKeyInfoNodeRead(node, key, keyCtx) < 0 ) 
+	goto fail;
+
+    /* Set up the signature context and attack the keys */
+    if ( !(dsigCtx = xmlSecDSigCtxCreate(NULL)))
+	goto fail;
+
+    dsigCtx->signKey = key;
+
+    /* find the Signature section */
+    if ( !(node = xmlSecFindNode(root, 
+		    xmlSecNodeSignature, xmlSecDSigNs)))
+	goto fail;
+
+    /* Check it */
+    if ( (rv = xmlSecDSigCtxVerify(dsigCtx, node)) < 0 ) 
+	goto fail;
+
+    /* Strangely xmlSecDSigCtxVerify can return success even if the status is
+     * bad.  Check the status in the context explicitly and override the result
+     * above if necessary.*/
+    if ( dsigCtx->status != xmlSecDSigStatusSucceeded) 
+	goto fail;
+
+    return 1;
+fail:
+    if ( key ) xmlSecKeyDestroy(key);
+    if ( keyCtx ) xmlSecKeyInfoCtxDestroy(keyCtx);
+    if ( dsigCtx) xmlSecDSigCtxDestroy(dsigCtx);
+    return 0;
+}
+
+/* Parse the content of the expires field and compare it to the time passed in
+ * n.  If expires is earlier, return false, else true.  If n is null, compare
+ * it to the current time. */
+int check_GENI_expires(xmlChar *expires, struct tm *n) {
+    struct tm tv;   /* Parsed expires field */
+    time_t now;	    /* Now in seconds since the epoch */
+    time_t exp;	    /* expires in seconds since the epoch */
+
+    if (n) now = mktime(n);
+    else time(&now);
+
+    strptime((char *) expires, "%FT%TZ", &tv);
+    exp = timegm(&tv);
+
+    return difftime(exp, now) > 0.0;
+}
+
+/* Convert a parsed privilege in a GENI privilege string into one or more ABAC
+ * creds.  Rules are as in http://groups.geni.net/geni/wiki/TIEDCredentials .
+ * keyid is  the issuer's keyid, text_owner is the owners keyid (XXX:a
+ * placeholder) text_target is the target's keyid (XXX: a placeholder), priv is
+ * the privilege being assigned, and delegate is true if it can be delegated.
+ * carray is the output array of character strings that currently has *nc
+ * entries in it.  If nc has nothing in it, insert the "speaks_for" delegation
+ * rules.  Then add the privilege specific rules. On failure ***carray and its
+ * contents are freed and *nc is set to zero.*/
+void add_privilege_credential_string(xmlChar *text_keyid, xmlChar *text_owner, 
+	xmlChar *text_target, xmlChar *priv, int delegate, xmlChar ***carray,
+	int *nc) {
+    xmlChar **rv = *carray;	/* Local pointer to the array of strings */
+    xmlChar **newrv = NULL;	/* Used to realloc the array of strings */
+    int ncred = *nc;		/* Local copy of the number of creds in rv */
+    int newc = (delegate) ? 3 : 1;  /* Number of new creds to add */
+    int base = ncred;		/* First new credential index.  This advances
+				   as we add creds to rv. */
+    int i = 0;			/* Scratch */
+
+    /* If rv is empty, add the speaks_for rules */
+    if (base == 0 ) newc += 2;
+
+    /* Resize rv */
+    if (!(newrv = realloc(rv, (base + newc) * sizeof(xmlChar *))))
+	goto fail;
+    for ( i = 0; i < base +newc; i ++) 
+	newrv[i] = (i < base) ? rv[i] : NULL;
+
+    /* So fail works */
+    rv = newrv;
+    ncred = base + newc;
+
+    /* Add speaks_for rules  if needed */
+    if ( base == 0 ) {
+	if ( !(rv[base] = malloc(CREDLEN))) goto fail;
+	snprintf((char *) rv[base], CREDLEN, 
+		"%s.speaks_for_%s <- %s.speaks_for_%s",
+		text_keyid, text_owner, text_owner, text_owner);
+	base++;
+	if ( !(rv[base] = malloc(CREDLEN))) goto fail;
+	snprintf((char *) rv[base], CREDLEN, 
+		"%s.speaks_for_%s <- %s",
+		text_keyid, text_owner, text_owner);
+	base++;
+    }
+
+    /* The assignemnt of priv.  Always happens */
+    if ( !(rv[base] = malloc(CREDLEN))) goto fail;
+    snprintf((char *) rv[base], CREDLEN, 
+	    "%s.%s_%s <- %s.speaks_for_%s",
+	    text_keyid, priv, text_target, text_keyid, text_owner);
+    base++;
+    /* Add delegation rules */
+    if ( delegate ) {
+	if ( !(rv[base] = malloc(CREDLEN))) goto fail;
+	snprintf((char *) rv[base], CREDLEN, 
+		"%s.%s_%s <- %s.can_delegate_%s_%s.%s_%s",
+		text_keyid, priv, text_target, text_keyid, priv, 
+		text_target, priv, text_target);
+	base++;
+	if ( !(rv[base] = malloc(CREDLEN))) goto fail;
+	snprintf((char *) rv[base], CREDLEN, 
+		"%s.can_delegate_%s_%s <- %s",
+		text_keyid, priv, text_target, text_owner);
+	base++;
+    }
+    /* And return new values */
+    *carray = rv;
+    *nc = ncred;
+    return;
+fail:
+    if ( rv ) {
+	/* Delete all the allocations, ours or not, and clear the caller's 
+	 * variables */
+	for (i = 0; i < ncred; i++) 
+	    if (rv[i]) free(rv[i]);
+	free(rv);
+    }
+    *carray = NULL;
+    *nc = 0;
+}
+
+/* Parse a GENI privilege credential (that has already had its signature
+ * checked) and return the RT0 strings that the credential is encoded as.  The
+ * return value is an array of strings, zero-terminated (like argv) that holds
+ * the RT0 strings.  It is NULL on failure. */
+xmlChar **parse_privilege(xmlDocPtr doc) {
+    xmlNodePtr root = NULL;	/* XML root node */
+    xmlNodePtr node = NULL;	/* XML scratch node */
+    xmlNodePtr owner = NULL;	/* XML owner_gid node */
+    xmlNodePtr expires = NULL;	/* XML expires node */
+    xmlNodePtr target = NULL;	/* XML target_gid node */
+    xmlNodePtr privs = NULL;	/* XML privileges node */
+    xmlNodePtr priv = NULL;	/* XML privilege node - used to iterate */
+    xmlChar keyid[SHA_DIGEST_LENGTH];	/* Issuer key SHA1 */
+    xmlChar text_keyid[2*SHA_DIGEST_LENGTH+1];/* Issuer keyid as text */
+    xmlChar **newrv = NULL;	/* Used to realloc rv to add the NULL
+				   terminator*/
+    xmlChar **rv = NULL;	/* return value */
+    int ncred = 0;		/* number of creds in rv, incase we need to
+				   deallocate it */
+    int i = 0;			/* scratch */
+
+    if ( doc && !(root = xmlDocGetRootElement(doc)) ) 
+	goto fail;
+
+    /* Get the issuer keyid */
+    if ( !get_keyid_from_keyinfo(doc, keyid)) 
+	goto fail;
+    sha1_to_text(keyid, text_keyid);
+
+    /* Find the various fields of interest */
+    if ( !(node = xmlSecFindNode(root, (xmlChar *) GENI_credential, NULL)))
+	goto fail;
+
+    /* Make sure this is not expired */
+    if ( !(expires = xmlSecFindNode(node, (xmlChar *) GENI_expires, NULL)))
+	goto fail;
+
+    if ( !check_GENI_expires(get_element_content(expires), NULL))
+	goto fail;
+
+    /* XXX: owner and target will be X.509 pem files from which we need to
+     * extract keyids for add_privilege_credential_string.  I didn't replciate
+     * that code which lives in libabac. Code to get those keyids needs to be
+     * added. */
+    if ( !(owner = xmlSecFindNode(node, (xmlChar *) GENI_owner_gid, NULL)))
+	goto fail;
+
+    if ( !(target = xmlSecFindNode(node, (xmlChar *) GENI_target_gid, NULL)))
+	goto fail;
+
+    if ( !(privs = xmlSecFindNode(node, (xmlChar *) GENI_privileges, NULL)))
+	goto fail;
+
+    /* Iterate through the privileges, parsing out names and can_delegate and
+     * generating the strings from it. */
+    for (priv = privs->children; priv; priv = priv->next) {
+	/* reinitialized every time around */
+	xmlNodePtr n = NULL;
+	xmlChar *name = NULL;
+	int delegate = -1;
+
+	/* Privilege node */
+	if ( priv->type != XML_ELEMENT_NODE || 
+		strcmp((char *) priv->name, (char *) GENI_privilege) ) {
+	    fprintf(stderr, "Bad node!\n");
+	    goto fail;
+	}
+	/* looking for name and can_delegate */
+	for (n = priv->children; n; n = n->next) {
+	    if ( n->type != XML_ELEMENT_NODE ) 
+		continue;
+	    if ( !strcmp((char *) n->name, (char *) GENI_name)) {
+		name = get_element_content(n);
+		continue;
+	    }
+	    if ( !strcmp((char *) n->name, (char *) GENI_can_delegate)) {
+		xmlChar *boolean = get_element_content(n);
+
+		if ( !strcmp((char *) boolean, "true") ||
+			!strcmp((char *) boolean, "1") ) {
+		    delegate = 1;
+		} else if ( !strcmp((char *) boolean, "false") ||
+			!strcmp((char *) boolean, "0") ) {
+		    delegate = 0;
+		} else {
+		    fprintf(stderr, "Unknown delegation value %s", boolean);
+		}
+	    }
+	}
+	/* Found both name and can_delegate, add the RT0 to rv and ncred */
+	if ( name && delegate != -1 ) {
+	    add_privilege_credential_string(text_keyid, 
+		    (xmlChar *) "owner-sha1", (xmlChar *) "target-sha1", name,
+		    delegate, &rv, &ncred);
+	    if ( !rv ) goto fail;
+	}
+    }
+
+    /* Add the terminating NULL */
+    if (!(newrv = realloc(rv, ncred+1)))
+	goto fail;
+
+    for ( i = 0; i < ncred+1; i ++) 
+	newrv[i] = (i < ncred) ? rv[i] : NULL;
+
+    return rv;
+
+fail:
+    /* Throw away all of rv if there's an error */
+    if ( rv ) {
+	for (i = 0; i < ncred; i++) 
+	    if (rv[i]) free(rv[i]);
+	free(rv);
+    }
+    return NULL;
+}
+
+/* Compare the version string (major.minor) to the major and minor numbers, and
+ * return true if the version string is >= the major minor pair. */
+int check_GENI_abac_version(xmlChar *version, int major, int minor) {
+    xmlChar lversion[VERSIONLEN];   /* Buffer to parse version in */
+    xmlChar *lp = &lversion[0];	    /* strsep needs a pointer it can modify */
+    char *p = NULL;		    /* Scratch */
+    char *ep = NULL;		    /* used to check the integer parsing */
+    int maj = 0;		    /* Parsed major number */
+    int min = 0;		    /* Parsed minor number */
+
+    snprintf((char *) lp, VERSIONLEN, "%s", (char *) version);
+    if ( !(p = strsep((char **) &lp, "."))) return 0;
+    /* lp points t the major number and p to the minor, now we parse integers*/
+
+    maj = strtol((char *) lp, &ep, 10);
+    /* If the major version string was empty or (more likely) there were
+     * non-digits in it, throw out the result */
+    if ( *lp == '\0' || *ep != '\0' ) 
+	return 0;
+    min = strtol(p, &ep, 10);
+    /* Same test on the minor string */
+    if ( *p == '\0' || *ep != '\0' ) 
+	return 0;
+
+    if (maj > major || (maj == major && min > minor) ) return 0;
+    else return 1;
+}
+/*
+ * Parse an ABAC credential (that has had its signature checked.  Make sure it
+ * has not expired and that its version is at least 1.0 (XXX: parameterize
+ * that), and return the RT0 it encodes as the only entry in an NULL-terminated
+ * array of strings (just like parse_privilege). On failure return NULL. */
+xmlChar **parse_abac(xmlDocPtr doc) {
+    xmlNodePtr root = NULL;	/* XML root node */
+    xmlNodePtr node = NULL;	/* XML credential node */
+    xmlNodePtr rt0 = NULL;	/* XML rt0 node */
+    xmlNodePtr expires = NULL;	/* XML expires node */
+    xmlNodePtr version = NULL;	/* XML version node */
+    xmlChar keyid[SHA_DIGEST_LENGTH];/* issuer SHA1 hash */
+    xmlChar text_keyid[2*SHA_DIGEST_LENGTH+1];/* Issuer keyid in text */
+    xmlChar *txt;		/* rt0 content */
+    xmlChar **rv = NULL;	/* return value */
+    int ncred = 0;		/* number of creds in rv */
+    int i = 0;			/* Scratch (used only in fail:)  */
+
+    if ( doc && !(root = xmlDocGetRootElement(doc)) ) 
+	goto fail;
+
+    /* Get the issuer keyid */
+    if ( !get_keyid_from_keyinfo(doc, keyid)) 
+	goto fail;
+    sha1_to_text(keyid, text_keyid);
+    /* get the various nodes of interest */
+    if ( !(node = xmlSecFindNode(root, (xmlChar *) GENI_credential, NULL)))
+	goto fail;
+    if ( !(expires = xmlSecFindNode(node, (xmlChar *) GENI_expires, NULL)))
+	goto fail;
+    if ( !(rt0 = xmlSecFindNode(node, (xmlChar *) GENI_rt0, NULL)))
+	goto fail;
+    if ( !(version = xmlSecFindNode(node, (xmlChar *) GENI_version, NULL)))
+	goto fail;
+
+    /* Check the version and expiration */
+    if ( !check_GENI_abac_version(get_element_content(version), 1, 0)) 
+	goto fail;
+    if ( !check_GENI_expires(get_element_content(expires), NULL))
+	goto fail;
+
+    /* read the RT0 and return it */
+    if ( !(txt = get_element_content(rt0)) ) goto fail;
+
+    if ( !(rv = malloc(2 * sizeof(xmlChar *)))) goto fail;
+    if (!(rv[0] = malloc(strlen((char *) txt)+1))) goto fail;
+    ncred++;
+
+    strcpy((char *) rv[0], (char *) txt);
+    rv[1] = NULL;
+
+    return rv;
+fail:
+    if ( rv ) {
+	for (i = 0; i < ncred; i++) 
+	    if (rv[i]) free(rv[i]);
+	free(rv);
+    }
+    return NULL;
+}
+
+/* Check and parse a GENI credential.  Return the new RT0 rules in a
+ * NULL-terminated array of strings.  If the signature or parsing fails, return
+ * NULL. Demultiplexed to parse_privilege or parse_abac to do the parsing and
+ * uses check_signature to confirm the sig. */
+xmlChar **read_credential(char *infile, xmlChar **xml) {
+    xmlDocPtr doc = xmlParseFile(infile);   /* Parse the document */
+    xmlNodePtr node = NULL;		    /* XML scratch node */
+    xmlChar *text = NULL;		    /* Text of the type field */
+    xmlChar **rv = NULL;		    /* return value from parse_* */
+
+    if ( !check_signature(doc) ) 
+	goto fail;
+    /* Parse out the type field */
+    if ( !(node = xmlDocGetRootElement(doc)) ) 
+	goto fail;
+    if ( !(node = xmlSecFindNode(node, (xmlChar *) GENI_credential, NULL)))
+	goto fail;
+    if ( !(node = xmlSecFindNode(node, (xmlChar *) GENI_type, NULL)))
+	goto fail;
+
+    if ( !(text = get_element_content(node)) ) 
+	goto fail;
+
+    /* Demux on type */
+    if ( !strcmp((char *) text, "privilege")) {
+	rv = parse_privilege(doc);
+    } else if ( !strcmp((char *) text, "abac")) {
+	rv = parse_abac(doc);
+    } else { 
+	goto fail;
+    }
+    int len=0;
+    xmlDocDumpMemoryEnc(doc, xml, &len, "UTF-8");
+    if(len == 0)
+       goto fail;
+
+fail:
+    xmlFreeDoc(doc);
+    return rv;
+}
+
+char **my_read_credential(char *infile, char **xml) {
+    return (char **)read_credential(infile, (xmlChar **)xml);
+}
+
+
+/* Straight off http://www.aleksey.com/xmlsec/api/xmlsec-examples.html .
+ * Voodoo.  But call it. */
+int init_xmlsec() {
+    /* Init xmlsec library */
+    if(xmlSecInit() < 0) {
+        fprintf(stderr, "Error: xmlsec initialization failed.\n");
+        return(-1);
+    }
+
+    /* Check loaded library version */
+    if(xmlSecCheckVersion() != 1) {
+        fprintf(stderr,
+		"Error: loaded xmlsec library version is not compatible.\n");
+        return(-1);
+    }
+
+    /* Load default crypto engine if we are supporting dynamic
+     * loading for xmlsec-crypto libraries. Use the crypto library
+     * name ("openssl", "nss", etc.) to load corresponding 
+     * xmlsec-crypto library.
+     */
+#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
+    if(xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
+        fprintf(stderr, "Error: unable to load default xmlsec-crypto library. "
+		"Make sure\n" 
+		"that you have it installed and check shared libraries path\n"
+		"(LD_LIBRARY_PATH) envornment variable.\n");
+        return(-1);     
+    }
+#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */
+
+    /* Init crypto library */
+    if(xmlSecCryptoAppInit(NULL) < 0) {
+        fprintf(stderr, "Error: crypto initialization failed.\n");
+        return(-1);
+    }
+
+    /* Init xmlsec-crypto library */
+    if(xmlSecCryptoInit() < 0) {
+        fprintf(stderr, "Error: xmlsec-crypto initialization failed.\n");
+        return(-1);
+    }
+    return 0;
+}
+
+int deinit_xmlsec() {
+  /* no op for now */
+    return 0;
+}
+
+/* from Ted's writer */
+
+/* maximum rt0 stringlen */
+#define CREDLEN 1024
+/* Maximum version len */
+#define VERSIONLEN 256
+
+/* XML template for a new RT0 credential.  Fill in the RT0 to store (XML
+ * escaped) and the expiration time (formated using strftime_format and
+ * strftime). */
+xmlChar *template = (xmlChar *) (
+"<signed-credential>\n"
+"    <credential xml:id=\"ref0\">\n"
+"	<type>abac</type>\n"
+"	<version>1.0</version>\n"
+"	<expires>%s</expires>\n"
+"	<rt0>%s</rt0>\n"
+"    </credential>\n"
+"    <signatures>\n"
+"	<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n"
+"	    <SignedInfo>\n"
+"		<CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>\n"
+"		<SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"/>\n"
+"		<Reference URI=\"#ref0\">\n"
+"		    <Transforms>\n"
+"			<Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"/>\n"
+"		    </Transforms>\n"
+"		    <DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/>\n"
+"		    <DigestValue/>\n"
+"		</Reference>\n"
+"	    </SignedInfo>\n"
+"	    <SignatureValue/>\n"
+"	    <KeyInfo>\n"
+"	      <KeyValue/>\n"
+"		<X509Data>\n"
+"		    <X509Certificate/>\n"
+"		    <X509SubjectName/>\n"
+"		    <X509IssuerSerial/>\n"
+"		</X509Data>\n"
+"	    </KeyInfo>\n"
+"	</Signature>\n"
+"    </signatures>\n"
+"</signed-credential>");
+
+char *strftime_fmt = "%FT%TZ";
+#define EXPIRESLEN 20
+
+/* Return a copy of str with > < and & replaced by &gt; &lt; and &amp; for
+ * embedding in XML.  Caller is responsible for deallocating the return value
+ * using xmlFree().
+ */
+xmlChar *minimal_xml_escaping(xmlChar *str) {
+    /* A quickie translation table with the character to escape, the output
+     * string and the length of the output in it. The table is initialized with
+     * the three translations we want. */
+    static struct esc {
+	xmlChar c;
+	xmlChar *esc;
+	int l;
+    } escapes[] = {
+	{ (xmlChar) '<', (xmlChar *) "&lt;", 4 }, 
+	{ (xmlChar) '>', (xmlChar *) "&gt;", 4},
+	{ (xmlChar) '&', (xmlChar *) "&amp;", 5},
+	{ (xmlChar) '\0', NULL, 0 },
+    };
+
+    xmlChar *rv = NULL;	    /* Return value */
+    xmlChar *p = NULL;	    /* Scratch (walking str) */
+    xmlChar *q = NULL;	    /* Scratch (walking rv) */
+    struct esc *e = NULL;   /* Scratch for walking escapes */
+    int len = 0;	    /* Length of rv */
+
+    /* Walk str and calculate how long the escaped version is */
+    for ( p = str; *p ; p++) {
+	int foundit = 0;
+	for ( e = escapes; !foundit && e->c ; e++ ) {
+	    if ( *p == e->c ) {
+		len += e->l;
+		foundit = 1;
+	    }
+	}
+	if ( !foundit ) len++;
+    }
+    /* Allocate the new string */
+    q = rv = (xmlChar *) xmlMalloc(len+1);
+    /* copy str to rv, escaping when necessary */
+    for ( p = str; *p ; p++) {
+	int foundit = 0;
+	for ( e = escapes; !foundit && e->c ; e++ ) {
+	    if ( *p == e->c ) {
+		strncpy((char *) q, (char *) e->esc, e->l);
+		q += e->l;
+		foundit = 1;
+	    }
+	}
+	if ( !foundit ) *q++ = *p;
+    }
+    /* terminate rv */
+    *q = '\0';
+    return rv;
+}
+
+/* Make an new GENI abac credential with the rt0 rule that expires secs from
+ * now.  cert is the PEM encoded X.509 of the issuer's certificate as a string.
+ * certlen is the length of cert.  Returns the XML. Caller is responsible for
+ * freeing it. */
+char *make_credential(xmlChar *rt0, int secs, xmlSecByte *cert, 
+	xmlSecSize certlen) {
+    xmlDocPtr doc = NULL;	/* parsed XML document */
+    xmlNodePtr root = NULL;	/* Root of the document */
+    xmlNodePtr signNode = NULL;	/* <Signature> element */
+    xmlSecDSigCtxPtr dsigCtx = NULL;  /* Signing context */
+    xmlChar *rt0_escaped = minimal_xml_escaping(rt0); /* RT0, escaped */
+    xmlChar *rv = NULL;		/* return value */
+    time_t exp;			/* expriation time (seconds since epoch) */
+    struct tm exp_tm;		/* expiration for formatting */
+    char estr[EXPIRESLEN+1];	/* String with formatted expiration */
+    char *temp = NULL;		/* populated XML template */
+    int len = 0;		/* length of the populated template (temp) */
+
+    if ( !rt0_escaped) goto fail;
+
+    /* Calculate the length of the populated template and allocate it */
+    len = strlen((char *) template)+EXPIRESLEN+strlen((char *) rt0_escaped)+1;
+
+    if ( !(temp = malloc(len)) )
+	goto fail;
+
+    /* format expiration */
+    time(&exp);
+    exp += secs;
+    gmtime_r(&exp, &exp_tm);
+
+    if (strftime(estr, EXPIRESLEN+1, strftime_fmt, &exp_tm) == 0 ) 
+	goto fail;
+
+    /* Populate template with  expiration and escaped rt0 */
+    snprintf(temp, len, (char *) template, estr, (char *) rt0_escaped);
+
+    /* parse the populated template */
+    if ( !(doc = xmlParseMemory(temp, len))) 
+	goto fail;
+
+    if (!(root = xmlDocGetRootElement(doc)) )
+	goto fail;
+
+    /* Find the signature element for the Signing call */
+    signNode = xmlSecFindNode(root, xmlSecNodeSignature, xmlSecDSigNs);
+
+    /* Create the context */
+    if ( !(dsigCtx = xmlSecDSigCtxCreate(NULL))) 
+	goto fail;
+
+    /* Assign the key (a PEM key) */
+    if (!(dsigCtx->signKey = xmlSecCryptoAppKeyLoadMemory(cert, certlen,
+		    xmlSecKeyDataFormatPem, NULL, NULL, NULL)) )
+	goto fail;
+
+    /* Load the certificate */
+    if ( xmlSecCryptoAppKeyCertLoadMemory(dsigCtx->signKey, cert, certlen,
+		xmlSecKeyDataFormatPem) < 0)
+	goto fail;
+
+    /* Sign it */
+    if ( xmlSecDSigCtxSign(dsigCtx, signNode) < 0)
+	goto fail;
+
+    /* Store the signed credential to rv */
+    xmlDocDumpMemoryEnc(doc, &rv, &len, "UTF-8");
+fail:
+    /* clean up */
+    if (dsigCtx) 
+	xmlSecDSigCtxDestroy(dsigCtx);
+    if ( doc) xmlFreeDoc(doc);
+    if (rt0_escaped) xmlFree(rt0_escaped);
+    if ( temp) free(temp);
+    return (char *) rv;
+}
+
+char *my_make_credential(char* rt0, int secs, char* cert, int certlen)
+{
+    return make_credential((xmlChar *)rt0, secs, (xmlSecByte *)cert, (xmlSecSize)certlen);
+}
+
+
+#define CERTSIZE 4096
+/* Read a file into a the dynamically allocated array buf.  Whatever was in buf
+ * is discarded w/o freeing so it should initially be NULL and len 0. On return
+ * buf contains as much of the contents of filename as possible and len is the
+ * length of it.  The caller must free() buf. buf is zero terminated.*/
+void read_cert(char *filename, char **buf, int *len) {
+    FILE *cert = NULL;
+    char *nbuf = NULL;
+    int cap = CERTSIZE;
+    int r = 0;
+
+    *len = 0; 
+    if (!(*buf = malloc(CERTSIZE))) return;
+
+    if ( !(cert = fopen(filename, "r"))) 
+	goto fail;
+
+    /* Read cert, expanding buf as necessary */
+    while ( (r = fread(*buf + *len, 1, cap - *len, cert)) != 0) {
+	*len += r;
+	if ( *len == cap ) {
+	    if ( !(nbuf = realloc(*buf, cap + CERTSIZE)) ) 
+		goto fail;
+	    memcpy(nbuf, *buf, cap);
+	    cap += CERTSIZE;
+	    *buf = nbuf;
+	}
+    }
+    /* Extend if we read exactly cap bytes so we can terminate the string */
+    if ( *len == cap ) {
+	if ( !(nbuf = realloc(*buf, cap + CERTSIZE)) ) 
+	    goto fail;
+	memcpy(nbuf, *buf, cap);
+	cap += CERTSIZE;
+	*buf = nbuf;
+    }
+    (*buf)[*len] = '\0';
+    return;
+fail:
+    if ( *buf) free(*buf);
+    *buf = NULL;
+    *len = 0;
+    return;
+}
+
+
+/******** helper functions **************************/
+char *get_keyid_from_xml(char *xml) {
+    xmlDocPtr doc=xmlParseMemory(xml,strlen(xml));
+    xmlChar keyid[SHA_DIGEST_LENGTH];   /* Issuer key SHA1 */
+    xmlChar text_keyid[2*SHA_DIGEST_LENGTH+1];/* Issuer keyid as text */
+    char *ret=NULL;
+
+    /* Get the issuer keyid */
+    if ( !get_keyid_from_keyinfo(doc, keyid))
+        goto fail;
+    sha1_to_text(keyid, text_keyid);
+    ret=strdup((char *)text_keyid);
+fail:
+    xmlFreeDoc(doc);
+    return ret;
+}
+
+/* validity time in xml from current time */
+long get_validity_from_xml(char *xml) {
+    xmlDocPtr doc=xmlParseMemory(xml,strlen(xml));
+    xmlNodePtr node = NULL;                 /* XML scratch node */
+    xmlNodePtr expires = NULL;  /* XML expires node */
+    struct tm tv;   /* Parsed expires field */
+    time_t now;     /* Now in seconds since the epoch */
+    time_t exp;     /* expires in seconds since the epoch */
+    long dtime=0;
+
+    if ( !(node = xmlDocGetRootElement(doc)) )
+        goto fail;
+
+    if ( !(expires = xmlSecFindNode(node, (xmlChar *) GENI_expires, NULL)))
+        goto fail;
+
+    xmlChar *etime=get_element_content(expires);
+    time(&now);
+
+    strptime((char *) etime, "%FT%TZ", &tv);
+    exp = timegm(&tv);
+    dtime=difftime(exp, now);
+
+fail:
+    xmlFreeDoc(doc);
+    return dtime;
+}
+
+char **get_rt0_from_xml(char *xml) {
+    xmlDocPtr doc=xmlParseMemory(xml,strlen(xml));
+    xmlNodePtr node = NULL;                 /* XML scratch node */
+    xmlChar *text = NULL;                   /* Text of the type field */
+    xmlChar **rv = NULL;                    /* return value from parse_* */
+    
+    if ( !(node = xmlDocGetRootElement(doc)) )
+        goto fail;
+
+    /* Demux on type */
+    if ( !strcmp((char *) text, "privilege")) {
+        rv = parse_privilege(doc);
+    } else if ( !strcmp((char *) text, "abac")) {
+        rv = parse_abac(doc);
+    } else {
+        goto fail;
+    }
+fail:
+    xmlFreeDoc(doc);
+    return rv;
+}
Index: libabac/abac_xml.h
===================================================================
--- libabac/abac_xml.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
+++ libabac/abac_xml.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -0,0 +1,19 @@
+/* abac_xml.h */
+#ifndef __ABAC_XML_H__
+#define __ABAC_XML_H__
+
+extern void read_cert(char *filename, char **buf, int *len);
+extern char *my_make_credential(char* rt0, int secs, char* cert, int certlen);
+extern void fatal(const char *str);
+
+extern int init_xmlsec();
+extern int deinit_xmlsec();
+extern char **my_read_credential(char *infile, char **xml);
+
+extern char **get_rt0_from_xml(char *xml);
+extern char *get_keyid_from_xml(char *xml);
+extern long get_validity_from_xml(char *xml);
+
+#endif /* __ABAC_XML_H__ */
+
+
Index: libabac/compat/readpassphrase.c
===================================================================
--- libabac/compat/readpassphrase.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
+++ libabac/compat/readpassphrase.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -0,0 +1,209 @@
+/*	$OpenBSD: readpassphrase.c,v 1.23 2010/05/14 13:30:34 millert Exp $	*/
+
+/*
+ * Copyright (c) 2000-2002, 2007, 2010
+ *	Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */
+
+/**
+ * Tom Carroll <thomas.carroll@pnnl.gov>
+ *
+ * Properly handled tcsetattr and SIGTTOU
+ */
+
+#ifndef HAVE_READPASSPHRASE
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#include <signal.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include "compat/readpassphrase.h"
+
+#ifndef TCSASOFT
+# define TCSASOFT 0
+#endif
+
+#ifndef NSIG
+# ifdef _NSIG
+#  define NSIG _NSIG
+# else
+#  define NSIG 128
+# endif
+#endif
+
+static volatile sig_atomic_t signo[NSIG];
+
+static void handler(int);
+
+char *
+readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
+{
+	ssize_t nr;
+	int input, output, save_errno, i, need_restart;
+	char ch, *p, *end;
+	struct termios term, oterm;
+	struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
+	struct sigaction savetstp, savettin, savettou, savepipe;
+
+	/* I suppose we could alloc on demand in this case (XXX). */
+	if (bufsiz == 0) {
+		errno = EINVAL;
+		return(NULL);
+	}
+
+restart:
+	for (i = 0; i < NSIG; i++)
+		signo[i] = 0;
+	nr = -1;
+	save_errno = 0;
+	need_restart = 0;
+	/*
+	 * Read and write to /dev/tty if available.  If not, read from
+	 * stdin and write to stderr unless a tty is required.
+	 */
+	if ((flags & RPP_STDIN) ||
+	    (input = output = open(_PATH_TTY, O_RDWR)) == -1) {
+		if (flags & RPP_REQUIRE_TTY) {
+			errno = ENOTTY;
+			return(NULL);
+		}
+		input = STDIN_FILENO;
+		output = STDERR_FILENO;
+	}
+
+	/*
+	 * Turn off echo if possible.
+	 * If we are using a tty but are not the foreground pgrp this will
+	 * generate SIGTTOU, so do it *before* installing the signal handlers.
+	 */
+	if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
+		memcpy(&term, &oterm, sizeof(term));
+		if (!(flags & RPP_ECHO_ON))
+			term.c_lflag &= ~(ECHO | ECHONL);
+#ifdef VSTATUS
+		if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
+			term.c_cc[VSTATUS] = _POSIX_VDISABLE;
+#endif
+		(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
+	} else {
+		memset(&term, 0, sizeof(term));
+		term.c_lflag |= ECHO;
+		memset(&oterm, 0, sizeof(oterm));
+		oterm.c_lflag |= ECHO;
+	}
+
+	/*
+	 * Catch signals that would otherwise cause the user to end
+	 * up with echo turned off in the shell.  Don't worry about
+	 * things like SIGXCPU and SIGVTALRM for now.
+	 */
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;		/* don't restart system calls */
+	sa.sa_handler = handler;
+	(void)sigaction(SIGALRM, &sa, &savealrm);
+	(void)sigaction(SIGHUP, &sa, &savehup);
+	(void)sigaction(SIGINT, &sa, &saveint);
+	(void)sigaction(SIGPIPE, &sa, &savepipe);
+	(void)sigaction(SIGQUIT, &sa, &savequit);
+	(void)sigaction(SIGTERM, &sa, &saveterm);
+	(void)sigaction(SIGTSTP, &sa, &savetstp);
+	(void)sigaction(SIGTTIN, &sa, &savettin);
+	(void)sigaction(SIGTTOU, &sa, &savettou);
+
+	if (!(flags & RPP_STDIN))
+		(void)write(output, prompt, strlen(prompt));
+	end = buf + bufsiz - 1;
+	p = buf;
+	while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
+		if (p < end) {
+			if ((flags & RPP_SEVENBIT))
+				ch &= 0x7f;
+			if (isalpha(ch)) {
+				if ((flags & RPP_FORCELOWER))
+					ch = (char)tolower(ch);
+				if ((flags & RPP_FORCEUPPER))
+					ch = (char)toupper(ch);
+			}
+			*p++ = ch;
+		}
+	}
+	*p = '\0';
+	save_errno = errno;
+	if (!(term.c_lflag & ECHO))
+		(void)write(output, "\n", 1);
+
+	/* Restore old terminal settings and signals. */
+	if (memcmp(&term, &oterm, sizeof(term)) != 0) {
+		sigset_t ttou_sigset, old_sigset;
+		sigemptyset(&ttou_sigset);
+		sigaddset(&ttou_sigset, SIGTTOU);
+		sigprocmask(SIG_BLOCK, &ttou_sigset, &old_sigset);
+		while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
+		    errno == EINTR)
+			continue;
+		sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+	}
+	(void)sigaction(SIGALRM, &savealrm, NULL);
+	(void)sigaction(SIGHUP, &savehup, NULL);
+	(void)sigaction(SIGINT, &saveint, NULL);
+	(void)sigaction(SIGQUIT, &savequit, NULL);
+	(void)sigaction(SIGPIPE, &savepipe, NULL);
+	(void)sigaction(SIGTERM, &saveterm, NULL);
+	(void)sigaction(SIGTSTP, &savetstp, NULL);
+	(void)sigaction(SIGTTIN, &savettin, NULL);
+	(void)sigaction(SIGTTOU, &savettou, NULL);
+	if (input != STDIN_FILENO)
+		(void)close(input);
+
+	/*
+	 * If we were interrupted by a signal, resend it to ourselves
+	 * now that we have restored the signal handlers.
+	 */
+	for (i = 0; i < NSIG; i++) {
+		if (signo[i]) {
+			kill(getpid(), i);
+			switch (i) {
+			case SIGTSTP:
+			case SIGTTIN:
+			case SIGTTOU:
+				need_restart = 1;
+			}
+		}
+	}
+	if (need_restart)
+		goto restart;
+
+	return(nr == -1 ? errno = save_errno, NULL : buf);
+}
+
+static void handler(int s)
+{
+
+	signo[s] = 1;
+}
+
+#endif /* ! HAVE_READPASSPHRASE */
Index: libabac/compat/readpassphrase.h
===================================================================
--- libabac/compat/readpassphrase.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
+++ libabac/compat/readpassphrase.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -0,0 +1,42 @@
+/*	$OpenBSD: readpassphrase.h,v 1.5 2003/06/17 21:56:23 millert Exp $	*/
+
+/*
+ * Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+#ifndef _READPASSPHRASE_H_
+#define _READPASSPHRASE_H_
+
+#ifndef HAVE_READPASSPHRASE
+
+#define RPP_ECHO_OFF    0x00		/* Turn off echo (default). */
+#define RPP_ECHO_ON     0x01		/* Leave echo on. */
+#define RPP_REQUIRE_TTY 0x02		/* Fail if there is no tty. */
+#define RPP_FORCELOWER  0x04		/* Force input to lower case. */
+#define RPP_FORCEUPPER  0x08		/* Force input to upper case. */
+#define RPP_SEVENBIT    0x10		/* Strip the high bit from input. */
+#define RPP_STDIN       0x20		/* Read from stdin, not /dev/tty */
+
+#include <stddef.h>
+
+char * readpassphrase(const char *, char *, size_t, int);
+
+#endif /* ! HAVE_READPASSPHRASE */
+
+#endif /* !_READPASSPHRASE_H_ */
Index: libabac/libabac_common.h
===================================================================
--- libabac/libabac_common.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
+++ libabac/libabac_common.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -0,0 +1,36 @@
+#ifndef __LIBABAC_COMMON_H__
+#define __LIBABAC_COMMON_H__
+
+#include "abac.h"
+
+void libabac_init();
+
+/* helper functions */
+
+// generate a random serial (8byte)
+unsigned char *abac_generate_serial();
+
+// returns true if a name starts with a letter and 
+//  is otherwise alphanumeric
+int abac_clean_name(char *string);
+
+// return a PEM blob of the ID cert
+abac_chunk_t abac_id_in_PEM(abac_id_t *id);
+
+// return a PEM blob of the ID/PKEY 
+int abac_id_PEM(abac_id_t *id, abac_chunk_t *);
+
+// return a blob of the Attribute cert
+abac_chunk_t abac_attribute_cert(abac_attribute_t *ptr);
+
+// called by abac_verifier 
+int init_xmlsec();
+int deinit_xmlsec();
+
+// called by abac_verifier
+int init_openssl();
+int deinit_openssl();
+
+
+#endif /* __LIBABAC_COMMON_H__ */
+
Index: libabac/options.c
===================================================================
--- libabac/options.c	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/options.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -1,2 +1,6 @@
+
+/* options.c */
+
+#include <stdio.h>
 #include <getopt.h>
 #include <stdlib.h>
@@ -10,4 +14,5 @@
         "        --keystore <keystore> \\\n"
         "        --role <keyid.role> --principal <keyid>\n"
+        "        --dump <file>\n"
         "    loads the keystore and runs the query role <-?- principal\n",
         name
@@ -20,8 +25,10 @@
 #define OPT_ROLE        2
 #define OPT_PRINCIPAL   3
+#define OPT_DUMP        4
     struct option options[] = {
         { "keystore",   1, 0, OPT_KEYSTORE  },
         { "role",       1, 0, OPT_ROLE      },
         { "principal",  1, 0, OPT_PRINCIPAL },
+        { "dump",       1, 0, OPT_DUMP },
         { 0 },
     };
@@ -42,4 +49,8 @@
                 opts->principal = strdup(optarg);
                 break;
+            case OPT_DUMP:
+                opts->rulefile = strdup(optarg);
+                break;
+
 
             default:
@@ -48,5 +59,5 @@
     }
 
-    if (!(opts->keystore && opts->role && opts->principal))
+    if (!(opts->keystore && opts->role && opts->principal) && !(opts->rulefile) )
         _usage(argv[0]);
 }
Index: libabac/options.h
===================================================================
--- libabac/options.h	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/options.h	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -10,4 +10,5 @@
     char *role;
     char *principal;
+    char *rulefile;
 } options_t;
 
Index: libabac/prover.c
===================================================================
--- libabac/prover.c	(revision d4b3b529e2089c1d6789e5f0d05d99ff3aa4c533)
+++ libabac/prover.c	(revision c75b2c28006e67279531bed747ab66b8aa312373)
@@ -15,4 +15,21 @@
     abac_context_t *ctx = abac_context_new();
     abac_context_load_directory(ctx, opts.keystore);
+
+    if(opts.rulefile) {
+        FILE *fp=fopen(opts.rulefile,"w+");
+        if(fp) { 
+            abac_credential_t **credentials = abac_context_credentials(ctx);
+            if (credentials != NULL)
+                for (i = 0; credentials[i] != NULL; ++i) {
+                    cred = credentials[i];
+                    fprintf(fp,"%s <- %s\n",
+                            abac_role_string(abac_credential_head(cred)),
+                            abac_role_string(abac_credential_tail(cred))
+                          );
+                }
+            abac_context_credentials_free(credentials);
+            fclose(fp);
+        }
+    }
 
     abac_credential_t **credentials = abac_context_query(ctx,
