Index: creddy/attribute.c
===================================================================
--- creddy/attribute.c	(revision 612ca14ea93433dd17d56819bd994af1cab79043)
+++ creddy/attribute.c	(revision 39fed7cfca3152c1d7385e267e7873c003b07590)
@@ -140,5 +140,5 @@
     time_t not_before = time(NULL);
     time_t not_after = not_before + opts->validity * 3600 * 60 * 60;
-    chunk_t serial = generate_serial();
+    chunk_t serial = creddy_generate_serial();
 
     certificate_t *attr_cert = lib->creds->create(lib->creds,
Index: creddy/creddy.c
===================================================================
--- creddy/creddy.c	(revision 612ca14ea93433dd17d56819bd994af1cab79043)
+++ creddy/creddy.c	(revision 39fed7cfca3152c1d7385e267e7873c003b07590)
@@ -328,2 +328,19 @@
     return cert;
 }
+
+chunk_t creddy_generate_serial() {
+    chunk_t serial = chunk_empty;
+
+    // create a serial (stolen from strongswan pki)
+    rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+    if (!rng)
+        errx(1, "no random number generator");
+
+    rng->allocate_bytes(rng, 8, &serial);
+    while (serial.ptr[0] == 0)
+        // don't get leading 0's
+        rng->get_bytes(rng, 1, serial.ptr);
+    rng->destroy(rng);
+
+    return serial;
+}
Index: creddy/creddy.h
===================================================================
--- creddy/creddy.h	(revision 612ca14ea93433dd17d56819bd994af1cab79043)
+++ creddy/creddy.h	(revision 39fed7cfca3152c1d7385e267e7873c003b07590)
@@ -48,5 +48,5 @@
 
 // generate a random serial
-chunk_t generate_serial();
+chunk_t creddy_generate_serial();
 
 void usage(options_t *opts);
@@ -62,14 +62,3 @@
 void verify_main(options_t *opts);
 
-#define CREDDY_SUCCESS                      0
-#define CREDDY_GENERATE_INVALID_CN          -1
-#define CREDDY_GENERATE_INVALID_VALIDITY    -2
-
-/**
- * Generate an ID cert / private key pair. Returns one of the error
- * codes above. Validity is in days. Output is in ${cn}_ID.pem and
- * ${cn}_private.der.
- */
-int creddy_generate(char *cn, int validity);
-
 #endif /* __CREDDY_H__ */
Index: creddy/generate.c
===================================================================
--- creddy/generate.c	(revision 612ca14ea93433dd17d56819bd994af1cab79043)
+++ creddy/generate.c	(revision 39fed7cfca3152c1d7385e267e7873c003b07590)
@@ -4,17 +4,17 @@
 
 #include "creddy.h"
-
-#define KEY_SUFFIX  "_private.pem"
-#define CERT_SUFFIX "_ID.pem"
-
-static private_key_t *_generate_key(char *filename);
-static void _generate_cert(char *filename, private_key_t *private, char *cn, int validity);
+#include "libcreddy.h"
 
 void generate_main(options_t *opts) {
+    int ret, fd;
+    creddy_id_t *id;
+    char *filename;
+    FILE *out;
+
     printf("Generating key, this will take a while. Create entropy!\n");
     printf("    - move the mouse\n");
     printf("    - generate disk activity (run find)\n");
 
-    int ret = creddy_generate(opts->cn, opts->validity);
+    ret = creddy_id_generate(&id, opts->cn, opts->validity);
 
     if (ret == CREDDY_GENERATE_INVALID_CN) {
@@ -26,177 +26,26 @@
         usage(opts);
     }
-}
+    // in both above cases: usage(opts) exits
 
-int creddy_generate(char *cn, int validity) {
-    private_key_t *key;
-    chunk_t encoding;
+    //
+    // success!
+    //
 
-    if (cn == NULL || !clean_name(cn))
-        return CREDDY_GENERATE_INVALID_CN;
+    // write the cert
+    filename = creddy_id_cert_filename(id);
+    out = fopen(filename, "w");
+    creddy_id_write_cert(id, out);
+    fclose(out);
+    free(filename);
 
-    if (validity < 0)
-        return CREDDY_GENERATE_INVALID_VALIDITY;
-
-    int cn_len = strlen(cn);
-
-    // key output filename: "${cn}_private.pem"
-    char *filename = xmalloc(cn_len + sizeof(KEY_SUFFIX));
-    memcpy(filename, cn, cn_len);
-
-    memcpy(filename + cn_len, KEY_SUFFIX, sizeof(KEY_SUFFIX));
-    key = _generate_key(filename);
-
-    // cert filename: ${cn}_ID.pem
-    memcpy(filename + cn_len, CERT_SUFFIX, sizeof(CERT_SUFFIX));
-    _generate_cert(filename, key, cn, validity);
-
-    free(filename);
-    DESTROY_IF(key);
-
-    return CREDDY_SUCCESS;
-}
-
-static private_key_t *_generate_key(char *filename) {
-    private_key_t *key;
-    int ret;
-    chunk_t encoding;
-
-    // generate the key
-    key = lib->creds->create(
-        lib->creds,
-        CRED_PRIVATE_KEY, KEY_RSA,
-        BUILD_KEY_SIZE, 2048,
-        BUILD_END
-    );
-    if (key == NULL)
-        errx(1, "Key generation failed");
-
-    // get the key encoding
-    ret = key->get_encoding(key, KEY_PRIV_PEM, &encoding);
-    if (!ret)
-        errx(1, "Couldn't encode private key");
-
-    // write it to a file (with mode 600)
-    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+    // write the key
+    filename = creddy_id_privkey_filename(id);
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); // mode 600
     if (fd < 0)
-        err(1, "Couldn't open %s for writing private key", filename);
-
-    ret = write(fd, encoding.ptr, encoding.len);
-    if (ret < encoding.len)
-        errx(1, "Couldn't write all the bytes of the private key");
-
-    close(fd);
-
-    free(encoding.ptr);
-
-    return key;
-}
-
-static char *_create_dn(char *cn) {
-
-#define DN "cn="
-
-    char *dn = xmalloc(sizeof(DN) + strlen(cn));
-    memcpy(dn, DN, sizeof(DN));
-    strcat(dn, cn);
-
-    return dn;
-}
-
-#define BYTES_PER_LINE 64
-
-// thx libstrongswan
-static void _encode_base64(char *filename, chunk_t encoding) {
-    int start;
-
-    chunk_t b64 = chunk_to_base64(encoding, NULL);
-
-    FILE *out = fopen(filename, "w");
-    if (out == NULL)
-        err(1, "couldn't open %s for writing", filename);
-
-    fprintf(out, "-----BEGIN CERTIFICATE-----\n");
-
-    for (start = 0; start < b64.len; start += BYTES_PER_LINE) {
-        int left = b64.len - start;
-        int len = left < BYTES_PER_LINE ? left : BYTES_PER_LINE;
-        fwrite(b64.ptr + start, len, 1, out);
-        fprintf(out, "\n");
-    }
-
-    fprintf(out, "-----END CERTIFICATE-----\n");
+        err(1, "Can't open private key file %s", filename);
+    out = fdopen(fd, "w");
+    creddy_id_write_privkey(id, out);
     fclose(out);
 
-    free(b64.ptr);
+    creddy_id_free(id);
 }
-
-static void _generate_cert(char *filename, private_key_t *private, char *cn, int validity) {
-    // build the DN
-    char *dn_string = _create_dn(cn);
-    identification_t *id = identification_create_from_string(dn_string);
-    if (id == NULL)
-        errx(1, "couldn't create ID from DN %s", dn_string);
-    free(dn_string);
-
-    // get the public key
-    public_key_t *public = private->get_public_key(private);
-    if (public == NULL)
-        errx(1, "couldn't get public key from private key");
-
-    // create a serial (stolen from strongswan pki)
-    rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
-    if (!rng)
-        errx(1, "no random number generator");
-
-    // random serial
-    chunk_t serial = generate_serial();
-
-    // validity period
-    time_t not_before = time(NULL);
-    time_t not_after = not_before + validity * 24 * 60 * 60;
-
-    // create!
-    certificate_t *cert = lib->creds->create(lib->creds,
-        CRED_CERTIFICATE, CERT_X509,
-        BUILD_SIGNING_KEY, private,
-        BUILD_PUBLIC_KEY, public,
-        BUILD_SUBJECT, id,
-        BUILD_NOT_BEFORE_TIME, not_before,
-        BUILD_NOT_AFTER_TIME, not_after,
-        BUILD_SERIAL, serial,
-        BUILD_DIGEST_ALG, HASH_SHA1,
-        BUILD_X509_FLAG, X509_CA,
-        BUILD_PATHLEN, X509_NO_PATH_LEN_CONSTRAINT,
-        BUILD_END
-    );
-    if (cert == NULL)
-        errx(1, "couldn't build cert :(");
-
-    chunk_t encoding = cert->get_encoding(cert);
-
-    // sigh
-    _encode_base64(filename, encoding);
-
-    DESTROY_IF(id);
-    DESTROY_IF(cert);
-    DESTROY_IF(public);
-    free(encoding.ptr);
-    free(serial.ptr);
-}
-
-chunk_t generate_serial() {
-    chunk_t serial = chunk_empty;
-
-    // create a serial (stolen from strongswan pki)
-    rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
-    if (!rng)
-        errx(1, "no random number generator");
-
-    rng->allocate_bytes(rng, 8, &serial);
-    while (serial.ptr[0] == 0)
-        // don't get leading 0's
-        rng->get_bytes(rng, 1, serial.ptr);
-    rng->destroy(rng);
-
-    return serial;
-}
Index: creddy/id.c
===================================================================
--- creddy/id.c	(revision 612ca14ea93433dd17d56819bd994af1cab79043)
+++ creddy/id.c	(revision 39fed7cfca3152c1d7385e267e7873c003b07590)
@@ -1,8 +1,12 @@
 #include <assert.h>
+#include <err.h>
 #include <termios.h>
+#include <time.h>
 
 #include "creddy.h"
 #include "id.h"
 
+#define KEY_SUFFIX  "_private.pem"
+#define CERT_SUFFIX "_ID.pem"
 /* Size of password memory allocation */
 #define PWLEN 128
@@ -26,5 +30,9 @@
 };
 
+static char *_get_keyid(certificate_t *cert);
 static chunk_t _passphrase_callback(void *user, int try);
+static private_key_t *_generate_key(void);
+static certificate_t *_generate_cert(private_key_t *private, char *cn, int validity);
+static void _encode_base64(FILE *out, chunk_t encoding);
 
 /**
@@ -48,9 +56,5 @@
     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;
+    id->keyid = _get_keyid(id->cert);
 
     // TODO get CN
@@ -59,4 +63,8 @@
 }
 
+
+/**
+ * Load private key for a cert.
+ */
 int creddy_id_load_privkey(creddy_id_t *id, char *filename) {
     struct cb_opts c_opts = { 1, 0, 3, "Key password:" };
@@ -76,4 +84,26 @@
 
     id->key = key;
+    return 1;
+}
+
+/**
+ * Generate an ID with the specified CN and validity.
+ */
+int creddy_id_generate(creddy_id_t **ret, char *cn, int validity) {
+    if (cn == NULL || !clean_name(cn))
+        return CREDDY_GENERATE_INVALID_CN;
+
+    if (validity < 0)
+        return CREDDY_GENERATE_INVALID_VALIDITY;
+
+    creddy_id_t *id = xmalloc(sizeof(creddy_id_t));
+
+    id->cn = xstrdup(cn);
+    id->key = _generate_key();
+    id->cert = _generate_cert(id->key, cn, validity);
+    id->keyid = _get_keyid(id->cert);
+
+    *ret = id;
+    return CREDDY_SUCCESS;
 }
 
@@ -94,4 +124,63 @@
 
     return id->key;
+}
+
+/**
+ * Get the default filename for the cert. Value must be freed by caller.
+ */
+char *creddy_id_cert_filename(creddy_id_t *id) {
+    assert(id != NULL);
+    assert(id->cn != NULL);
+
+    // malloc the filename
+    int len = strlen(id->cn) + strlen(CERT_SUFFIX) + 1;
+    char *filename = xmalloc(len);
+    sprintf(filename, "%s" CERT_SUFFIX, id->cn);
+
+    return filename;
+}
+
+/**
+ * Write the ID cert to an open file pointer.
+ */
+void creddy_id_write_cert(creddy_id_t *id, FILE *out) {
+    assert(id != NULL);
+
+    chunk_t encoding = id->cert->get_encoding(id->cert);
+    _encode_base64(out, encoding);
+    free(encoding.ptr);
+}
+
+/**
+ * Default private key filename. Value must be freed by caller.
+ */
+char *creddy_id_privkey_filename(creddy_id_t *id) {
+    assert(id != NULL);
+    assert(id->cn != NULL);
+
+    // malloc the filename
+    int len = strlen(id->cn) + strlen(KEY_SUFFIX) + 1;
+    char *filename = xmalloc(len);
+    sprintf(filename, "%s" KEY_SUFFIX, id->cn);
+
+    return filename;
+}
+
+/**
+ * Write the private key to a file.
+ */
+void creddy_id_write_privkey(creddy_id_t *id, FILE *out) {
+    int ret;
+    chunk_t encoding;
+
+    assert(id != NULL);
+
+    ret = id->key->get_encoding(id->key, KEY_PRIV_PEM, &encoding);
+    if (!ret)
+        errx(1, "Couldn't encode private key");
+
+    fwrite(encoding.ptr, encoding.len, 1, out);
+
+    free(encoding.ptr);
 }
 
@@ -110,4 +199,12 @@
 // Helper functions below
 //
+
+static char *_get_keyid(certificate_t *cert) {
+    // 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);
+    return (char *)string.ptr;
+}
 
 static chunk_t _passphrase_callback(void *user, int try) {
@@ -185,2 +282,106 @@
     return rv;
 }
+
+/**
+ * Generate a private key.
+ */
+static private_key_t *_generate_key(void) {
+    private_key_t *key;
+
+    // generate the key
+    key = lib->creds->create(
+        lib->creds,
+        CRED_PRIVATE_KEY, KEY_RSA,
+        BUILD_KEY_SIZE, 2048,
+        BUILD_END
+    );
+    if (key == NULL)
+        errx(1, "Key generation failed");
+
+    return key;
+}
+
+static char *_create_dn(char *cn) {
+
+#define DN "cn="
+
+    char *dn = xmalloc(sizeof(DN) + strlen(cn));
+    memcpy(dn, DN, sizeof(DN));
+    strcat(dn, cn);
+
+    return dn;
+}
+
+/**
+ * Generate certificate.
+ */
+static certificate_t *_generate_cert(private_key_t *private, char *cn, int validity) {
+    // build the DN
+    char *dn_string = _create_dn(cn);
+    identification_t *id = identification_create_from_string(dn_string);
+    if (id == NULL)
+        errx(1, "couldn't create ID from DN %s", dn_string);
+    free(dn_string);
+
+    // get the public key
+    public_key_t *public = private->get_public_key(private);
+    if (public == NULL)
+        errx(1, "couldn't get public key from private key");
+
+    // create a serial (stolen from strongswan pki)
+    rng_t *rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+    if (!rng)
+        errx(1, "no random number generator");
+
+    // random serial
+    chunk_t serial = creddy_generate_serial();
+
+    // validity period
+    time_t not_before = time(NULL);
+    time_t not_after = not_before + validity * 24 * 60 * 60;
+
+    // create!
+    certificate_t *cert = lib->creds->create(lib->creds,
+        CRED_CERTIFICATE, CERT_X509,
+        BUILD_SIGNING_KEY, private,
+        BUILD_PUBLIC_KEY, public,
+        BUILD_SUBJECT, id,
+        BUILD_NOT_BEFORE_TIME, not_before,
+        BUILD_NOT_AFTER_TIME, not_after,
+        BUILD_SERIAL, serial,
+        BUILD_DIGEST_ALG, HASH_SHA1,
+        BUILD_X509_FLAG, X509_CA,
+        BUILD_PATHLEN, X509_NO_PATH_LEN_CONSTRAINT,
+        BUILD_END
+    );
+    if (cert == NULL)
+        errx(1, "couldn't build cert :(");
+
+    DESTROY_IF(id);
+    DESTROY_IF(public);
+    free(serial.ptr);
+
+    return cert;
+}
+
+#define BYTES_PER_LINE 64
+
+// thx libstrongswan
+static void _encode_base64(FILE *out, chunk_t encoding) {
+    int start;
+
+    chunk_t b64 = chunk_to_base64(encoding, NULL);
+
+    fprintf(out, "-----BEGIN CERTIFICATE-----\n");
+
+    for (start = 0; start < b64.len; start += BYTES_PER_LINE) {
+        int left = b64.len - start;
+        int len = left < BYTES_PER_LINE ? left : BYTES_PER_LINE;
+        fwrite(b64.ptr + start, len, 1, out);
+        fprintf(out, "\n");
+    }
+
+    fprintf(out, "-----END CERTIFICATE-----\n");
+
+    free(b64.ptr);
+}
Index: creddy/libcreddy.h
===================================================================
--- creddy/libcreddy.h	(revision 612ca14ea93433dd17d56819bd994af1cab79043)
+++ creddy/libcreddy.h	(revision 39fed7cfca3152c1d7385e267e7873c003b07590)
@@ -1,4 +1,10 @@
 #ifndef __LIBCREDDY_H__
 #define __LIBCREDDY_H__
+
+#include <stdio.h>
+
+#define CREDDY_SUCCESS                      0
+#define CREDDY_GENERATE_INVALID_CN          -1
+#define CREDDY_GENERATE_INVALID_VALIDITY    -2
 
 /**
@@ -15,6 +21,25 @@
 int creddy_id_load_privkey(creddy_id_t *id, char *filename);
 
+// generate an ID
+// returns one of CREDDY_SUCCESS or CREDDY_GENERATE_* (see top)
+int creddy_id_generate(creddy_id_t **ret, char *cn, int validity);
+
 // get the SHA1 keyid, pointer is valid for the lifetime of the object
 char *creddy_id_keyid(creddy_id_t *id);
+
+// default filename for the cert: ${CN}_ID.pem
+// caller must free the returned string
+char *creddy_id_cert_filename(creddy_id_t *id);
+
+// write the cert fo an open file pointer
+void creddy_id_write_cert(creddy_id_t *id, FILE *out);
+
+// default filename for the private key: ${CN}_key.pem
+// caller must free the return value
+char *creddy_id_privkey_filename(creddy_id_t *id);
+
+// write the private key to a file
+// it is recommended that you open this file mode 0600
+void creddy_id_write_privkey(creddy_id_t *id, FILE *out);
 
 // destroy the id
