Index: libabac/abac.hh
===================================================================
--- libabac/abac.hh	(revision a70acc99bc512a43f30e6c2114b80fe176c960e7)
+++ libabac/abac.hh	(revision 461541aae6382bb58dfb3c4a1679d2d48e8f9e64)
@@ -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;
+    };
 }
 
