aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2015-06-22 20:18:27 -0400
committerRob Austein <sra@hactrn.net>2015-06-22 20:18:27 -0400
commit291a2e0b6a37ffcc3325388c5fdad63d8f185130 (patch)
tree831bceb929d07d3a826fb3012930e9c848769405
parent67d2f799fb76197d78bbf8ab6d76557f09f30114 (diff)
Convert from Cryptlib to libhal. Compiles, not yet tested otherwise.
-rw-r--r--GNUmakefile12
-rw-r--r--pkcs11.c1618
-rw-r--r--schema.sql53
3 files changed, 549 insertions, 1134 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.
+ * Error checking for libhal calls.
*/
-/*
- * Construct name of configuration file if we don't already have it cached.
- */
-
-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];
- }
+ static const char test_kek[] =
+ " SELECT kek IS NULL FROM global";
- else {
- hlen = 2 + (der[1] & 0x7F);
- vlen = 0;
+ static const char set_kek[] =
+ " UPDATE global SET kek = ?1";
- if (hlen >= len)
- return 0;
+ sqlite3_stmt *q = NULL;
- for (i = 2; i < hlen; i++)
- vlen = (vlen << 8) + der[i];
- }
+ int ok = (sql_check_ok(sql_prepare(&q, test_kek)) &&
+ sql_check_row(sqlite3_step(q)));
- if (hlen + vlen > len)
- return 0;
+ if (ok && sqlite3_column_int(q, 0)) {
+ uint8_t kekbuf[bitsToBytes(256)];
- *phlen = hlen;
- *pvlen = vlen;
- return 1;
-}
+ 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)));
-/*
- * 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 (der == NULL || len == NULL || !asn1_prep(tag, *der, *len, &hlen, &vlen))
- return 0;
-
- 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.
*
- * This may require calculating the keyid from the CKA_ID attribute.
+ * Write the key as PKCS #1.5 RSAPrivateKey DER, encrypt that using
+ * AES key wrap, and store the result as an SQL blob.
+ *
+ * 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;
- 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));
+ 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)));
+
+ 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,41 +1507,18 @@ 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;
-
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,27 +2100,9 @@ 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)
+ if (!kek_init())
lose(CKR_GENERAL_ERROR);
-#if ENABLE_CRYPTLIB_DEVICE
- if (cryptDeviceOpen(&cryptlib_device, CRYPT_UNUSED, CRYPT_DEVICE_HARDWARE, NULL) != CRYPT_OK)
- lose(CKR_GENERAL_ERROR);
-#endif
-
#if USE_POSIX
initialized_pid = getpid();
#endif
@@ -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:
-
- /*
- * Congregation will now please turn to RFC 2313 8.1 as we
- * construct a PKCS #1.5 type 01 encryption block.
- */
+ 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;
- 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 (