Index: creddy/attribute.c
===================================================================
--- creddy/attribute.c	(revision 93549372ed8c4e25241464779d6c6ab6dd0d5671)
+++ creddy/attribute.c	(revision 002b25a3892b412ebe01e57990f553497d477232)
@@ -3,4 +3,5 @@
 
 #include "creddy.h"
+#include "id.h"
 
 #include <termios.h>
@@ -9,93 +10,7 @@
 #define INTERSECTION_SEP " & "
 #define SHA1_LENGTH 40
-/* Size of password memory allocation */
-#define PWLEN 128
-
-/* Callback configuration */
-struct cb_opts {
-    bool use_prompt;	/* Print a prompt to stderr */
-    bool use_echo;	/* If true, turn off input echo on stdin */
-    unsigned int tries;	/* Number of attempts allowed */
-    char prompt[20];	/* The prompt to display if use_echo is true */
-};
-
-chunk_t passphrase_callback(void *user, int try) {
-    /* Get a password from stdin and return it as a chunk_t.  If too many tries
-     * have occurred or there is any other problem, return an empty chunk_t,
-     * which libstrongswan takes as giving up.  The chunk is alloated here
-     * (inside getline), and presumably freed by libstrongswan. User points to
-     * a cb_opts struct, which affects this routine in the obvious ways.
-     */
-    /* Configuration options */
-    struct cb_opts *opts = (struct cb_opts *) user;
-    chunk_t rv = chunk_empty;	/* Return value, starts empty */
-
-    if (try -1 < opts->tries ) {
-	struct termios t;   /* Terminal settings */
-	size_t len = 0;	    /* Length of string from getline */
-	tcflag_t orig = 0;  /* Holds the original local flags (echo in here) */
-
-	if (!opts->use_echo) {
-	    /* Use tc{get,set}attr to turn echo off and restore the intial
-	     * echo settings */
-	    if (!tcgetattr(0, &t)) { 
-		orig = t.c_lflag;
-
-		t.c_lflag &= ~ECHO;
-		if ( tcsetattr(0, TCSANOW, &t) ) { 
-		    perror("Cannot turn off echo"); 
-		    return rv;
-		}
-	    }
-	    else {
-		perror("Cannot turn get attributes to off echo"); 
-		return rv;
-	    }
-	}
-	if (opts->use_prompt) printf("%s", opts->prompt);
-
-	/* Because rv.ptr starts as NULL, getline allocates memory.  The size
-	 * of the allocation returns in rv.len and the size of the string
-	 * (including newline and NUL) is in len.  */
-	if ((rv.ptr = (u_char *) malloc(rv.len = PWLEN))) {
-	    if ( fgets(rv.ptr, rv.len, stdin) ) {
-		/* Readjust the chunk_t's len field to the size of the string
-		 * w/o the newline or NUL */
-		/* would prefer strnlen, but no such luck in FBSD7 or earlier*/
-		size_t len = strlen(rv.ptr);
-
-		if (rv.ptr[len-2] == '\n') rv.len = len-2;
-		else rv.len = len -1;
-	    }
-	    else {
-		/* Read failed.  Deallocate and clear rv */
-		free(rv.ptr);
-		rv = chunk_empty;
-	    }
-	}
-	else {
-	    /* Failed malloc.  Restore rv to empty and return it */
-	    perror("malloc");
-	    rv = chunk_empty;
-	    return rv;
-	}
-
-	if (!opts->use_echo ) {
-	    /* Pop echo beck to its original setting. */
-	    t.c_lflag = orig;
-
-	    if ( tcsetattr(0, TCSANOW, &t) ) 
-		perror("Cannot restore echo setting?"); 
-
-	    if (opts->use_prompt) printf("\n");
-	}
-    }
-    else fprintf(stderr, "Too many tries (%d)", try-1);
-    return rv;
-}
 
 void attribute_main(options_t *opts) {
-    struct cb_opts c_opts = { 1, 0, 3, "Key password:" };
-    int i, role_len = 1;
+    int i, ret, role_len = 1;
 
     if (
@@ -141,7 +56,9 @@
         // otherwise we have a cert
         else {
-            certificate_t *subject = cert_from_file(cur->cert);
-            cur->id = cert_keyid(subject);
-            DESTROY_IF(subject);
+            creddy_id_t *subject = creddy_id_from_file(cur->cert);
+            if (subject == NULL)
+                errx(1, "Can't load subject cert from %s", cur->cert);
+            cur->id = xstrdup(creddy_id_keyid(subject));
+            creddy_id_free(subject);
         }
 
@@ -186,19 +103,16 @@
     }
 
-    chunk_t pw = chunk_empty;
-    // load signer key
-    private_key_t *key = lib->creds->create(lib->creds,
-        CRED_PRIVATE_KEY, KEY_RSA,
-        BUILD_FROM_FILE, opts->key,
-	/* Ask for password if the key's encrypted */
-	BUILD_PASSPHRASE_CALLBACK, passphrase_callback, &c_opts, 
-        BUILD_END
-    );
-    if (key == NULL)
-        errx(1, "can't open private key file %s", opts->key);
+    // issuer
+    creddy_id_t *issuer = creddy_id_from_file(opts->issuer);
+    if (issuer == NULL)
+        errx(1, "Can't load cert from %s", opts->issuer);
+
+    // private key
+    ret = creddy_id_load_privkey(issuer, opts->key);
+    if (!ret)
+        errx(1, "Can't load private key from %s", opts->key);
 
     // get the keyids
-    certificate_t *issuer = cert_from_file(opts->issuer);
-    char *issuer_id = cert_keyid(issuer);
+    char *issuer_id = creddy_id_keyid(issuer);
 
     // build the role encoding
@@ -223,6 +137,4 @@
     }
 
-    free(issuer_id);
-
     // create attribute cert
     time_t not_before = time(NULL);
@@ -232,11 +144,11 @@
     certificate_t *attr_cert = lib->creds->create(lib->creds,
         CRED_CERTIFICATE, CERT_X509_AC,
-        BUILD_CERT, issuer,
+        BUILD_CERT, creddy_id_cert(issuer),
         BUILD_NOT_BEFORE_TIME, not_before,
         BUILD_NOT_AFTER_TIME, not_after,
         BUILD_SERIAL, serial,
         BUILD_IETF_GROUP_ATTR, role_encoding,
-        BUILD_SIGNING_CERT, issuer,
-        BUILD_SIGNING_KEY, key,
+        BUILD_SIGNING_CERT, creddy_id_cert(issuer),
+        BUILD_SIGNING_KEY, creddy_id_privkey(issuer),
         BUILD_END
     );
@@ -256,5 +168,5 @@
     free(serial.ptr);
     DESTROY_IF(attr_cert);
-    DESTROY_IF(issuer);
-    DESTROY_IF(key);
+    free(encoding.ptr);
+    creddy_id_free(issuer);
 }
Index: creddy/id.c
===================================================================
--- creddy/id.c	(revision 002b25a3892b412ebe01e57990f553497d477232)
+++ creddy/id.c	(revision 002b25a3892b412ebe01e57990f553497d477232)
@@ -0,0 +1,186 @@
+#include <assert.h>
+#include <termios.h>
+
+#include "creddy.h"
+#include "id.h"
+
+/* Size of password memory allocation */
+#define PWLEN 128
+
+//
+// ID object
+//
+struct _creddy_id_t {
+    char *keyid;
+    char *cn;
+    certificate_t *cert;
+    private_key_t *key;
+}; 
+
+/* Callback configuration */
+struct cb_opts {
+    bool use_prompt;	/* Print a prompt to stderr */
+    bool use_echo;	/* If true, turn off input echo on stdin */
+    unsigned int tries;	/* Number of attempts allowed */
+    char prompt[20];	/* The prompt to display if use_echo is true */
+};
+
+static chunk_t _passphrase_callback(void *user, int try);
+
+/**
+ * Load an ID cert from a file.
+ */
+creddy_id_t *creddy_id_from_file(char *filename) {
+    certificate_t *cert = lib->creds->create(lib->creds,
+        CRED_CERTIFICATE, CERT_X509,
+        BUILD_FROM_FILE, filename,
+        BUILD_X509_FLAG, X509_AA,
+        BUILD_END
+    );
+
+    if (cert == NULL)
+        return NULL;
+
+    creddy_id_t *id = xmalloc(sizeof(creddy_id_t));
+    id->keyid = NULL;
+    id->cn = NULL;
+    id->cert = cert;
+    id->key = NULL;
+
+    // get the keyid
+    x509_t *x509 = (x509_t *)cert;
+    chunk_t keyid = x509->get_subjectKeyIdentifier(x509);
+    chunk_t string = chunk_to_hex(keyid, NULL, 0);
+    id->keyid = string.ptr;
+
+    // TODO get CN
+
+    return id;
+}
+
+int creddy_id_load_privkey(creddy_id_t *id, char *filename) {
+    struct cb_opts c_opts = { 1, 0, 3, "Key password:" };
+
+    assert(id != NULL);
+
+    // load signer key
+    private_key_t *key = lib->creds->create(lib->creds,
+        CRED_PRIVATE_KEY, KEY_RSA,
+        BUILD_FROM_FILE, filename,
+	/* Ask for password if the key's encrypted */
+	BUILD_PASSPHRASE_CALLBACK, _passphrase_callback, &c_opts, 
+        BUILD_END
+    );
+    if (key == NULL)
+        return 0;
+
+    id->key = key;
+}
+
+char *creddy_id_keyid(creddy_id_t *id) {
+    assert(id != NULL);
+
+    return id->keyid;
+}
+
+certificate_t *creddy_id_cert(creddy_id_t *id) {
+    assert(id != NULL);
+
+    return id->cert;
+}
+
+private_key_t *creddy_id_privkey(creddy_id_t *id) {
+    assert(id != NULL);
+
+    return id->key;
+}
+
+void creddy_id_free(creddy_id_t *id) {
+    if (id == NULL)
+        return;
+
+    DESTROY_IF(id->cert);
+    DESTROY_IF(id->key);
+
+    free(id->keyid);
+    free(id);
+}
+
+//
+// Helper functions below
+//
+
+static chunk_t _passphrase_callback(void *user, int try) {
+    /* Get a password from stdin and return it as a chunk_t.  If too many tries
+     * have occurred or there is any other problem, return an empty chunk_t,
+     * which libstrongswan takes as giving up.  The chunk is alloated here
+     * (inside getline), and presumably freed by libstrongswan. User points to
+     * a cb_opts struct, which affects this routine in the obvious ways.
+     */
+    /* Configuration options */
+    struct cb_opts *opts = (struct cb_opts *) user;
+    chunk_t rv = chunk_empty;	/* Return value, starts empty */
+
+    if (try -1 < opts->tries ) {
+	struct termios t;   /* Terminal settings */
+	size_t len = 0;	    /* Length of string from getline */
+	tcflag_t orig = 0;  /* Holds the original local flags (echo in here) */
+
+	if (!opts->use_echo) {
+	    /* Use tc{get,set}attr to turn echo off and restore the intial
+	     * echo settings */
+	    if (!tcgetattr(0, &t)) { 
+		orig = t.c_lflag;
+
+		t.c_lflag &= ~ECHO;
+		if ( tcsetattr(0, TCSANOW, &t) ) { 
+		    perror("Cannot turn off echo"); 
+		    return rv;
+		}
+	    }
+	    else {
+		perror("Cannot turn get attributes to off echo"); 
+		return rv;
+	    }
+	}
+	if (opts->use_prompt) printf("%s", opts->prompt);
+
+	/* Because rv.ptr starts as NULL, getline allocates memory.  The size
+	 * of the allocation returns in rv.len and the size of the string
+	 * (including newline and NUL) is in len.  */
+	if ((rv.ptr = (u_char *) malloc(rv.len = PWLEN))) {
+	    if ( fgets(rv.ptr, rv.len, stdin) ) {
+		/* Readjust the chunk_t's len field to the size of the string
+		 * w/o the newline or NUL */
+		/* would prefer strnlen, but no such luck in FBSD7 or earlier*/
+		size_t len = strlen(rv.ptr);
+
+		if (rv.ptr[len-2] == '\n') rv.len = len-2;
+		else rv.len = len -1;
+	    }
+	    else {
+		/* Read failed.  Deallocate and clear rv */
+		free(rv.ptr);
+		rv = chunk_empty;
+	    }
+	}
+	else {
+	    /* Failed malloc.  Restore rv to empty and return it */
+	    perror("malloc");
+	    rv = chunk_empty;
+	    return rv;
+	}
+
+	if (!opts->use_echo ) {
+	    /* Pop echo beck to its original setting. */
+	    t.c_lflag = orig;
+
+	    if ( tcsetattr(0, TCSANOW, &t) ) 
+		perror("Cannot restore echo setting?"); 
+
+	    if (opts->use_prompt) printf("\n");
+	}
+    }
+    else fprintf(stderr, "Too many tries (%d)", try-1);
+    return rv;
+}
Index: creddy/id.h
===================================================================
--- creddy/id.h	(revision 002b25a3892b412ebe01e57990f553497d477232)
+++ creddy/id.h	(revision 002b25a3892b412ebe01e57990f553497d477232)
@@ -0,0 +1,21 @@
+#ifndef __ID_H__
+#define __ID_H__
+
+#include <credentials/certificates/certificate.h>
+#include <credentials/certificates/x509.h>
+#include <credentials/keys/private_key.h>
+
+#include "libcreddy.h"
+
+//
+// Private API
+//
+
+// get the cert from the ID
+certificate_t *creddy_id_cert(creddy_id_t *id);
+
+// get the private key from the ID
+// will return NULL if no key has been loaded
+private_key_t *creddy_id_privkey(creddy_id_t *id);
+
+#endif /* __ID_H__ */
Index: creddy/libcreddy.h
===================================================================
--- creddy/libcreddy.h	(revision 002b25a3892b412ebe01e57990f553497d477232)
+++ creddy/libcreddy.h	(revision 002b25a3892b412ebe01e57990f553497d477232)
@@ -0,0 +1,23 @@
+#ifndef __LIBCREDDY_H__
+#define __LIBCREDDY_H__
+
+/**
+ * Creddy identifiers.
+ */
+
+typedef struct _creddy_id_t creddy_id_t;
+
+// create an ID from an X.509 certificate
+creddy_id_t *creddy_id_from_file(char *filename);
+
+// load an X.509 private key for an from a file
+// handles keys with a password
+int creddy_id_load_privkey(creddy_id_t *id, char *filename);
+
+// get the SHA1 keyid, pointer is valid for the lifetime of the object
+char *creddy_id_keyid(creddy_id_t *id);
+
+// destroy the id
+void creddy_id_free(creddy_id_t *id);
+
+#endif /* __LIBCREDDY_H__ */
