[Cryptech-Commits] [sw/pkcs11] 05/20: Convert from Cryptlib to libhal. Compiles, not yet tested otherwise.

git at cryptech.is git at cryptech.is
Tue Jul 7 18:26:35 UTC 2015


This is an automated email from the git hooks/post-receive script.

sra at hactrn.net pushed a commit to branch master
in repository sw/pkcs11.

commit 291a2e0b6a37ffcc3325388c5fdad63d8f185130
Author: Rob Austein <sra at hactrn.net>
Date:   Mon Jun 22 20:18:27 2015 -0400

    Convert from Cryptlib to libhal.  Compiles, not yet tested otherwise.
---
 GNUmakefile |   12 +-
 pkcs11.c    | 1620 ++++++++++++++++++-----------------------------------------
 schema.sql  |   53 +-
 3 files changed, 550 insertions(+), 1135 deletions(-)

diff --git a/GNUmakefile b/GNUmakefile
index 9277e8f..e73c757 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -28,15 +28,11 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Change this to "../cryptlib/build" when this code moves to sw/pkcs11/.
-#
-#CRYPTLIB_DIR = ../cryptlib/build
-CRYPTLIB_DIR = ../../../sw/cryptlib/build
-
+LIBHAL_DIR   = ../libhal
 SQLITE3_DIR  = ../sqlite3
 
-CFLAGS	+= -g -I${CRYPTLIB_DIR} -I${SQLITE3_DIR} -fPIC -DENABLE_CRYPTLIB_DEVICE=0 -Wall
-LIBS	:= ${CRYPTLIB_DIR}/libcl.a ${SQLITE3_DIR}/libsqlite3.a
+CFLAGS	+= -g3 -fPIC -Wall -std=c99 -I${LIBHAL_DIR} -I${SQLITE3_DIR}
+LIBS	:= ${LIBHAL_DIR}/libhal.a ${SQLITE3_DIR}/libsqlite3.a
 
 all: libpkcs11.so
 
@@ -63,5 +59,5 @@ libpkcs11.so: pkcs11.so
 
 tags: TAGS
 
-TAGS: *.[ch] ${CRYPTLIB_DIR}/cryptlib.h ${SQLITE3_DIR}/sqlite3.h
+TAGS: *.[ch]
 	etags $^
diff --git a/pkcs11.c b/pkcs11.c
index 4063836..a2e7dfc 100644
--- a/pkcs11.c
+++ b/pkcs11.c
@@ -46,7 +46,7 @@
 
 #include <sqlite3.h>
 
-#include "cryptlib.h"
+#include <hal.h>
 
 /*
  * Magic PKCS #11 macros that must be defined before including
@@ -100,39 +100,6 @@
 #define P11_VERSION_HW_MINOR    0
 
 /*
- * A value that can't possibly be a valid Cryptlib handle.
- */
-
-#ifndef CRYPT_HANDLE_NONE
-#define CRYPT_HANDLE_NONE       (-1)
-#endif
-
-/*
- * Whether to enable hardware (FPGA) support.  This option may go away
- * eventually, once we have enough algorithms implemented in Verilog.
- */
-
-#ifndef ENABLE_CRYPTLIB_DEVICE
-#define ENABLE_CRYPTLIB_DEVICE  1
-#endif
-
-/*
- * Whehter to enable software algorithms.  This is not really an
- * option at the moment, as the code won't run or even build properly
- * if this is disabled.  It's a placeholder to let us flag bits of
- * code that probably should go away if and when we're doing all the
- * crypto algorithms on the FPGA.
- */
-
-#ifndef ENABLE_CRYPTLIB_SOFTWARE
-#define ENABLE_CRYPTLIB_SOFTWARE 1
-#endif
-
-#if !ENABLE_CRYPTLIB_SOFTWARE
-#error Code will not work correctly with software algorithm support disabled
-#endif
-
-/*
  * Debugging control.
  */
 
@@ -150,19 +117,6 @@
 #endif
 
 /*
- * Default name for PKCS #15 keyring.  Can be overriden at runtime by
- * setting PKCS11_KEYRING environment variable.
- *
- * In the long term this probably goes away, as all keys should live
- * behind the Cryptlib hardware interface, but we need something for
- * initial testing.
- */
-
-#ifndef PKCS15_KEYRING
-#define PKCS15_KEYRING ".cryptech-pkcs11.p15"
-#endif
-
-/*
  * Whether to include POSIX-specific features.
  */
 
@@ -183,38 +137,25 @@
  */
 
 /*
- * Cryptlib handles in the session structure are defined via a silly
- * macro so that we can automate initialization and finalization
- * without accidently missing any of the handles.
+ * At present we have no concept of encryption or signature algorithms
+ * in libhal, as we only support RSA and AES.  For PKCS #11 purposes
+ * we can figure out what kind of key we're looking at from attributes
+ * like CKA_KEY_TYPE, so it's just something we look up given the key
+ * object handle.
  *
- * Note that the encryption and decryption cases (other than raw
- * encryption with no symmetric cipher algorithm) will need to use the
- * enveloping API: see pp 61-62, 70-71, 190 of the Cryptlib manual.
- * We may not really need to keep all the contexts around in this case
- * once we've bound them into the envelope, drive off that bridge when
- * we get to it.
+ * At the moment we don't need to keep any signature or digest state
+ * in the session structure, which is good since the current hash
+ * cores don't allow us to extract state anyway.  This makes it
+ * impossible to implement the incremental operations
+ * (C_DigestUpdate(), C_SignUpdate()) but also simplifies our current
+ * task.
  *
- * Syntax: One handle per line, as calls to to-be-defined macros
- * SESSION_CRYPTLIB_CONTEXT() or SESSION_CRYPTLIB_ENVELOPE(), entries
- * separated by semicolons, no semicolon after last entry.
+ * General idea is that we have separate descriptors/handles/state for
+ * each operation that we're allowed to do in parallel, so sign,
+ * verify, digest, encrypt, decrypt, wrapkey, and unwrapkey all need
+ * separate slots in the session structure.  Add these as we go.
  */
 
-#define SESSION_CRYPTLIB_HANDLES                        \
-  SESSION_CRYPTLIB_CONTEXT(sign_key_context);           \
-  SESSION_CRYPTLIB_CONTEXT(sign_digest_context);        \
-  SESSION_CRYPTLIB_CONTEXT(verify_key_context);         \
-  SESSION_CRYPTLIB_CONTEXT(verify_digest_context);      \
-  SESSION_CRYPTLIB_CONTEXT(digest_context)
-
-#if 0
-  SESSION_CRYPTLIB_CONTEXT(encrypt_key_context);
-  SESSION_CRYPTLIB_CONTEXT(encrypt_cipher_context);
-  SESSION_CRYPTLIB_CONTEXT(decrypt_key_context);
-  SESSION_CRYPTLIB_CONTEXT(decrypt_cipher_context);
-  SESSION_CRYPTLIB_ENVELOPE(encrypt_envelope);
-  SESSION_CRYPTLIB_ENVELOPE(decrypt_envelope);
-#endif
-
 typedef struct p11_session {
   CK_SESSION_HANDLE handle;             /* Session handle */
   struct p11_session *link;             /* Next session in list */
@@ -223,12 +164,10 @@ typedef struct p11_session {
   CK_VOID_PTR application;              /* Application data */
   sqlite3_stmt *find_query;             /* FindObject*() query state */
   int find_query_done;                  /* find_query has terminated */
-
-#define SESSION_CRYPTLIB_CONTEXT(_ctx_)         CRYPT_CONTEXT  _ctx_
-#define SESSION_CRYPTLIB_ENVELOPE(_env_)        CRYPT_ENVELOPE _env_
-  SESSION_CRYPTLIB_HANDLES;
-#undef  SESSION_CRYPTLIB_ENVELOPE
-#undef  SESSION_CRYPTLIB_CONTEXT
+  const hal_hash_descriptor_t
+  	*digest_descriptor,             /* Hash for C_Digest*() */
+    	*sign_digest_descriptor;        /* Hash for C_Sign*() */
+  CK_OBJECT_HANDLE sign_key_handle;     /* Key  for C_Sign*() */
 
 } p11_session_t;
 
@@ -277,19 +216,6 @@ static p11_session_t *p11_sessions;
 static sqlite3 *sqldb = NULL;
 
 /*
- * Saved copy of PIN (sigh).
- *
- * We'd like to do better than this, but as long as we're supporting
- * software keysets which require a password every time we read or
- * write a private key, we need this.  Once we're dealing with just
- * the hardware interface we should be able to skip this.
- */
-
-#if ENABLE_CRYPTLIB_SOFTWARE
-static char *pin = NULL;
-#endif
-
-/*
  * Next PKCS #11 handle to allocate.  We use a single handle space for
  * both session and object handles, and we just keep incrementing
  * until it wraps, to reduce the amount of time we have to spend
@@ -299,21 +225,6 @@ static char *pin = NULL;
 static CK_ULONG next_handle;
 
 /*
- * Cryptlib handle for hardware device.
- */
-
-#if ENABLE_CRYPTLIB_DEVICE
-static CRYPT_DEVICE cryptlib_device = CRYPT_HANDLE_NONE;
-#endif
-
-/*
- * Filenames for SQL database and PKCS #15 keyring.
- */
-
-static char *database_filename = NULL;
-static char *keyring_filename = NULL;
-
-/*
  * Mutex callbacks.
  */
 
@@ -362,14 +273,18 @@ static pid_t initialized_pid;
  */
 
 #if DEBUG_SQL
+
 #define sql_whine(_expr_)                                               \
   (fprintf(stderr, "%s:%u: %s returned %s\n",                           \
            __FILE__, __LINE__, #_expr_, sqlite3_errmsg(sqldb)),         \
    sql_breakpoint())
-#else
+
+#else  /* DEBUG_SQL */
+
 #define sql_whine(_expr_)                                               \
   ((void) 0)
-#endif
+
+#endif  /* DEBUG_SQL */
 
 #define sql_check(_good_, _expr_)                                       \
   ((_expr_) == (_good_) ? 1 : (sql_whine(_expr_), 0))
@@ -379,52 +294,31 @@ static pid_t initialized_pid;
 #define sql_check_done(_expr_)  sql_check(SQLITE_DONE, _expr_)
 #define sql_whine_step()        sql_whine(sqlite3_step())
 
-

-
-/*
- * Filename utilities.
- */
-
 /*
- * Construct name of configuration file if we don't already have it cached.
+ * Error checking for libhal calls.
  */
 
-static char *cf_generate(char **fn,                     /* Output filename */
-                         const char * const env,        /* Name of environment variable */
-                         const char * const base)       /* Filename in home directory */
-{
-  char *var;
-
-  assert(fn != NULL && env != NULL && base != NULL);
-
-  if (*fn != NULL)
-    return *fn;
-
-  if ((var = getenv(env)) != NULL && (*fn = malloc(strlen(var) + 1)) != NULL)
-    strcpy(*fn, var);
+#ifndef DEBUG_HAL
+#define DEBUG_HAL 0
+#endif
 
-  else if (var == NULL && (var = getenv("HOME")) != NULL && (*fn = malloc(strlen(var) + strlen(base) + 2)) != NULL)
-    sprintf(*fn, "%s/%s", var, base);
-  
-  else if (var == NULL && (*fn = malloc(strlen(base) + 1)) != NULL)
-    strcpy(*fn, base);
+#if DEBUG_HAL
 
-  return *fn;
+static int _hal_check(const hal_error_t err, const char * const expr, const const * const file, const unsigned line)
+{
+  if (err == HAL_OK)
+    return 1;
+  fprintf(stderr, "%s:%u: %s returned %s\n", file, line, hal_errorstring(err), expr);
+  return 0;
 }
 
-/*
- * Closures over cf_generate() for particular filenames.
- */
+#define hal_check(_expr_) (_hal_check((_expr_), #_expr_, __FILE__, __LINE__))
 
-static char *cf_sql_database(void)
-{
-  return cf_generate(&database_filename, "PKCS11_DATABASE", SQL_DATABASE);
-}
+#else  /* DEBUG_HAL */
 
-static char *cf_pkcs15_keyring(void)
-{
-  return cf_generate(&keyring_filename, "PKCS11_KEYRING", PKCS15_KEYRING);
-}
+#define hal_check(_expr_) ((_expr_) == HAL_OK)
+
+#endif  /* DEBUG_HAL */
 
 

 
@@ -595,130 +489,6 @@ static CK_RV posix_mutex_unlock(CK_VOID_PTR pMutex)
 

 
 /*
- * Wrappers around some of Cryptlib's context functions, so that the
- * rest of the code can mostly ignore whether a particular algorithm
- * is implemented in hardware or not.  In theory, we could achieve
- * this simply by always trying cryptDeviceCreateContext() and
- * checking its return code to see whether we should fall back to
- * CryptCreateContext(), but for the moment I'm more comfortable with
- * explictly coding the list of algorithms we expect to be supported
- * here.  This may change at some future date, once the HAL code is a
- * little further along.
- */
-
-static int cryptlib_implemented_in_hardware(const CRYPT_ALGO_TYPE algo)
-{
-#if ENABLE_CRYPTLIB_DEVICE
-  switch (algo) {
-  case CRYPT_ALGO_YOU_NEED_TO_SPECIFY_SOMETHING_HERE_BOZO:
-    return 1;
-  }
-#endif
-
-  return 0;
-}
-
-/*
- * Create a context -- hardware if supported, software otherwise.
- */
-
-static C_RET cryptlib_create_context(CRYPT_CONTEXT *ctx, const CRYPT_ALGO_TYPE algo)
-{
-#if ENABLE_CRYPTLIB_DEVICE
-  if (cryptlib_implemented_in_hardware(algo))
-    return cryptDeviceCreateContext(cryptlib_device, ctx, algo);
-#endif
-
-  return cryptCreateContext(ctx, CRYPT_UNUSED, algo);
-}
-
-/*
- * Store a key.  This is a no-op for hardware contexts (the hardware
- * device functions as a key store), but requires writing to the PKCS
- * #15 keyring for software contexts.
- */
-
-static C_RET cryptlib_store_key(const CRYPT_CONTEXT ctx)
-{
-  CRYPT_KEYSET keyset;
-  int ret, algo;
-
-  if ((ret = cryptGetAttribute(ctx, CRYPT_CTXINFO_ALGO, &algo)) != CRYPT_OK)
-    return ret;
-
-  if (cryptlib_implemented_in_hardware(algo))
-    return CRYPT_OK;
-
-  ret = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, cf_pkcs15_keyring(), CRYPT_KEYOPT_NONE);
-
-  if (ret == CRYPT_ERROR_OPEN || ret == CRYPT_ERROR_NOTFOUND)
-    ret = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, cf_pkcs15_keyring(), CRYPT_KEYOPT_CREATE);
-
-  if (ret != CRYPT_OK)
-    return ret;
-
-  ret = cryptAddPrivateKey(keyset, ctx, pin);
-
-  cryptKeysetClose(keyset);
-
-  return ret;
-}
-
-/*
- * Load a key.  This creates a new context.
- */
-
-static C_RET cryptlib_load_key(CRYPT_CONTEXT *ctx, const char *keyid)
-{
-  CRYPT_KEYSET keyset;
-  int ret;
-
-  assert(ctx != NULL);
-
-  *ctx = CRYPT_HANDLE_NONE;
-
-#if ENABLE_CRYPTLIB_DEVICE
-  if ((ret = cryptGetPrivateKey(cryptlib_device, ctx, CRYPT_KEYID_NAME, keyid, NULL)) == CRYPT_OK)
-    return ret;
-#endif
-
-  if ((ret = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, cf_pkcs15_keyring(), CRYPT_KEYOPT_READONLY)) != CRYPT_OK)
-    return ret;
-
-  ret = cryptGetPrivateKey(keyset, ctx, CRYPT_KEYID_NAME, keyid, pin);
-
-  cryptKeysetClose(keyset);
-
-  return ret;
-}
-
-/*
- * Delete a key.
- */
-
-static C_RET cryptlib_delete_key(const char *keyid)
-{
-  CRYPT_KEYSET keyset;
-  int ret;
-
-#if ENABLE_CRYPTLIB_DEVICE
-  if ((ret = cryptDeleteKey(cryptlib_device, CRYPT_KEYID_NAME, keyid)) == CRYPT_OK)
-    return ret;
-#endif
-
-  if ((ret = cryptKeysetOpen(&keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, cf_pkcs15_keyring(), CRYPT_KEYOPT_NONE)) != CRYPT_OK)
-    return ret;
-
-  ret = cryptDeleteKey(keyset, CRYPT_KEYID_NAME, keyid);
-
-  cryptKeysetClose(keyset);
-
-  return ret;
-}
-
-

-
-/*
  * SQL utilities.
  */
 
@@ -766,7 +536,26 @@ static int sql_init(void)
 
   assert(sqldb == NULL);
 
-  return sql_check_ok(sqlite3_open(cf_sql_database(), &sqldb)) && sql_exec(schema);
+  const char * const env  = getenv("PKCS11_DATABASE");
+  const char * const home = getenv("HOME");
+  const char * const base = SQL_DATABASE;
+  int ok;
+
+  if (env != NULL) {
+    ok = sql_check_ok(sqlite3_open(env, &sqldb));
+  }
+
+  else if (home == NULL) {
+    ok = sql_check_ok(sqlite3_open(base, &sqldb));
+  }
+
+  else {
+    char fn[strlen(home) + strlen(base) + 2];
+    snprintf(fn, sizeof(fn), "%s/%s", home, base);
+    ok = sql_check_ok(sqlite3_open(fn, &sqldb));
+  }
+
+  return ok && sql_exec(schema);
 }
 
 /*
@@ -825,150 +614,68 @@ static int sql_prepare(sqlite3_stmt **q, const char *format, ...)
   return sqlite3_prepare_v2(sqldb, buffer, -1, q, NULL);
 }
 
-

-
 /*
- * (Extremely) minimal ASN.1 parser, just good enough to pick a few
- * fields out of something like a well-formed ASN.1 DER representation
- * of a certificate.
+ * This idiom occurs frequently, bundle it so we have the option of
+ * doing it along with the normal conditional control flow that SQL
+ * queries seem to follow.
  */
 
-#define ASN1_UNIVERSAL          0x00
-#define ASN1_APPLICATION        0x40
-#define ASN1_CONTEXT_SPECIFIC   0x80
-#define ASN1_PRIVATE            0xC0
+static int sql_finalize_and_clear(sqlite3_stmt **q)
+{
+  assert(q != NULL);
 
-#define ASN1_PRIMITIVE          0x00
-#define ASN1_CONSTRUCTED        0x20
+  int err = sqlite3_finalize(*q);
 
-#define ASN1_TAG_MASK           0x1F
+  if (err != SQLITE_OK)
+    return err;
 
-#define ASN1_INTEGER            (ASN1_PRIMITIVE   | 0x02)
-#define ASN1_BIT_STRING         (ASN1_PRIMITIVE   | 0x03)
-#define ASN1_OCTET_STRING       (ASN1_PRIMITIVE   | 0x04)
-#define ASN1_NULL               (ASN1_PRIMITIVE   | 0x05)
-#define ASN1_OBJECT_IDENTIFIER  (ASN1_PRIMITIVE   | 0x06)
-#define ASN1_SEQUENCE           (ASN1_CONSTRUCTED | 0x10)
-#define ASN1_SET                (ASN1_CONSTRUCTED | 0x11)
+  *q = NULL;
+  return SQLITE_OK;
+}
 
-#define ASN1_EXPLICIT_CONTEXT   (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED)
-#define ASN1_EXPLICIT_0         (ASN1_EXPLICIT_CONTEXT + 0)
+

 
 /*
- * Common setup code for asn1_dive() and asn1_skip().
+ * Initialize KEK.  If we had proper hardware support the KEK would be
+ * living in special RAM where we could wipe it if anything triggered
+ * our tamper circuitry.  But we have no such at the moment, so we
+ * have no good place to store the KEK.
  *
- * Check ASN.1 tag and various errors, decode length field.
- * Outputs are length of header (tag + length) and value.
+ * So we store it in the SQL database, which kind of defeats the point
+ * of wrapping private keys that live in the same database -- except
+ * that we're trying to get all the other bits right so that we can
+ * just move the KEK to secure memory once we have it.
  */
 
-static int asn1_prep(const unsigned char tag,
-                     const unsigned char * const der,
-                     const size_t len,
-                     size_t *phlen,
-                     size_t *pvlen)
+static int kek_init(void)
 {
-  size_t i, hlen, vlen;
-
-  if (der == NULL || len < 2 || phlen == NULL || pvlen == NULL || der[0] != tag || der[1] > 0x84)
-    return 0;
-
-  if ((der[1] & 0x80) == 0) {
-    hlen = 2;
-    vlen = der[1];
-  }
-
-  else {
-    hlen = 2 + (der[1] & 0x7F);
-    vlen = 0;
-
-    if (hlen >= len)
-      return 0;
+  static const char test_kek[] =
+    " SELECT kek IS NULL FROM global";
 
-    for (i = 2; i < hlen; i++)
-      vlen = (vlen << 8) + der[i];
-  }
+  static const char set_kek[] =
+    " UPDATE global SET kek = ?1";
 
-  if (hlen + vlen > len)
-    return 0;
+  sqlite3_stmt *q = NULL;
 
-  *phlen = hlen;
-  *pvlen = vlen;
-  return 1;
-}
+  int ok = (sql_check_ok(sql_prepare(&q, test_kek))             &&
+            sql_check_row(sqlite3_step(q)));
 
-/*
- * Dive into an ASN.1 object.
- *
- * The special handling for BIT STRING is only appropriate for the
- * intended use, where BIT STRING always encapsulates another ASN.1
- * object like SubjectPublicKeyInfo and is thus always required to be
- * a multiple of 8 bits in length.  If we ever need to use this code
- * to deal with real bit strings, the special handling will need to
- * move to a separate function which we can call when appropriate.
- */
- 
-static int asn1_dive(const unsigned char tag,
-                     const unsigned char **der,
-                     size_t *len)
-{
-  size_t hlen, vlen;
+  if (ok && sqlite3_column_int(q, 0)) {
+    uint8_t kekbuf[bitsToBytes(256)];
 
-  if (der == NULL || len == NULL || !asn1_prep(tag, *der, *len, &hlen, &vlen))
-    return 0;
+    ok = (hal_check(hal_get_random(kekbuf, sizeof(kekbuf)))	&&
+          sql_check_ok(sql_finalize_and_clear(&q))              &&
+          sql_check_ok(sql_prepare(&q, set_kek))		&&
+          sql_check_ok(sqlite3_bind_blob(q, 1, kekbuf,
+                                         sizeof(kekbuf),
+                                         NULL))                 &&
+          sql_check_done(sqlite3_step(q)));
 
-  if (tag == ASN1_BIT_STRING) {
-    if (vlen == 0 || hlen >= *len || (*der)[hlen] != 0x00)
-      return 0;
-    hlen++, vlen--;
+    memset(kekbuf, 0, sizeof(kekbuf));
   }
 
-  assert(hlen + vlen <= *len);
-  *der += hlen;                 /* Advance past the header */
-  *len = vlen;                  /* Shrink range to be just the content */
-  return 1;  
-}
-
-/*
- * Skip over an ASN.1 object.
- */
-
-static int asn1_skip(const unsigned char tag,
-                     const unsigned char **der,
-                     size_t *len)
-{
-  size_t hlen, vlen;
-
-  if (der == NULL || len == NULL || !asn1_prep(tag, *der, *len, &hlen, &vlen))
-    return 0;
-
-  assert(hlen + vlen <= *len);
-  *der += hlen + vlen;          /* Advance past entire object */
-  *len -= hlen + vlen;          /* Reduce range by length of object */
-  return 1;
-}
-
-/*
- * Grovel through a DER encoded X.509v3 certificate object until we
- * find the subjectPublicKey field.  See the ASN.1 in RFC 5280.
- *
- * This is much too simplistic for general use, but should suffice to
- * pick the subjectPublicKey data out of a certificate generated for
- * us by Cryptlib.
- */
-
-static int asn1_find_x509_spki(const unsigned char **der, size_t *len)
-{
-  return (asn1_dive(ASN1_SEQUENCE,      der, len) && /* Dive into certificate */
-          asn1_dive(ASN1_SEQUENCE,      der, len) && /* Dive into tbsCertificate */
-          asn1_skip(ASN1_EXPLICIT_0,    der, len) && /* Skip version */
-          asn1_skip(ASN1_INTEGER,       der, len) && /* Skip serialNumber */
-          asn1_skip(ASN1_SEQUENCE,      der, len) && /* Skip signature */
-          asn1_skip(ASN1_SEQUENCE,      der, len) && /* Skip issuer */
-          asn1_skip(ASN1_SEQUENCE,      der, len) && /* skip validity */
-          asn1_skip(ASN1_SEQUENCE,      der, len) && /* Skip subject */
-          asn1_dive(ASN1_SEQUENCE,      der, len) && /* Dive into subjectPublicKeyInfo */
-          asn1_skip(ASN1_SEQUENCE,      der, len) && /* Skip algorithm */
-          asn1_dive(ASN1_BIT_STRING,    der, len));  /* Dive into subjectPublicKey */
+  sqlite3_finalize(q);
+  return ok;
 }
 
 

@@ -1201,8 +908,15 @@ static int p11_attribute_find_in_template(const CK_ATTRIBUTE_TYPE type,
  * values, it may be necessary to defer calling this method until
  * after the default and mandatory values have been merged into the
  * values supplied by the application-supplied template.
+ *
+ * Semantics of the flags follow RFC 5280 4.2.1.3, numeric values
+ * don't matter particularly as we only use them internally.
  */
 
+#define KEYUSAGE_DIGITALSIGNATURE	(1 << 0)
+#define KEYUSAGE_KEYENCIPHERMENT	(1 << 1)
+#define KEYUSAGE_DATAENCIPHERMENT	(1 << 2)
+
 static void p11_attribute_apply_keyusage(unsigned *keyusage, const CK_ATTRIBUTE_TYPE type, const CK_BBOOL *value)
 {
   unsigned flag;
@@ -1212,15 +926,15 @@ static void p11_attribute_apply_keyusage(unsigned *keyusage, const CK_ATTRIBUTE_
   switch (type) {
   case CKA_SIGN:                /* Generate signature */
   case CKA_VERIFY:              /* Verify signature */
-    flag = CRYPT_KEYUSAGE_DIGITALSIGNATURE;
+    flag = KEYUSAGE_DIGITALSIGNATURE;
     break;
   case CKA_ENCRYPT:             /* Encrypt bulk data (seldom used) */
   case CKA_DECRYPT:             /* Bulk decryption (seldom used) */
-    flag = CRYPT_KEYUSAGE_DATAENCIPHERMENT;
+    flag = KEYUSAGE_DATAENCIPHERMENT;
     break;
   case CKA_WRAP:                /* Wrap key (normal way of doing encryption) */
   case CKA_UNWRAP:              /* Unwrap key (normal way of doing decryption) */
-    flag = CRYPT_KEYUSAGE_KEYENCIPHERMENT;
+    flag = KEYUSAGE_KEYENCIPHERMENT;
     break;
   default:
     return;                     /* Attribute not related to key usage */
@@ -1370,11 +1084,6 @@ static CK_RV p11_object_check_rights(const p11_session_t *session,
 
 static int p11_object_delete_all_private(void)
 {
-  static const char select_format[] =
-    " WITH"
-    "   private AS (SELECT session_object_id FROM session_attribute WHERE type = %u AND value <> X'00')"
-    " SELECT keyid FROM session_object WHERE keyid IS NOT NULL AND session_object_id IN private";
-
   static const char delete_format[] =
     " WITH"
     "  s AS (SELECT session_object_id FROM session_attribute WHERE type = %u AND value <> X'00'),"
@@ -1382,22 +1091,7 @@ static int p11_object_delete_all_private(void)
     " DELETE FROM object WHERE token_object_id IN t OR session_object_id IN s";
 
   sqlite3_stmt *q = NULL;
-  int ret, ok = 0;
-
-  if (!sql_check_ok(sql_prepare(&q, select_format, CKA_PRIVATE)))
-    goto fail;
-
-  while ((ret = sqlite3_step(q)) == SQLITE_ROW)
-    if (cryptlib_delete_key((const char *) sqlite3_column_text(q, 0)) != CRYPT_OK)
-      goto fail;
-
-  if (ret != SQLITE_DONE) {
-    sql_whine_step();
-    goto fail;
-  }
-
-  sqlite3_finalize(q);
-  q = NULL;
+  int ok = 0;
 
   if (!sql_check_ok(sql_prepare(&q, delete_format, CKA_PRIVATE, CKA_PRIVATE))   ||
       !sql_check_done(sqlite3_step(q)))
@@ -1467,8 +1161,8 @@ static CK_OBJECT_HANDLE p11_object_create(const p11_session_t *session,
 
   object_id = sqlite3_last_insert_rowid(sqldb);
 
-  sqlite3_finalize(q);
-  q = NULL;
+  if (!sql_check_ok(sql_finalize_and_clear(&q)))
+    goto fail;
 
   switch (flavor) {
 
@@ -1477,16 +1171,13 @@ static CK_OBJECT_HANDLE p11_object_create(const p11_session_t *session,
         !sql_check_done(sqlite3_step(q)))
       goto fail;
     token_object_id = sqlite3_last_insert_rowid(sqldb);
-    sqlite3_finalize(q);
-    q = NULL;
-    if (!sql_check_ok(sql_prepare(&q, update_object_token_object))      ||
+    if (!sql_check_ok(sql_finalize_and_clear(&q))                       ||
+        !sql_check_ok(sql_prepare(&q, update_object_token_object))      ||
         !sql_check_ok(sqlite3_bind_int64(q, 1, token_object_id))        ||
         !sql_check_ok(sqlite3_bind_int64(q, 2, object_id))              ||
-        !sql_check_done(sqlite3_step(q)))
-      goto fail;
-    sqlite3_finalize(q);
-    q = NULL;
-    if (!sql_check_ok(sql_prepare(&q, insert_token_attribute))          ||
+        !sql_check_done(sqlite3_step(q))                                ||
+        !sql_check_ok(sql_finalize_and_clear(&q))                       ||
+        !sql_check_ok(sql_prepare(&q, insert_token_attribute))          ||
         !sql_check_ok(sqlite3_bind_int64(q, 1, token_object_id)))
       goto fail;
     break;
@@ -1497,17 +1188,14 @@ static CK_OBJECT_HANDLE p11_object_create(const p11_session_t *session,
         !sql_check_done(sqlite3_step(q)))
       goto fail;
     session_object_id = sqlite3_last_insert_rowid(sqldb);
-    sqlite3_finalize(q);
-    q = NULL;
-    if (!sql_check_ok(sql_prepare(&q, update_object_session_object))    ||
+    if (!sql_check_ok(sql_finalize_and_clear(&q))                       ||
+        !sql_check_ok(sql_prepare(&q, update_object_session_object))    ||
         !sql_check_ok(sqlite3_bind_int64(q, 1, session->handle))        ||
         !sql_check_ok(sqlite3_bind_int64(q, 2, session_object_id))      ||
         !sql_check_ok(sqlite3_bind_int64(q, 3, object_id))              ||
-        !sql_check_done(sqlite3_step(q)))
-      goto fail;
-    sqlite3_finalize(q);
-    q = NULL;
-    if (!sql_check_ok(sql_prepare(&q, insert_session_attribute))        ||
+        !sql_check_done(sqlite3_step(q))                                ||
+        !sql_check_ok(sql_finalize_and_clear(&q))                       ||
+        !sql_check_ok(sql_prepare(&q, insert_session_attribute))        ||
         !sql_check_ok(sqlite3_bind_int64(q, 1, session_object_id)))
       goto fail;
     break;
@@ -1584,188 +1272,111 @@ static CK_OBJECT_HANDLE p11_object_create(const p11_session_t *session,
 }
 
 /*
- * Get the keyid for an object.
+ * Store an RSA private key.
+ *
+ * Write the key as PKCS #1.5 RSAPrivateKey DER, encrypt that using
+ * AES key wrap, and store the result as an SQL blob.
  *
- * This may require calculating the keyid from the CKA_ID attribute.
+ * We jump through a few minor hoops to let us do all the encoding and
+ * wrapping in place in a single buffer.
  */
 
-static int p11_object_get_keyid(const CK_OBJECT_HANDLE object_handle,
-                                char *keyid,
-                                const size_t maxkeyid)
+static int p11_object_set_rsa_private_key(const CK_OBJECT_HANDLE object_handle,
+                                          const hal_rsa_key_t key)
 {
-  static const char select_format[] =
-    " SELECT keyid FROM %s_object NATURAL JOIN object WHERE object_handle = ?";
+  static const char select_kek[] =
+    " SELECT kek FROM global";
 
   static const char update_format[] =
-    " UPDATE %s_object SET keyid = ?1"
-    " WHERE %s_object_id = (SELECT %s_object_id FROM object WHERE object_handle =?2)";
+    " UPDATE %s_object SET private_key = ?1"
+    " WHERE %s_object_id = (SELECT %s_object_id FROM object WHERE object_handle = ?2)";
 
+  uint8_t wrapbuf[hal_aes_keywrap_ciphertext_length(hal_rsa_key_to_der_len(key))];
   const char *flavor = is_token_handle(object_handle) ? "token" : "session";
-
   sqlite3_stmt *q = NULL;
+  size_t len;
   int ok = 0;
 
-  if (!sql_check_ok(sql_prepare(&q, select_format, flavor))     ||
-      !sql_check_ok(sqlite3_bind_int64(q, 1, object_handle))    ||
-      !sql_check_row(sqlite3_step(q)))
+  if (!sql_check_ok(sql_prepare(&q, select_kek))                                ||
+      !sql_check_row(sqlite3_step(q))                                           ||
+      sqlite3_column_type(q, 0) == SQLITE_NULL                                  ||
+      !hal_check(hal_rsa_key_to_der(key, wrapbuf+8, &len, sizeof(wrapbuf)-8))   ||
+      !hal_check(hal_aes_keywrap(sqlite3_column_blob(q, 0),
+                                 sqlite3_column_bytes(q, 0),
+                                 wrapbuf+8, len, wrapbuf, &len))		||
+      !sql_check_ok(sql_finalize_and_clear(&q))                                 ||
+      !sql_check_ok(sql_prepare(&q, update_format, flavor, flavor, flavor))     ||
+      !sql_check_ok(sqlite3_bind_blob( q, 1, wrapbuf, len, NULL))               ||
+      !sql_check_ok(sqlite3_bind_int64(q, 2, object_handle))                    ||
+      !sql_check_done(sqlite3_step(q)))
     goto fail;
 
-  if (sqlite3_column_type(q, 0) == SQLITE_NULL) {
-
-    /*
-     * No keyid set yet, have to create one.  We use the CKA_ID
-     * attribute for this, zero-filling or truncating as necessary.
-     */
-
-    const CK_ULONG target_length = (CRYPT_MAX_TEXTSIZE < maxkeyid ? CRYPT_MAX_TEXTSIZE : (maxkeyid - 1)) / 2;
-    unsigned char id[CRYPT_MAX_HASHSIZE];
-    CK_ULONG len;
-    int i;
-
-    assert(target_length > 0 && target_length <= sizeof(id) && target_length * 2 < maxkeyid);
-
-    if (!p11_attribute_get(object_handle, CKA_ID, id, &len, sizeof(id)))
-      goto fail;
-
-    if (len < target_length) {
-      memmove(id + target_length - len, id, len);
-      memset(id, 0x00, target_length - len);
-    }
-
-    for (i = 0; i < target_length; i++)
-      sprintf(keyid + (2 * i), "%02x", id[i]);
-    keyid[target_length * 2] = '\0';
-
-    sqlite3_finalize(q);
-    q = NULL;
-
-    if (!sql_check_ok(sql_prepare(&q, update_format, flavor, flavor, flavor))   ||
-        !sql_check_ok(sqlite3_bind_text( q, 1, keyid, strlen(keyid), NULL))     ||
-        !sql_check_ok(sqlite3_bind_int64(q, 2, object_handle))                  ||
-        !sql_check_done(sqlite3_step(q)))
-      goto fail;
-
-  } else {
-
-    /*
-     * Already had a keyid, just have to copy it.
-     */
-
-    int len = sqlite3_column_bytes(q, 0);
-
-    if (len >= maxkeyid)
-      goto fail;
-
-    memcpy(keyid, sqlite3_column_text(q, 0), len);
-    keyid[len] = '\0';
-
-  }
-
   ok = 1;
 
  fail:
+  memset(wrapbuf, 0, sizeof(wrapbuf));
   sqlite3_finalize(q);
   return ok;
 }
 
 /*
- * Add attributes representing the SPKI value of a key we've
- * generated.
+ * Fetch an RSA private key.
  *
- * Cryptlib does such a complete job of protecting our keys that it's
- * rather tedious to extract the raw subjectPublicKeyInfo, but the
- * PKCS #11 client needs that information, so we have to jump through
- * some silly hoops.  This routine does most of the work, but uses a
- * separate handler (supplied as an argument) to generate attributes
- * based on mechanism-specific data from the subjectPublicKey.
+ * Retrieve SQL blob from the object, unwrap that to get the DER
+ * encoding of a PKCS #1.5 RSAPrivateKey object, load the key from
+ * that.
  *
- * Basic approach here is to generate a temporary certificate from the
- * key, export that as DER, parse the DER for the data we need, and
- * destroy the temporary certificate.
+ * If the key isn't set, we return success with null key.
  */
 
-static int p11_object_add_spki(const CK_OBJECT_HANDLE public_handle,
-                               const CK_OBJECT_HANDLE private_handle,
-                               const CRYPT_CONTEXT key,
-                               int (*handler)(const CK_OBJECT_HANDLE,
-                                              const CK_OBJECT_HANDLE,
-                                              const unsigned char *,
-                                              const size_t))
+static int p11_object_get_rsa_private_key(const CK_OBJECT_HANDLE object_handle,
+                                          hal_rsa_key_t *key,
+                                          uint8_t *keybuf, const size_t keybuf_len)
 {
-  static const char label[] = "Don't care";
-  CRYPT_CERTIFICATE cert = CRYPT_HANDLE_NONE;
-  unsigned char *buffer = NULL;
-  const unsigned char *der;
-  int ilen, ok = 0;
-  size_t ulen;
-
-  if (handler                                                                           == NULL     ||
-      cryptCreateCert(&cert, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTIFICATE)                  != CRYPT_OK ||
-      cryptSetAttribute(cert, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, key)                 != CRYPT_OK ||
-      cryptSetAttribute(cert, CRYPT_CERTINFO_XYZZY, 1)                                  != CRYPT_OK ||
-      cryptSetAttributeString(cert, CRYPT_CERTINFO_COMMONNAME, label, sizeof(label))    != CRYPT_OK ||
-      cryptSignCert(cert, key)                                                          != CRYPT_OK ||
-      cryptExportCert(NULL, 0, &ilen, CRYPT_CERTFORMAT_CERTIFICATE, cert)               != CRYPT_OK ||
-      (der = buffer = malloc(ulen = (size_t) ilen))                                     == NULL     ||
-      cryptExportCert(buffer, ilen, &ilen, CRYPT_CERTFORMAT_CERTIFICATE, cert)          != CRYPT_OK ||
-      !asn1_find_x509_spki(&der, &ulen)                                                             ||
-      !handler(public_handle, private_handle, der, ulen))
-    goto fail;
-
-  ok = 1;
-
- fail:
-  if (buffer != NULL)
-    free(buffer);
-  if (cert != CRYPT_HANDLE_NONE)
-    cryptDestroyCert(cert);
-  return ok;
-}
+  static const char select_format[] =
+    " SELECT kek, private_key FROM global, %s_object NATURAL JOIN object WHERE object_handle = ?1";
 
-/*
- * RSA-specific handler to go with p11_object_add_spki().
- *
- * Extract RSA modulus and public exponent from the subjectPublicKey
- * and adds the appropriate attributes to the public and private keys.
- */
+  const char *flavor = is_token_handle(object_handle) ? "token" : "session";
+  sqlite3_stmt *q = NULL;
+  int ok;
 
-static int p11_object_add_spki_rsa(const CK_OBJECT_HANDLE public_handle,
-                                   const CK_OBJECT_HANDLE private_handle,
-                                   const unsigned char *der,
-                                   const size_t len)
-{
-  const unsigned char *modulus = der, *publicExponent = der;
-  size_t modulus_len = len, publicExponent_len = len;
+  assert(key != NULL && keybuf != NULL);
 
   /*
-   * Dig the relevant integers out of the ASN.1.
+   * Pull everything we need from the database.
    */
-  if (!asn1_dive(ASN1_SEQUENCE, &modulus,        &modulus_len)          ||
-      !asn1_dive(ASN1_INTEGER,  &modulus,        &modulus_len)          ||
-      !asn1_dive(ASN1_SEQUENCE, &publicExponent, &publicExponent_len)   ||
-      !asn1_skip(ASN1_INTEGER,  &publicExponent, &publicExponent_len)   ||
-      !asn1_dive(ASN1_INTEGER,  &publicExponent, &publicExponent_len))
-    return 0;
 
-  /*
-   * ASN.1 INTEGERs are signed while PKCS #11 "big integers" are
-   * unsigned, so skip leading zero byte, if present.
-   */
+  if (!sql_check_ok(sql_prepare(&q, select_format, flavor))     ||
+      !sql_check_ok(sqlite3_bind_int64(q, 1, object_handle))    ||
+      !sql_check_row(sqlite3_step(q))                           ||
+      sqlite3_column_type(q, 0) == SQLITE_NULL) {
+    ok = 0;
+  }
 
-  if (modulus_len > 0 && *modulus == 0x00)
-    modulus_len--, modulus++;
+  else if (sqlite3_column_type(q, 1) == SQLITE_NULL) {
+    key->key = NULL;
+    ok = 1;
+  }
 
-  if (publicExponent_len > 0 && *publicExponent == 0x00)
-    publicExponent_len--, publicExponent++;
-  
-  /*
-   * Insert the attributes and we're done.
-   */
+  else {
+    const uint8_t * const kek  = sqlite3_column_blob(q, 0);
+    const uint8_t * const pkey = sqlite3_column_blob(q, 1);
+    const size_t kek_len  = sqlite3_column_bytes(q, 0);
+    const size_t pkey_len = sqlite3_column_bytes(q, 1);
+    uint8_t wrapbuf[sqlite3_column_bytes(q, 1)];
+    size_t  wrapbuf_len;
+
+    ok = (hal_check(hal_aes_keyunwrap(kek, kek_len, pkey, pkey_len, wrapbuf, &wrapbuf_len)) &&
+          hal_check(hal_rsa_key_from_der(key, keybuf, keybuf_len, wrapbuf, wrapbuf_len)));
 
-  return (p11_attribute_set(public_handle,  CKA_MODULUS,         modulus,        modulus_len)           &&
-          p11_attribute_set(public_handle,  CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len)    &&
-          p11_attribute_set(private_handle, CKA_MODULUS,         modulus,        modulus_len)           &&
-          p11_attribute_set(private_handle, CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len));
+    memset(wrapbuf, 0, sizeof(wrapbuf));
+  }
+
+  if (!ok || key->key == NULL)
+    memset(keybuf, 0, keybuf_len);
+
+  sqlite3_finalize(q);
+  return ok;
 }
 
 

@@ -1784,13 +1395,6 @@ static p11_session_t *p11_session_new(void)
   if (session == NULL)
     return NULL;
   memset(session, 0, sizeof(*session));
-
-#define SESSION_CRYPTLIB_CONTEXT(_ctx_)         session->_ctx_ = CRYPT_HANDLE_NONE
-#define SESSION_CRYPTLIB_ENVELOPE(_env_)        session->_env_ = CRYPT_HANDLE_NONE
-  SESSION_CRYPTLIB_HANDLES;
-#undef  SESSION_CRYPTLIB_ENVELOPE
-#undef  SESSION_CRYPTLIB_CONTEXT
-
   return session;
 }
 
@@ -1803,14 +1407,7 @@ static void p11_session_free(p11_session_t *session)
   if (session == NULL)
     return;
 
-  if (session->find_query != NULL)
-    sqlite3_finalize(session->find_query);
-
-#define SESSION_CRYPTLIB_CONTEXT(_ctx_)         if (session->_ctx_ != CRYPT_HANDLE_NONE) cryptDestroyContext(session->_ctx_)
-#define SESSION_CRYPTLIB_ENVELOPE(_env_)        if (session->_env_ != CRYPT_HANDLE_NONE) cryptDestroyEnvelope(session->_env_)
-  SESSION_CRYPTLIB_HANDLES;
-#undef  SESSION_CRYPTLIB_ENVELOPE
-#undef  SESSION_CRYPTLIB_CONTEXT
+  sql_finalize_and_clear(&session->find_query);
 
   free(session);
 }
@@ -1876,45 +1473,21 @@ static p11_session_t *p11_session_find(const CK_SESSION_HANDLE session_handle)
  * Delete a session: remove it from SQL and free the session data
  * structure.
  *
- * Since this destroys all associated session objects, we also have to
- * delete any keys we might be holding for session objects.
- *
  * This method assumes the move-to-the-front behavior of
  * p11_session_find().
  */
 
 static CK_RV p11_session_delete(const CK_SESSION_HANDLE session_handle)
 {
-  static const char select_keyid[] =
-    " SELECT keyid FROM session NATURAL JOIN session_object"
-    " WHERE session_handle = ?1 AND keyid IS NOT NULL";
-
   static const char delete_session[] =
     " DELETE FROM session WHERE session_handle = ?";
 
   p11_session_t *session = p11_session_find(session_handle);
   sqlite3_stmt *q = NULL;
   CK_RV rv = CKR_OK;
-  int ret;
 
   if (session == NULL)
     return CKR_SESSION_HANDLE_INVALID;
-  
-  if (!sql_check_ok(sql_prepare(&q, select_keyid)) ||
-      !sql_check_ok(sqlite3_bind_int64(q, 1, session_handle)))
-    lose(CKR_FUNCTION_FAILED);
-
-  while ((ret = sqlite3_step(q)) == SQLITE_ROW)
-    if (cryptlib_delete_key((const char *) sqlite3_column_text(q, 0)) != CRYPT_OK)
-      lose(CKR_FUNCTION_FAILED);
-
-  if (ret != SQLITE_DONE) {
-    sql_whine_step();
-    lose(CKR_FUNCTION_FAILED);
-  }
-
-  sqlite3_finalize(q);
-  q = NULL;
 
   if (!sql_check_ok(sql_prepare(&q, delete_session))            ||
       !sql_check_ok(sqlite3_bind_int64(q, 1, session_handle))   ||
@@ -1934,40 +1507,17 @@ static CK_RV p11_session_delete(const CK_SESSION_HANDLE session_handle)
 
 /*
  * Delete all sessions.
- *
- * Like p11_session_delete(), this must also delete any keys held in
- * session objects.
  */
 
-static CK_RV p11_session_delete_all(void)
-{
-  static const char select_keys[] =
-    " SELECT keyid FROM session_object WHERE keyid IS NOT NULL";
-
 #warning Should this also clear the object table?
 
+static CK_RV p11_session_delete_all(void)
+{
   static const char delete_all_sessions[] =
     " DELETE FROM session";
 
   p11_session_t *session;
-  sqlite3_stmt *q = NULL;
-  int ret = SQLITE_OK;
-  CK_RV rv = CKR_OK;
-
-  if (!sql_check_ok(sql_prepare(&q, select_keys)))
-    lose(CKR_FUNCTION_FAILED);
-
-  while ((ret = sqlite3_step(q)) == SQLITE_ROW)
-    if (cryptlib_delete_key((const char *) sqlite3_column_text(q, 0)) != CRYPT_OK)
-      lose(CKR_FUNCTION_FAILED);
-
-  if (ret != SQLITE_DONE) {
-    sql_whine_step();
-    lose(CKR_FUNCTION_FAILED);
-  }
-
-  sqlite3_finalize(q);
-  q = NULL;
+  CK_RV rv = CKR_OK;
 
   if (!sql_exec(delete_all_sessions))
     lose(CKR_FUNCTION_FAILED);
@@ -1979,7 +1529,6 @@ static CK_RV p11_session_delete_all(void)
   }
 
  fail:
-  sqlite3_finalize(q);
   return rv;
 }
 
@@ -2156,15 +1705,10 @@ static CK_RV p11_check_keypair_attributes_check_template_2(const p11_session_t *
  * amount of checking.  We automate as much of the dumb stuff as
  * possible through the object descriptor.
  * 
- * Key usage handling here is based on RFC 5280 4.2.1.3, same as
- * Cryptlib.  We reuse Cryptlib's bit flags because they're
- * convenient.
+ * Key usage handling here is based on RFC 5280 4.2.1.3.
  *
- * We use the PKCS #11 CKA_ID attribute to generate the Cryptlib key
- * label.  PKCS #11 suggests but does not require CKA_ID values for
- * public and private key to match; we do insist on this, because we
- * really only have one key label which applies to both the public and
- * private keys.
+ * PKCS #11 suggests but does not require CKA_ID values for public and
+ * private key to match.
  */
 
 static CK_RV p11_check_keypair_attributes(const p11_session_t *session,
@@ -2176,8 +1720,6 @@ static CK_RV p11_check_keypair_attributes(const p11_session_t *session,
                                           const p11_descriptor_t * const private_descriptor)
 {
   unsigned public_keyusage = 0, private_keyusage = 0;
-  const CK_BYTE *id = NULL;
-  size_t id_len = 0;
   CK_RV rv = CKR_OK;
   int i;
 
@@ -2208,11 +1750,6 @@ static CK_RV p11_check_keypair_attributes(const p11_session_t *session,
       goto fail;
 
     p11_attribute_apply_keyusage(&public_keyusage, type, val);
-
-    if (type == CKA_ID) {
-      id = val;
-      id_len = len;
-    }
   }
 
   for (i = 0; i < ulPrivateKeyAttributeCount; i++) {
@@ -2224,14 +1761,6 @@ static CK_RV p11_check_keypair_attributes(const p11_session_t *session,
       goto fail;
 
     p11_attribute_apply_keyusage(&private_keyusage, type, val);
-
-    if (type == CKA_ID && id == NULL) {
-      id = val;
-      id_len = len;
-    }
-
-    if (type == CKA_ID && (len != id_len || memcmp(id, val, len)))
-      lose(CKR_TEMPLATE_INCONSISTENT);
   }
 
   /*
@@ -2243,13 +1772,6 @@ static CK_RV p11_check_keypair_attributes(const p11_session_t *session,
     lose(CKR_TEMPLATE_INCONSISTENT);
 
   /*
-   * We require a key ID.
-   */
-
-  if (id == NULL || id_len == 0)
-    lose(CKR_TEMPLATE_INCOMPLETE);
-
-  /*
    * Check that all required attributes have been specified.
    */
 
@@ -2294,11 +1816,15 @@ static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session,
   CK_OBJECT_HANDLE public_handle = CK_INVALID_HANDLE;
   handle_flavor_t public_handle_flavor = handle_flavor_session_object;
   handle_flavor_t private_handle_flavor = handle_flavor_session_object;
-  char keyid[CRYPT_MAX_HASHSIZE * 2 + 1];
-  CRYPT_CONTEXT ctx = CRYPT_HANDLE_NONE;
-  const CK_BYTE *id = NULL;
+  uint8_t
+    keybuf[hal_rsa_key_t_size],
+    modulus[hal_rsa_key_t_size/8],
+    public_exponent[hal_rsa_key_t_size/8];
+  size_t
+    modulus_len,
+    public_exponent_len;
+  hal_rsa_key_t key = { NULL };
   CK_ULONG keysize = 0;
-  size_t id_len = 0;
   CK_RV rv;
   int i;
 
@@ -2316,8 +1842,6 @@ static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session,
          pPublicKeyTemplate  != NULL && phPublicKey  != NULL && 
          pPrivateKeyTemplate != NULL && phPrivateKey != NULL);
 
-  memset(keyid, 0, sizeof(keyid));
-
   /*
    * Grab values and perform mechanism-specific checks.
    */
@@ -2335,12 +1859,7 @@ static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session,
       public_handle_flavor = p11_handle_flavor_from_cka_token(val);
       continue;
 
-    case CKA_ID:                /* We use PKCS #11 "ID" as Cryptlib label */
-      id = val;
-      id_len = len;
-      continue;
-
-    case CKA_MODULUS_BITS:      /* Keysize in bits -- Cryptlib only allows multiples of 8 */
+    case CKA_MODULUS_BITS:      /* Keysize in bits -- only allow multiples of 8 */
       keysize = *(CK_ULONG *) val;
       if ((keysize & 7) != 0)
         return CKR_ATTRIBUTE_VALUE_INVALID;
@@ -2362,52 +1881,40 @@ static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session,
       private_handle_flavor = p11_handle_flavor_from_cka_token(val);
       continue;
 
-    case CKA_ID:                /* We use PKCS #11 "ID" as Cryptlib label */
-      id = val;
-      id_len = len;
-      continue;
-
     }
   }
 
   /*
-   * We require a key ID and a key size, and if either key is a token
-   * object, the other must be too.
+   * We require a key size, and if either key is a token object, the
+   * other must be too.
    */
-  if (id == NULL || id_len == 0 || keysize == 0 || public_handle_flavor != private_handle_flavor)
+  if (keysize == 0 || public_handle_flavor != private_handle_flavor)
     return CKR_TEMPLATE_INCOMPLETE;
 
   /*
-   * If we got this far, create the PKCS #11 objects.
+   * Create the PKCS #11 objects and generate the keypair.
    */
 
-  if (!sql_exec("BEGIN"))
+  if (!sql_exec("BEGIN")                                                                        ||
+      (public_handle = p11_object_create(session, public_handle_flavor,
+                                         pPublicKeyTemplate, ulPublicKeyAttributeCount,
+                                         &p11_descriptor_rsa_public_key,
+                                         pMechanism)) == CK_INVALID_HANDLE                      ||
+      (private_handle = p11_object_create(session, private_handle_flavor,
+                                          pPrivateKeyTemplate,  ulPrivateKeyAttributeCount,
+                                          &p11_descriptor_rsa_private_key,
+                                          pMechanism)) == CK_INVALID_HANDLE			||
+      !p11_attribute_get(public_handle, CKA_PUBLIC_EXPONENT,
+                         public_exponent, &public_exponent_len, sizeof(public_exponent))	||
+      !hal_check(hal_rsa_key_gen(&key, keybuf, sizeof(keybuf), keysize,
+                                 public_exponent, public_exponent_len))        			||
+      !p11_object_set_rsa_private_key(private_handle, key)                                      ||
+      !hal_check(hal_rsa_key_get_modulus(key, modulus, &modulus_len, sizeof(modulus)))          ||
+      !p11_attribute_set(public_handle,  CKA_MODULUS, modulus, modulus_len)                     ||
+      !p11_attribute_set(private_handle, CKA_MODULUS, modulus, modulus_len))
     lose(CKR_FUNCTION_FAILED);
 
-  public_handle = p11_object_create(session, public_handle_flavor,
-                                    pPublicKeyTemplate, ulPublicKeyAttributeCount,
-                                    &p11_descriptor_rsa_public_key, pMechanism);
-
-  private_handle = p11_object_create(session, private_handle_flavor,
-                                     pPrivateKeyTemplate,  ulPrivateKeyAttributeCount,
-                                     &p11_descriptor_rsa_private_key, pMechanism);
-
-  if (public_handle == CK_INVALID_HANDLE || private_handle == CK_INVALID_HANDLE)
-    lose(CKR_FUNCTION_FAILED);    
-
-  /*
-   * Generate the keypair.
-   */
-
-  if (!p11_object_get_keyid(private_handle, keyid, sizeof(keyid))                           ||
-      cryptlib_create_context(&ctx, CRYPT_ALGO_RSA)                             != CRYPT_OK ||
-      cryptSetAttributeString(ctx, CRYPT_CTXINFO_LABEL, keyid, strlen(keyid))   != CRYPT_OK ||
-      cryptSetAttribute(ctx, CRYPT_CTXINFO_KEYSIZE, keysize / 8)                != CRYPT_OK ||
-      cryptGenerateKey(ctx)                                                     != CRYPT_OK ||
-      !p11_object_add_spki(public_handle, private_handle, ctx, p11_object_add_spki_rsa)     ||
-      cryptlib_store_key(ctx)                                                   != CRYPT_OK ||
-      cryptDestroyContext(ctx)                                                  != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);
+  hal_rsa_key_clear(key);
 
   /*
    * Commit the SQL transaction.
@@ -2425,11 +1932,7 @@ static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session,
 
  fail:
 
-  if (ctx != CRYPT_HANDLE_NONE)
-    cryptDestroyContext(ctx);
-
-  if (ctx != CRYPT_HANDLE_NONE && keyid[0] != 0x00)
-    (void) cryptlib_delete_key(keyid);
+  memset(keybuf, 0, sizeof(keybuf));
 
   if (!sql_exec("ROLLBACK"))
     rv = CKR_GENERAL_ERROR;
@@ -2437,6 +1940,54 @@ static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session,
   return rv;
 }
 
+/*
+ * Sign a PKCS #1 DigestInfo using an RSA key and PKCS #1.5 padding.
+ *
+ * As explained in RFC 3447, the RSASP1 (signature generation)
+ * operation is the same mathematical operation as the RSADP
+ * (decryption) operation (both use the private key as exponent).
+ */
+
+static CK_RV sign_rsa_pkcs(hal_rsa_key_t key,
+                           const uint8_t * const digest_info, const size_t digest_info_len,
+                           uint8_t *signature, const size_t signature_len)
+{
+  CK_RV rv;
+
+  assert(digest_info != NULL && signature != NULL);
+
+  /*
+   * Congregation will now please turn to RFC 2313 8.1 as we
+   * construct a PKCS #1.5 type 01 encryption block.
+   */
+
+  if (digest_info_len > signature_len - 11)
+    lose(CKR_DATA_LEN_RANGE);
+
+  signature[0] = 0x00;
+  signature[1] = 0x01;
+  memset(signature + 2, 0xFF, signature_len - 3 - digest_info_len);
+  signature[signature_len - digest_info_len - 1] = 0x00;
+  memcpy(signature + signature_len - digest_info_len, digest_info, digest_info_len);
+
+#if 0
+  fprintf(stderr, "[PKCS #1.5 signature_len %lu digest_info_len %lu block ", signature_len, digest_info_len);
+  for (int i = 0; i < signature_len; i++)
+    fprintf(stderr, "%s%02x", i == 0 ? "" : ":", signature[i]);
+  fprintf(stderr, "]\n");
+#endif
+
+  if (!hal_check(hal_rsa_decrypt(key, signature, signature_len, signature, signature_len)))
+    lose(CKR_FUNCTION_FAILED);
+
+  return CKR_OK;
+
+ fail:
+  memset(signature, 0, signature_len);
+  return rv;
+}
+
+
 

 
 /*
@@ -2445,8 +1996,8 @@ static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session,
 
 CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
 {
-  int initialized_sql = 0, initialized_cryptlib = 0;
   CK_C_INITIALIZE_ARGS_PTR a = pInitArgs;
+  int initialized_sql = 0;
   CK_RV rv;
 
   /*
@@ -2549,26 +2100,8 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
 
   initialized_sql = 1;
 
-  /*
-   * Initialize cryptlib and open the hardware crypto device (our FPGA).
-   *
-   * The option settings are to make sure that internal stuff like the
-   * PKCS #15 keyset code uses algorithms we like.
-   */
-
-  if (cryptInit() != CRYPT_OK)
-    lose(CKR_GENERAL_ERROR);
-
-  initialized_cryptlib = 1;
-
-  if (cryptSetAttribute(CRYPT_UNUSED, CRYPT_OPTION_ENCR_ALGO, CRYPT_ALGO_AES)  != CRYPT_OK ||
-      cryptSetAttribute(CRYPT_UNUSED, CRYPT_OPTION_ENCR_HASH, CRYPT_ALGO_SHA2) != CRYPT_OK)
-    lose(CKR_GENERAL_ERROR);
-
-#if ENABLE_CRYPTLIB_DEVICE
-  if (cryptDeviceOpen(&cryptlib_device, CRYPT_UNUSED, CRYPT_DEVICE_HARDWARE, NULL) != CRYPT_OK)
+  if (!kek_init())
     lose(CKR_GENERAL_ERROR);
-#endif
 
 #if USE_POSIX
   initialized_pid = getpid();
@@ -2578,16 +2111,6 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
 
  fail:
 
-#if ENABLE_CRYPTLIB_DEVICE
-  if (cryptlib_device != CRYPT_HANDLE_NONE) {
-    cryptDeviceClose(cryptlib_device);
-    cryptlib_device = CRYPT_HANDLE_NONE;
-  }
-#endif
-
-  if (initialized_cryptlib)
-    cryptEnd();
-
   if (initialized_sql)
     sql_fini();
 
@@ -2617,19 +2140,6 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved)
     lose(CKR_GENERAL_ERROR);
 
   /*
-   * Shut down hardware device and exit cryptlib.  Is there any point
-   * in checking error codes here?
-   */
-
-#if ENABLE_CRYPTLIB_DEVICE
-  if (cryptlib_device != CRYPT_HANDLE_NONE)
-    cryptDeviceClose(cryptlib_device);
-  cryptlib_device = CRYPT_HANDLE_NONE;
-#endif
-
-  cryptEnd();
-
-  /*
    * By this point we're pretty well committed to shutting down, so
    * there's not much to be done if these mutex operations fail.
    */
@@ -2873,9 +2383,13 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
               CK_UTF8CHAR_PTR pPin,
               CK_ULONG ulPinLen)
 {
+  static const char pin_query_format[] =
+    " SELECT pbkdf2_iterations, %s_pin, %s_pin_salt from global";
+
   p11_session_t *session;
+  sqlite3_stmt *q = NULL;
+  const char *pin_type;
   CK_RV rv = CKR_OK;
-  int crypt_cmd;
 
   mutex_lock_or_return_failure(p11_global_mutex);
 
@@ -2892,20 +2406,6 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
     lose(CKR_SESSION_HANDLE_INVALID);
 
   /*
-   * This is where the combination of pure-software and hardware
-   * starts to get confusing.  See the CRYPT_DEVINFO_* attributes for
-   * the operations we can do during device setup (setting PINs,
-   * logging in using pins, etc).
-   *
-   * All fine, but behaves somewhat differently from the case where
-   * we're doing everything in software and using the PIN primarily as
-   * the encryption password for the PKCS #15 keyring.
-   *
-   * In the long run just want the hardware interface.  This will
-   * require cleanup.
-   */
-
-  /*
    * We don't currently support re-login without an intervening
    * logout, so reject the login attempt if we're already logged in.
    */
@@ -2914,53 +2414,82 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
     lose(CKR_USER_ALREADY_LOGGED_IN);    
 
   /*
+   * Figure out which PIN we're checking.
    * We don't (yet?) support CKU_CONTEXT_SPECIFIC.
-   */
-
-  switch (userType) {
-  case CKU_USER:                crypt_cmd = CRYPT_DEVINFO_AUTHENT_USER;         break;
-  case CKU_SO:                  crypt_cmd = CRYPT_DEVINFO_AUTHENT_SUPERVISOR;   break;
-  case CKU_CONTEXT_SPECIFIC:    lose(CKR_OPERATION_NOT_INITIALIZED);
-  default:                      lose(CKR_USER_TYPE_INVALID);
-  }
-
-  /*
+   *
    * Read-only SO is an illegal state, so reject the login attempt if
    * we have any read-only sessions and we're trying to log in as SO.
    */
 
-  if (userType == CKU_SO)
+  switch (userType) {
+  case CKU_USER:
+    pin_type = "user";
+    break;
+  case CKU_SO:
     for (session = p11_sessions; session != NULL; session = session->link)
       if (session->state == CKS_RO_PUBLIC_SESSION)
         lose(CKR_SESSION_READ_ONLY_EXISTS);
+    pin_type = "so";
+    break;
+  case CKU_CONTEXT_SPECIFIC:
+    lose(CKR_OPERATION_NOT_INITIALIZED);
+  default:
+    lose(CKR_USER_TYPE_INVALID);
+  }
 
   /*
-   * Ask Cryptlib to log us in.  We may need to examine cryptlib error
-   * return more closely than this.
+   * Look up the PIN and make sure it's set.
+   *
+   * Not obvious what error we should return if SO PIN isn't set, for
+   * now consider this state "locked" (because it hasn't been set yet).
    */
 
-#if ENABLE_CRYPTLIB_DEVICE
-  if (cryptSetAttributeString(cryptlib_device, crypt_cmd, pPin, ulPinLen) != CRYPT_OK)
-    lose(CKR_PIN_INCORRECT);
-#endif
+  if (!sql_check_ok(sql_prepare(&q, pin_query_format, pin_type, pin_type)) ||
+      !sql_check_row(sqlite3_step(q)))
+    lose(CKR_FUNCTION_FAILED);
+
+  if (sqlite3_column_type(q, 1) == SQLITE_NULL ||
+      sqlite3_column_type(q, 2) == SQLITE_NULL) {
+    switch (userType) {
+    case CKU_USER:
+      lose(CKR_USER_PIN_NOT_INITIALIZED);
+    case CKU_SO:
+      lose(CKR_PIN_LOCKED);
+    default:
+      lose(CKR_USER_TYPE_INVALID);
+    }
+  }
+
+  /*
+   * Run PBKDF2 over the supplied PIN and compare results.
+   *
+   * Probably not really necessary to use constant-time string
+   * comparison, but it's harmless and cheap, so we might as well.
+   */
 
-#if ENABLE_CRYPTLIB_SOFTWARE
   {
-    char *newpin;
-    if (memchr(pPin, '\0', ulPinLen) != NULL)
+    const unsigned iterations = sqlite3_column_int(q, 0);
+    const uint8_t * const pin  = sqlite3_column_blob(q, 1);
+    const uint8_t * const salt = sqlite3_column_blob(q, 2);
+    const size_t pin_len  = sqlite3_column_bytes(q, 1);
+    const size_t salt_len = sqlite3_column_bytes(q, 2);
+    uint8_t pinbuf[pin_len];
+    unsigned diff = 0;
+
+    if (!hal_check(hal_pbkdf2(hal_hash_sha256, pPin, ulPinLen, salt, salt_len,
+                              pinbuf, sizeof(pinbuf), iterations)))
+      lose(CKR_FUNCTION_FAILED);
+
+    for (int i = 0; i < pin_len; i++)
+      diff |= pin[i] ^ pinbuf[i];
+
+    if (diff != 0)
       lose(CKR_PIN_INCORRECT);
-    if ((newpin = malloc(ulPinLen + 1)) == NULL)
-      lose(CKR_HOST_MEMORY);
-    memcpy(newpin, pPin, ulPinLen);
-    newpin[ulPinLen] = '\0';
-    if (pin != NULL)
-      free(pin);
-    pin = newpin;
   }
-#endif
 
   /*
-   * Update global login state, then whack each session into correct new state.
+   * If we get here, the PIN was OK.  Update global login state, then
+   * whack every session into the correct new state.
    */
 
   assert(p11_session_consistent_login());
@@ -2985,6 +2514,7 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
   assert(p11_session_consistent_login());
 
  fail:
+  sqlite3_finalize(q);
   mutex_unlock_return_with_rv(rv, p11_global_mutex);
 }
 
@@ -2992,7 +2522,6 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession)
 {
   p11_session_t *session;
   CK_RV rv = CKR_OK;
-  int crypt_cmd;
 
   mutex_lock_or_return_failure(p11_global_mutex);
 
@@ -3005,31 +2534,8 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession)
   if (p11_session_find(hSession) == NULL)
     lose(CKR_SESSION_HANDLE_INVALID);
 
-  switch (logged_in_as) {
-  case logged_in_as_user:       crypt_cmd = CRYPT_DEVINFO_AUTHENT_USER;         break;
-  case logged_in_as_so:         crypt_cmd = CRYPT_DEVINFO_AUTHENT_SUPERVISOR;   break;
-  case not_logged_in:           lose(CKR_USER_NOT_LOGGED_IN);
-  }
-
-  /*
-   * This is a bit problematic, because Cryptlib doesn't have a logout
-   * function per se.  For lack of a better idea, construe logout as a
-   * new authentication attempt with an empty PIN.  This is a little
-   * weird, but at least it's something we can use as a relatively
-   * clear signal to the HAL, and it's consistent with the way
-   * cryptlib does things like terminating digest inputs.
-   */
-
-#if ENABLE_CRYPTLIB_DEVICE
-  if (cryptSetAttributeString(cryptlib_device, crypt_cmd, "", 0) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);
-#endif
-
-#if ENABLE_CRYPTLIB_SOFTWARE
-  if (pin != NULL)
-    free(pin);
-  pin = NULL;
-#endif
+  if (logged_in_as == not_logged_in)
+    lose(CKR_USER_NOT_LOGGED_IN);
 
   /*
    * Update global login state, then delete any private objects and
@@ -3066,20 +2572,16 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession)
 CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession,
                       CK_OBJECT_HANDLE hObject)
 {
-  static const char select_format[] =
-    " SELECT %s_object_id, keyid FROM object NATURAL JOIN %s_object WHERE object_handle = ?1";
-
   static const char delete_object[] =
     " DELETE FROM object WHERE object_handle = ?";
 
   static const char delete_token_object[] =
-    " DELETE FROM token_object WHERE token_object_id = ?";
-
-  const char *flavor = is_token_handle(hObject) ? "token" : "session";
+    " WITH"
+    "   t AS (SELECT token_object_id FROM object WHERE object_handle = ?)"
+    " DELETE FROM token_object WHERE token_object_id = t";
 
   p11_session_t *session;
   sqlite3_stmt *q = NULL;
-  sqlite3_int64 id;
   CK_RV rv = CKR_OK;
 
   mutex_lock_or_return_failure(p11_global_mutex);
@@ -3089,39 +2591,15 @@ CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession,
   if ((rv = p11_object_check_rights(session, hObject, p11_object_access_write)) != CKR_OK)
     goto fail;
 
-  if (!sql_check_ok(sql_prepare(&q, select_format, flavor, flavor)) ||
-      !sql_check_ok(sqlite3_bind_int64(q, 1, hObject)))
-    lose(CKR_FUNCTION_FAILED);
-
-  switch (sqlite3_step(q)) {
-  case SQLITE_ROW:
-    break;
-  case SQLITE_DONE:
-    lose(CKR_OBJECT_HANDLE_INVALID);
-  default:
-    sql_whine_step();
-    lose(CKR_FUNCTION_FAILED);
-  }
-
-  id = sqlite3_column_int64(q, 0);
-
-  if (sqlite3_column_type(q, 1) == SQLITE_TEXT &&
-      cryptlib_delete_key((const char *) sqlite3_column_text(q, 1)) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);
-
-  sqlite3_finalize(q);
-  q = NULL;
-
   if (is_token_handle(hObject)                                  &&
       (!sql_check_ok(sql_prepare(&q, delete_token_object))      ||
-       !sql_check_ok(sqlite3_bind_int64(q, 1, id))              ||
-       !sql_check_done(sqlite3_step(q))))
+       !sql_check_ok(sqlite3_bind_int64(q, 1, hObject))         ||
+       !sql_check_done(sqlite3_step(q))                         ||
+       !sql_check_ok(sql_finalize_and_clear(&q))))
     lose(CKR_FUNCTION_FAILED);
 
-  sqlite3_finalize(q);
-  q = NULL;
-
-  if (!sql_check_ok(sql_prepare(&q, delete_object))     ||
+  if (
+      !sql_check_ok(sql_prepare(&q, delete_object))     ||
       !sql_check_ok(sqlite3_bind_int64(q, 1, hObject))  ||
       !sql_check_done(sqlite3_step(q)))
     lose(CKR_FUNCTION_FAILED);
@@ -3300,10 +2778,6 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession,
     lose(CKR_FUNCTION_FAILED);
   }
 
-  sqlite3_finalize(q1);
-  sqlite3_finalize(q2);
-  q1 = q2 = NULL;
-
   /*
    * Create a temporary table to hold this session's FindObjects
    * state.  Populate this with every object this session knows about,
@@ -3311,27 +2785,30 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession,
    * the caller supplied.
    */
 
-  if (!sql_check_ok(sql_prepare(&q1, drop_format, hSession))    ||
+  if (!sql_check_ok(sql_finalize_and_clear(&q1))                ||
+      !sql_check_ok(sql_finalize_and_clear(&q2))                ||
+      !sql_check_ok(sql_prepare(&q1, drop_format, hSession))    ||
       !sql_check_done(sqlite3_step(q1))                         ||
       !sql_check_ok(sql_prepare(&q2, create_format, hSession))  ||
       !sql_check_ok(sqlite3_bind_int64(q2, 1, hSession))        ||
-      !sql_check_done(sqlite3_step(q2)))
-    lose(CKR_FUNCTION_FAILED);
-
-  sqlite3_finalize(q1);
-  sqlite3_finalize(q2);
-  q1 = q2 = NULL;
-
-  if (!sql_check_ok(sql_prepare(&q1, delete_format, hSession)))
+      !sql_check_done(sqlite3_step(q2))                         ||
+      !sql_check_ok(sql_finalize_and_clear(&q1))                ||
+      !sql_check_ok(sql_finalize_and_clear(&q2))                ||
+      !sql_check_ok(sql_prepare(&q1, delete_format, hSession)))
     lose(CKR_FUNCTION_FAILED);
 
   /*
-   * We only see private objects when logged in as the regular user.
+   * If we're not logged in as the regular user, run an extra filter
+   * cycle to remove all private objects before we get to the
+   * caller-supplied template.
    */
 
   if (logged_in_as != logged_in_as_user) {
-    if (!sql_check_ok(sqlite3_bind_int64(q1, 1, CKA_PRIVATE)) ||
-        !sql_check_ok(sqlite3_bind_blob(q1, 2, &const_CK_FALSE, sizeof(const_CK_FALSE), NULL)) ||
+    if (!sql_check_ok(sqlite3_bind_int64(q1, 1, CKA_PRIVATE))   ||
+        !sql_check_ok(sqlite3_bind_blob( q1, 2,
+                                         &const_CK_FALSE,
+                                         sizeof(const_CK_FALSE),
+                                         NULL))                 ||
         !sql_check_done(sqlite3_step(q1)))
       lose(CKR_FUNCTION_FAILED);
   }
@@ -3441,10 +2918,8 @@ CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
    * Clean up result query and temporary table.
    */
 
-  sqlite3_finalize(session->find_query);
-  session->find_query = NULL;
-
-  if (!sql_check_ok(sql_prepare(&q, drop_format, hSession)) ||
+  if (!sql_check_ok(sql_finalize_and_clear(&session->find_query))       ||
+      !sql_check_ok(sql_prepare(&q, drop_format, hSession))             ||
       !sql_check_done(sqlite3_step(q)))
     lose(CKR_FUNCTION_FAILED);
 
@@ -3457,8 +2932,6 @@ CK_RV C_DigestInit(CK_SESSION_HANDLE hSession,
                    CK_MECHANISM_PTR pMechanism)
 {
   p11_session_t *session;
-  CRYPT_ALGO_TYPE algo;
-  unsigned hash_len = 0;
   CK_RV rv = CKR_OK;
 
   mutex_lock_or_return_failure(p11_global_mutex);
@@ -3469,33 +2942,25 @@ CK_RV C_DigestInit(CK_SESSION_HANDLE hSession,
   if (pMechanism == NULL)
     lose(CKR_ARGUMENTS_BAD);
 
-  if (session->digest_context != CRYPT_HANDLE_NONE)
+  if (session->digest_descriptor != NULL)
     lose(CKR_OPERATION_ACTIVE);
 
   switch (pMechanism->mechanism) {
-  case CKM_SHA_1:       algo = CRYPT_ALGO_SHA1; break;
-  case CKM_SHA256:      algo = CRYPT_ALGO_SHA2; hash_len = 256; break;
-  case CKM_SHA384:      algo = CRYPT_ALGO_SHA2; hash_len = 384; break;
-  case CKM_SHA512:      algo = CRYPT_ALGO_SHA2; hash_len = 512; break;
+  case CKM_SHA_1:       session->digest_descriptor = hal_hash_sha1;   break;
+  case CKM_SHA256:      session->digest_descriptor = hal_hash_sha256; break;
+  case CKM_SHA384:      session->digest_descriptor = hal_hash_sha384; break;
+  case CKM_SHA512:      session->digest_descriptor = hal_hash_sha512; break;
   default:              lose(CKR_MECHANISM_INVALID);
   }
 
-  assert((hash_len & 7) == 0);
-
-  if (cryptlib_create_context(&session->digest_context, algo) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);    
-
-  if (algo == CRYPT_ALGO_SHA2 &&
-      cryptSetAttribute(session->digest_context, CRYPT_CTXINFO_BLOCKSIZE, hash_len >> 3) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);
+  if (!hal_check(hal_hash_core_present(session->digest_descriptor))) {
+    session->digest_descriptor = NULL;
+    lose(CKR_MECHANISM_INVALID);
+  }
 
   return mutex_unlock(p11_global_mutex);
 
  fail:
-  if (session != NULL && session->digest_context != CRYPT_HANDLE_NONE) {
-    cryptDestroyContext(session->digest_context);
-    session->digest_context = CRYPT_HANDLE_NONE;
-  }
   mutex_unlock_return_with_rv(rv, p11_global_mutex);
 }
 
@@ -3507,7 +2972,6 @@ CK_RV C_Digest(CK_SESSION_HANDLE hSession,
 {
   p11_session_t *session;
   CK_RV rv = CKR_OK;
-  int len;
 
   mutex_lock_or_return_failure(p11_global_mutex);
 
@@ -3517,43 +2981,35 @@ CK_RV C_Digest(CK_SESSION_HANDLE hSession,
   if (pData == NULL || pulDigestLen == NULL)
     lose(CKR_ARGUMENTS_BAD);
 
-  if (session->digest_context == CRYPT_HANDLE_NONE)
+  if (session->digest_descriptor == NULL)
     lose(CKR_OPERATION_NOT_INITIALIZED);
 
-  if (pDigest == NULL) {
-    if (cryptGetAttribute(session->digest_context, CRYPT_CTXINFO_BLOCKSIZE, &len) != CRYPT_OK)
-      lose(CKR_FUNCTION_FAILED);
-    *pulDigestLen = len;
-    return mutex_unlock(p11_global_mutex);
-  }
-
-  if (cryptEncrypt(session->digest_context, pData, ulDataLen) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);
+  rv = *pulDigestLen < session->digest_descriptor->digest_length ? CKR_BUFFER_TOO_SMALL : CKR_OK;
 
-  if (ulDataLen != 0 &&
-      cryptEncrypt(session->digest_context, pData, 0) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);
+  *pulDigestLen = session->digest_descriptor->digest_length;
 
-  if (cryptGetAttributeString(session->digest_context,
-                              CRYPT_CTXINFO_HASHVALUE, NULL, &len) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);
+  if (pDigest == NULL)
+    return mutex_unlock(p11_global_mutex);
 
-  if (len > *pulDigestLen)
+  if (rv == CKR_BUFFER_TOO_SMALL)
     lose(CKR_BUFFER_TOO_SMALL);
 
-  if (cryptGetAttributeString(session->digest_context,
-                              CRYPT_CTXINFO_HASHVALUE, pDigest, &len) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);
+  {
+    uint8_t statebuf[session->digest_descriptor->hash_state_length];
+    hal_hash_state_t state = { NULL };
 
-  *pulDigestLen = len;
+    if (!hal_check(hal_hash_initialize(session->digest_descriptor,
+                                       &state, statebuf, sizeof(statebuf)))     ||
+        !hal_check(hal_hash_update(state, pData, ulDataLen))                    ||
+        !hal_check(hal_hash_finalize(state, pDigest, *pulDigestLen)))
+      lose(CKR_FUNCTION_FAILED);
+  }
 
   rv = CKR_OK;                  /* Fall through */
 
  fail:
-  if (session != NULL && session->digest_context != CRYPT_HANDLE_NONE) {
-    cryptDestroyContext(session->digest_context);
-    session->digest_context = CRYPT_HANDLE_NONE;
-  }
+  if (session != NULL)
+    session->digest_descriptor = NULL;
   mutex_unlock_return_with_rv(rv, p11_global_mutex);
 }
 
@@ -3562,11 +3018,6 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession,
                  CK_OBJECT_HANDLE hKey)
 {
   p11_session_t *session;
-  char keyid[CRYPT_MAX_HASHSIZE * 2 + 1];
-  CRYPT_ALGO_TYPE sign_algo, hash_algo;
-  unsigned hash_size = 0;
-  int need_cleanup = 0;
-  int key_algo;
   CK_RV rv = CKR_OK;
 
   mutex_lock_or_return_failure(p11_global_mutex);
@@ -3577,60 +3028,35 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession,
   if (pMechanism == NULL)
     lose(CKR_ARGUMENTS_BAD);
 
-  if (session->sign_key_context    != CRYPT_HANDLE_NONE ||
-      session->sign_digest_context != CRYPT_HANDLE_NONE)
+  if (session->sign_key_handle != CK_INVALID_HANDLE || session->sign_digest_descriptor != NULL)
     lose(CKR_OPERATION_ACTIVE);
 
   if ((rv = p11_object_check_rights(session, hKey, p11_object_access_read)) != CKR_OK)
     goto fail;
 
+  /*
+   * Will need to check key algorithm type here once we add support
+   * for signature algorithms other than RSA.
+   */
+
+  session->sign_key_handle = hKey;
+
   switch (pMechanism->mechanism) {
-  case CKM_RSA_PKCS:            sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_NONE; break;
-  case CKM_SHA1_RSA_PKCS:       sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_SHA1; break;
-  case CKM_SHA256_RSA_PKCS:     sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_SHA2; hash_size = 256; break;
-  case CKM_SHA384_RSA_PKCS:     sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_SHA2; hash_size = 384; break;
-  case CKM_SHA512_RSA_PKCS:     sign_algo = CRYPT_ALGO_RSA; hash_algo = CRYPT_ALGO_SHA2; hash_size = 512; break;
+  case CKM_RSA_PKCS:            session->sign_digest_descriptor = NULL;                 break;
+  case CKM_SHA1_RSA_PKCS:       session->sign_digest_descriptor = hal_hash_sha1;        break;
+  case CKM_SHA256_RSA_PKCS:     session->sign_digest_descriptor = hal_hash_sha256;      break;
+  case CKM_SHA384_RSA_PKCS:     session->sign_digest_descriptor = hal_hash_sha384;      break;
+  case CKM_SHA512_RSA_PKCS:     session->sign_digest_descriptor = hal_hash_sha512;      break;
   default:                      return CKR_MECHANISM_INVALID;
   }
 
-  assert((hash_size & 7) == 0);
-
-  need_cleanup = 1;
-
-  if (!p11_object_get_keyid(hKey, keyid, sizeof(keyid)) ||
-      cryptlib_load_key(&session->sign_key_context, keyid) != CRYPT_OK ||
-      cryptGetAttribute(session->sign_key_context, CRYPT_CTXINFO_ALGO, &key_algo) != CRYPT_OK)
-    lose(CKR_KEY_HANDLE_INVALID);
-
-  if (sign_algo != key_algo)
-    lose(CKR_KEY_TYPE_INCONSISTENT);
-
-  if (hash_algo != CRYPT_ALGO_NONE &&
-      cryptlib_create_context(&session->sign_digest_context, hash_algo) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);    
-
-  if (hash_algo == CRYPT_ALGO_SHA2 &&
-      cryptSetAttribute(session->sign_digest_context,
-                        CRYPT_CTXINFO_BLOCKSIZE, hash_size >> 3) != CRYPT_OK)
-    lose(CKR_FUNCTION_FAILED);
-
-  need_cleanup = 0;
-
-  rv = CKR_OK;                  /* Fall through */
+  return mutex_unlock(p11_global_mutex);
 
  fail:
-  assert(!need_cleanup || session != NULL);
-
-  if (need_cleanup && session->sign_key_context != CRYPT_HANDLE_NONE) {
-    cryptDestroyContext(session->sign_key_context);
-    session->sign_key_context = CRYPT_HANDLE_NONE;
-  }
-
-  if (need_cleanup && session->sign_digest_context != CRYPT_HANDLE_NONE) {
-    cryptDestroyContext(session->sign_digest_context);
-    session->sign_digest_context = CRYPT_HANDLE_NONE;
+  if (session != NULL) {
+    session->sign_key_handle = CK_INVALID_HANDLE;
+    session->sign_digest_descriptor = NULL;
   }
-
   mutex_unlock_return_with_rv(rv, p11_global_mutex);
 }
 
@@ -3640,8 +3066,10 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession,
              CK_BYTE_PTR pSignature,
              CK_ULONG_PTR pulSignatureLen)
 {
+  uint8_t keybuf[hal_rsa_key_t_size];
+  hal_rsa_key_t key = { NULL };
   p11_session_t *session;
-  int len, algo;
+  size_t signature_len;
   CK_RV rv;
 
   mutex_lock_or_return_failure(p11_global_mutex);
@@ -3652,160 +3080,111 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession,
   if (pData == NULL || pulSignatureLen == NULL)
     lose(CKR_ARGUMENTS_BAD);
 
-  if (session->sign_key_context == CRYPT_HANDLE_NONE)
+  if (session->sign_key_handle == CK_INVALID_HANDLE)
     lose(CKR_OPERATION_NOT_INITIALIZED);
 
-  if (pSignature == NULL) {
-    /*
-     * Caller just wants to know the signature length, which we can
-     * get from cryptCreateSignature(), using a dummy hash context if
-     * necessary.
-     *
-     * There may be an easier way: at least for RSA, reading the key's
-     * CRYPT_CTXINFO_KEYSIZE would give us the answer.  But the
-     * constraint that messages_size == key_size doesn't necessarily
-     * hold for all asymmetric algorithms, so best to be safe here.
-     */
-
-    CRYPT_CONTEXT ctx = session->sign_digest_context;
-
-    if (ctx == CRYPT_HANDLE_NONE && cryptCreateContext(&ctx, CRYPT_UNUSED, CRYPT_ALGO_SHA2) != CRYPT_OK)
-      lose(CKR_FUNCTION_FAILED);
-
-    if (cryptCreateSignature(NULL, 0, &len, session->sign_key_context, ctx) != CRYPT_OK)
-      len = 0;
+  /*
+   * From here down this function is RSA-specific, and will need
+   * rewriting when we add support for other algorithms.
+   */
 
-    if (session->sign_digest_context == CRYPT_HANDLE_NONE)
-      cryptDestroyContext(ctx);
+  if (!p11_object_get_rsa_private_key(session->sign_key_handle,
+                                      &key, keybuf, sizeof(keybuf)))
+    lose(CKR_FUNCTION_FAILED);
 
-    if (len == 0)
-      lose(CKR_FUNCTION_FAILED);
-  }
+  /*
+   * Retrieve signature length.  For RSA this is just the modulus
+   * length, other algorithms will need a more generic solution.
+   */
 
-  else if (session->sign_digest_context != CRYPT_HANDLE_NONE) {
-    /*
-     * Caller wanted a hash-and-sign operation, so we can use cryptCreateSignature().
-     */
+  if (!hal_check(hal_rsa_key_get_modulus(key, NULL, &signature_len, 0)))
+    lose(CKR_FUNCTION_FAILED);
 
-    if (cryptEncrypt(session->sign_digest_context, pData, ulDataLen) != CRYPT_OK)
-      lose(CKR_FUNCTION_FAILED);
+  rv = signature_len > *pulSignatureLen ? CKR_BUFFER_TOO_SMALL : CKR_OK;
 
-    if (ulDataLen != 0 &&
-        cryptEncrypt(session->sign_digest_context, pData, 0) != CRYPT_OK)
-      lose(CKR_FUNCTION_FAILED);
+  *pulSignatureLen = signature_len;
 
-    if (cryptCreateSignature(pSignature, *pulSignatureLen, &len,
-                             session->sign_key_context,
-                             session->sign_digest_context) != CRYPT_OK)
-      lose(CKR_FUNCTION_FAILED);
+  if (pSignature == NULL) {
+    hal_rsa_key_clear(key);
+    return mutex_unlock(p11_global_mutex);
   }
 
-  else {
+  if (rv == CKR_BUFFER_TOO_SMALL)
+    lose(CKR_BUFFER_TOO_SMALL);
 
+  if (session->sign_digest_descriptor != NULL) {
     /*
-     * Caller wanted a pure-signature operation, have to use
-     * cryptDeCrypt() [sic].
+     * Caller wanted a hash-and-sign operation.  We need to hash the
+     * caller's data and construct a DigestInfo SEQUENCE.
      *
-     * At the moment we just blindly sign this without checking that
-     * what we're signing really is (eg) a valid DigestInfo SEQUENCE.
-     * Should we bother checking the syntax here, given that we have
-     * no way of checking the digest itself (if we get here, we've
-     * never seen the original plaintext, just the purported digest)?
+     * This probably ought to be a library function somewhere.
      */
 
-    if (cryptGetAttribute(session->sign_key_context, CRYPT_CTXINFO_ALGO,   &algo) != CRYPT_OK ||
-        cryptGetAttribute(session->sign_key_context, CRYPT_CTXINFO_KEYSIZE, &len) != CRYPT_OK)
-      lose(CKR_FUNCTION_FAILED);
-
-    switch (algo) {
-
-    case CRYPT_ALGO_RSA:
+    const hal_hash_descriptor_t *desc = session->sign_digest_descriptor;
+    uint8_t digest_info[desc->digest_length + desc->digest_algorithm_id_length + 4];
+    uint8_t statebuf[session->digest_descriptor->hash_state_length];
+    hal_hash_state_t state = { NULL };
+    uint8_t *d = digest_info;
 
-      /*
-       * Congregation will now please turn to RFC 2313 8.1 as we
-       * construct a PKCS #1.5 type 01 encryption block.
-       */
-
-      if (len > *pulSignatureLen)
-        lose(CKR_BUFFER_TOO_SMALL);
+    /*
+     * This encoder will fail if the DigestInfo object is more than
+     * 129 octets long.  Rewrite if and when we need to support
+     * digests or OIDs long enough for that to be an issue.
+     */
+    assert(sizeof(digest_info) < 130);
 
-      if (ulDataLen > len - 11)
-        return CKR_DATA_LEN_RANGE;
+    *d++ = 0x30;                /* SEQUENCE */
+    *d++ = (uint8_t) (sizeof(digest_info) - 2);
 
-      pSignature[0] = 0x00;
-      pSignature[1] = 0x01;
-      memset(pSignature + 2, 0xFF, len - 3 - ulDataLen);
-      pSignature[len - ulDataLen - 1] = 0x00;
-      memcpy(pSignature + len - ulDataLen, pData, ulDataLen);
+    memcpy(d, desc->digest_algorithm_id, desc->digest_algorithm_id_length);
+    d += desc->digest_algorithm_id_length;
 
-#if 0
-      /* XXX */
-      {
-        int i;
-        fprintf(stderr, "[PKCS #1.5 len %lu ulDataLen %lu block ", len, ulDataLen);
-        for (i = 0; i < len; i++)
-          fprintf(stderr, "%s%02x", i == 0 ? "" : ":", pSignature[i]);
-        fprintf(stderr, "]\n");
-      }
-#endif
+    *d++ = 0x04;                /* OCTET STRING */
+    *d++ = (uint8_t) desc->digest_length;
 
-      break;
+    assert(digest_info + sizeof(digest_info) == d + desc->digest_length);
 
-    default:
+    if (!hal_check(hal_hash_initialize(desc, &state, statebuf, sizeof(statebuf))) ||
+        !hal_check(hal_hash_update(state, pData, ulDataLen))                      ||
+        !hal_check(hal_hash_finalize(state, d, desc->digest_length))) {
+      memset(digest_info, 0, sizeof(digest_info));
       lose(CKR_FUNCTION_FAILED);
     }
 
+    rv = sign_rsa_pkcs(key, digest_info, sizeof(digest_info), pSignature, signature_len);
+    memset(digest_info, 0, sizeof(digest_info));
+    if (rv != CKR_OK)
+      goto fail;
+  }
+
+  else {
+
     /*
-     * The terms "encrypt" and "decrypt" get weird when one goes this
-     * far past the API that a sane person would be using.  As
-     * explained in RFC 3447, the RSASP1 (signature generation)
-     * operation is the same mathematical operation as the RSADP
-     * (decryption) operation, so we have to use cryptDecrypt(), not
-     * cryptEncrypt() here.  No, really.
-     *
-     * Well, this works for RSA, anyway.  ECDSA may turn out to be a
-     * whole different bucket of monkey guts.
+     * Caller wanted a pure-signature operation.  We assume that input
+     * is a valid DigestInfo SEQUENCE: we've never seen the original
+     * plaintext, thus can't check the hash, so there's not much point
+     * in checking the ASN.1 structure.
      */
 
-    if (cryptDecrypt(session->sign_key_context, pSignature, len) != CRYPT_OK)
-      lose(CKR_FUNCTION_FAILED);
+    if ((rv = sign_rsa_pkcs(key, pData, ulDataLen, pSignature, signature_len)) != CKR_OK)
+      goto fail;
   }
 
-  *pulSignatureLen = len;
-
   rv = CKR_OK;                  /* Fall through */
 
  fail:
 
-  if (session != NULL && session->sign_digest_context != CRYPT_HANDLE_NONE) {
-    cryptDestroyContext(session->sign_digest_context);
-    session->sign_digest_context = CRYPT_HANDLE_NONE;
+  if (session != NULL) {
+    session->sign_key_handle = CK_INVALID_HANDLE;
+    session->sign_digest_descriptor = NULL;
   }
 
-  if (session != NULL && session->sign_key_context != CRYPT_HANDLE_NONE) {
-    cryptDestroyContext(session->sign_key_context);
-    session->sign_key_context = CRYPT_HANDLE_NONE;
-  }
+  hal_rsa_key_clear(key);
 
   mutex_unlock_return_with_rv(rv, p11_global_mutex);
 }
 
 /*
- * libhsm only uses C_GenerateKey() for DSA parameter generation.
- * More general use presumably wants this for things like generating
- * symmetric keys for later wrapping by asymmetric keys.
- */
-
-CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession,
-                    CK_MECHANISM_PTR pMechanism,
-                    CK_ATTRIBUTE_PTR pTemplate,
-                    CK_ULONG ulCount,
-                    CK_OBJECT_HANDLE_PTR phKey)
-{
-  return CKR_FUNCTION_NOT_SUPPORTED;
-}
-
-/*
  * If there's any method in this entire package which really needs a
  * more complex mutex structure than the single global mutex, it's
  * probably this one.  Key generation can take a looooong time.
@@ -3856,7 +3235,6 @@ CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession,
                        CK_ULONG ulRandomLen)
 {
   p11_session_t *session;
-  CRYPT_CONTEXT ctx = CRYPT_HANDLE_NONE;
   CK_RV rv = CKR_OK;
 
   mutex_lock_or_return_failure(p11_global_mutex);
@@ -3867,25 +3245,10 @@ CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession,
   if (RandomData == NULL)
     lose(CKR_ARGUMENTS_BAD);
 
-  /*
-   * Cryptlib doesn't expose the raw TRNG, but, per the manual, block
-   * cipher encryption output with a randomly generated key is good
-   * enough for most sane purposes.
-   *
-   * Not certain why the Cryptlib manual suggests using CFB mode
-   * instead of OFB mode here, but going with the manual for now.
-   */
-
-  if (cryptCreateContext(&ctx, CRYPT_UNUSED, CRYPT_ALGO_AES)     != CRYPT_OK ||
-      cryptSetAttribute(ctx, CRYPT_CTXINFO_MODE, CRYPT_MODE_CFB) != CRYPT_OK ||
-      cryptGenerateKey(ctx)                                      != CRYPT_OK ||
-      cryptEncrypt(ctx, RandomData, ulRandomLen)                 != CRYPT_OK)
+  if (!hal_check(hal_get_random(RandomData, ulRandomLen)))
     lose(CKR_FUNCTION_FAILED);
 
  fail:
-  if (ctx != CRYPT_HANDLE_NONE)
-    (void) cryptDestroyContext(ctx);
-
   mutex_unlock_return_with_rv(rv, p11_global_mutex);
 }
 
@@ -3904,6 +3267,13 @@ CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession,
  * there are enough bald yaks in this saga already.
  */
 
+CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession,
+                    CK_MECHANISM_PTR pMechanism,
+                    CK_ATTRIBUTE_PTR pTemplate,
+                    CK_ULONG ulCount,
+                    CK_OBJECT_HANDLE_PTR phKey)
+{ return CKR_FUNCTION_NOT_SUPPORTED; }
+
 CK_RV C_GetInfo(CK_INFO_PTR pInfo)
 { return CKR_FUNCTION_NOT_SUPPORTED; }
 
diff --git a/schema.sql b/schema.sql
index 82d9482..0ff5562 100644
--- a/schema.sql
+++ b/schema.sql
@@ -51,6 +51,55 @@
 
 PRAGMA foreign_keys = ON;
 
+-- Values we have to store somewhere and for which we have no better
+-- place.  This is a table with exactly one row (enforced by the CHECK
+-- clause on the primary index).  All columns must either allow NULL
+-- or provide default values.
+
+CREATE TABLE IF NOT EXISTS global (
+       global_id                INTEGER PRIMARY KEY NOT NULL DEFAULT 1 CHECK (global_id = 1),
+
+       -- Key-encryption-key (KEK)
+       --
+       -- The KEK **really** should be somewhere else, like in RAM
+       -- protected by tamper detection circuitry, but we don't have
+       -- that yet.  Not obvious that a separate file would be more
+       -- secure, so keep it here until we do have a better place.
+
+       kek                      BLOB CHECK (kek IS NULL OR (typeof(kek) = "blob" AND length(kek) IN (16, 32))),
+
+       -- PBKDF2-based PIN storage and check values.
+       --
+       -- "so_pin" and "user_pin" are PBKDF2 output, so only
+       -- moderately sensitive.
+       --
+       -- Not obvious that PKCS #11 ever really allows "so_pin" to be
+       -- unset, so it may want a NOT NULL constraint, but in that
+       -- case we'll need to provide a default value, which doesn't
+       -- seem like much of an improvement.  "so_pin" probably
+       -- requires out-of-band initialization.  "user-pin" is allowed
+       -- to be unset, there's an error code specifically for that
+       -- situation.
+       --
+       -- Numeric minima for PBKDF2 iterations, length of PIN, and
+       -- length of PBKDF2 salt are somewhat arbitrary, and will
+       -- probably change over time (which is why they are minima).
+       -- Feel free to suggest better minima.
+
+       pbkdf2_iterations        INTEGER NOT NULL DEFAULT 100000,
+       so_pin                   BLOB,
+       user_pin                 BLOB,
+       so_pin_salt,             BLOB,
+       user_pin_salt            BLOB,
+       CHECK ((pbkdf2_iterations >= 100000)                                                               AND
+              (so_pin        IS NULL OR (typeof(so_pin)        = "blob" AND length(so_pin)        >= 32)) AND
+              (user_pin      IS NULL OR (typeof(user_pin)      = "blob" AND length(user_pin)      >= 32)) AND
+              (so_pin_salt   IS NULL OR (typeof(so_pin_salt)   = "blob" AND length(so_pin_salt)   >= 16)) AND
+              (user_pin_salt IS NULL OR (typeof(user_pin_salt) = "blob" AND length(user_pin_salt) >= 16)))
+);
+
+INSERT OR IGNORE INTO global DEFAULT VALUES;
+
 CREATE TEMPORARY TABLE IF NOT EXISTS session (
         session_id              INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
         session_handle          INTEGER NOT NULL UNIQUE
@@ -75,7 +124,7 @@ CREATE TEMPORARY TABLE IF NOT EXISTS object (
 
 CREATE TEMPORARY TABLE IF NOT EXISTS session_object (
         session_object_id       INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
-        keyid                   TEXT UNIQUE,
+        private_key             BLOB UNIQUE,
         object_id               INTEGER NOT NULL UNIQUE
                                 REFERENCES object
                                 ON DELETE CASCADE ON UPDATE CASCADE
@@ -92,7 +141,7 @@ CREATE TEMPORARY TABLE IF NOT EXISTS session_attribute (
 
 CREATE TABLE IF NOT EXISTS token_object (
         token_object_id         INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
-        keyid                   TEXT UNIQUE
+        private_key             BLOB UNIQUE
 );
 
 CREATE TABLE IF NOT EXISTS token_attribute (



More information about the Commits mailing list