/*
* pkcs11.c
* --------
*
* This is a partial implementation of PKCS #11 on top of Cryptlib on
* top of a HAL connecting to the Cryptech FPGA cores.
*
* This is still at a very early stage and should not (yet?) be used
* for any serious purpose. Among other things, it's not yet entirely
* clear whether this approach really is workable.
*
* Author: Rob Austein
* Copyright (c) 2015, SUNET
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <sqlite3.h>
#include "cryptlib.h"
/*
* Magic PKCS #11 macros that must be defined before including
* pkcs11.h. For now these are only the Unix versions, add others
* later (which may require minor refactoring).
*/
#define CK_PTR *
#define CK_DEFINE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType (* name)
#define CK_CALLBACK_FUNCTION(returnType, name) returnType (* name)
#ifndef NULL_PTR
#define NULL_PTR NULL
#endif
#include "pkcs11.h"
#include "attributes.h"
/*
* This PKCS #11 implementation is hardwired with one slot, the token
* for which is always present (so we return the same answer
* regardless of the value of tokenPresent).
*/
#define P11_ONE_AND_ONLY_SLOT 0
/*
* Placeholders for PIN length limits. Figure out real values later.
*/
#warning Figure out PIN length limits
#define P11_MIN_PIN_LENGTH 16
#define P11_MAX_PIN_LENGTH 4096
/*
* Version numbers. Placeholders for now. Cryptlib has a version
* number, but from PKCS #11's point of view, Cryptlib is part of the
* "hardware", and we're probably going to need something other than
* Cryptlib's version number for the hardware, because we have to
* represent the version number of the attached Cryptech FPGA cores.
*
* Software version number is just the version of this PKCS #11
* implementation. Probably.
*/
#warning Figure out hardware and software version numbers
#define P11_VERSION_SW_MAJOR 0
#define P11_VERSION_SW_MINOR 0
#define P11_VERSION_HW_MAJOR 0
#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.
*/
#ifndef DEBUG_SQL
#define DEBUG_SQL 1
#endif
/*
* Default filename for SQL database lives. Can be overriden at
* runtime by setting PKCS11_DATABASE environment variable.
*/
#ifndef SQL_DATABASE
#define SQL_DATABASE ".cryptech-pkcs11.db"
#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
/*
* PKCS #11 session.
*/
/*
* 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.
*
* 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.
*
* 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.
*/
#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 */
CK_STATE state; /* State (CKS_*) of this session */
CK_NOTIFY notify; /* Notification callback */
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
} p11_session_t;
/*
* PKCS #11 handle management. PKCS #11 has two kinds of handles:
* session handles and object handles. We subdivide object handles
* into token object handles (handles for objects that live on the
* token) and session object handles (handles for objects that live
* only as long as the session does), and we steal a bit of the object
* handle as a flag to distinguish between our two kinds of object
* handles, considerably simplifing the objected-related SQL code.
*/
typedef enum {
handle_flavor_session,
handle_flavor_token_object,
handle_flavor_session_object
} handle_flavor_t;
#define FLAG_HANDLE_TOKEN 0x80000000
#define is_token_handle(_handle_) (((_handle_) & FLAG_HANDLE_TOKEN) != 0)
/*
* Current logged-in user.
*/
static enum {
not_logged_in,
logged_in_as_user,
logged_in_as_so
} logged_in_as = not_logged_in;
/*
* PKCS #11 sessions for this application.
*/
static p11_session_t *p11_sessions;
/*
* SQL database.
*/
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
* on SQL probes to avoid handle conflicts.
*/
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;
/*
* Syntactic sugar for functions returning CK_RV complex enough to
* need cleanup actions on failure. Also does very basic logging
* for debug-by-printf().
*/
#define lose(_ck_rv_code_) \
do { \
rv = (_ck_rv_code_); \
fprintf(stderr, "%s:%u: %s\n", __FILE__, __LINE__, #_ck_rv_code_); \
goto fail; \
} while (0)
/*
* Error checking for SQLite calls.
*/
#if DEBUG_SQL
#define sql_whine(_expr_) \
(fprintf(stderr, "%s:%u: %s returned %s\n", \
__FILE__, __LINE__, #_expr_, sqlite3_errmsg(sqldb)), \
sql_breakpoint())
#else
#define sql_whine(_expr_) \
((void) 0)
#endif
#define sql_check(_good_, _expr_) \
((_expr_) == (_good_) ? 1 : (sql_whine(_expr_), 0))
#define sql_check_ok(_expr_) sql_check(SQLITE_OK, _expr_)
#define sql_check_row(_expr_) sql_check(SQLITE_ROW, _expr_)
#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.
*/
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);
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);
return *fn;
}
/*
* Closures over cf_generate() for particular filenames.
*/
static char *cf_sql_database(void)
{
return cf_generate(&database_filename, "PKCS11_DATABASE", SQL_DATABASE);
}
static char *cf_pkcs15_keyring(void)
{
return cf_generate(&keyring_filename, "PKCS11_KEYRING", PKCS15_KEYRING);
}
/*
* 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.
*/
/*
* Hook on which to hang a debugger breakpoint on SQL errors.
*/
#if DEBUG_SQL
static void sql_breakpoint(void)
{
fprintf(stderr, "[sql_breakpoint]\n");
}
#endif
/*
* Execute SQL code that doesn't require a prepared query.
*/
static int sql_exec(const char *cmd)
{
char *msg = NULL;
if (sql_check_ok(sqlite3_exec(sqldb, cmd, NULL, NULL, &msg)))
return 1;
#if DEBUG_SQL
if (msg != NULL)
fprintf(stderr, "[%s]\n", msg);
#endif
return 0;
}
/*
* Initialize SQL. This includes loading our schema, portions of
* which live in the temp (memory) database thus always need to be
* created on startup.
*/
static int sql_init(void)
{
static const char schema[] =
#include "schema.h"
;
assert(sqldb == NULL);
return sql_check_ok(sqlite3_open(cf_sql_database(), &sqldb)) && sql_exec(schema);
}
/*
* Shut down SQL.
*
* Yes, this can return failure, although it's not clear what we're
* meant to do about that if the application is going to shut down
* regardless of what we do. I guess we could loop retrying a few
* times for errors like SQLITE_BUSY, but that's about it.
*/
static int sql_fini(void)
{
if (!sql_check_ok(sqlite3_close(sqldb)))
return 0;
sqldb = NULL;
return 1;
}
/*
* GCC attribute declaration to help catch format string errors,
* ignored by other compilers.
*/
#ifdef __GNUC__
static int sql_prepare(sqlite3_stmt **q,
const char *format, ...)
__attribute__ ((format (printf, 2, 3)));
#endif
/*
* Prepare an SQLite3 query, using vsnprintf() to format the query.
*
* WARNING WARNING WARNING WARNING
*
* Do not use this formatting mechanism for anything involving
* user-supplied data. It's only intended to handle things like
* selecting between two parallel table structures or queries using
* manifest constants that are only available in C header files.
*/
static int sql_prepare(sqlite3_stmt **q, const char *format, ...)
{
char buffer[2048];
va_list ap;
size_t n;
va_start(ap, format);
n = vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
if (n >= sizeof(buffer))
return SQLITE_TOOBIG;
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.
*/
#define ASN1_UNIVERSAL 0x00
#define ASN1_APPLICATION 0x40
#define ASN1_CONTEXT_SPECIFIC 0x80
#define ASN1_PRIVATE 0xC0
#define ASN1_PRIMITIVE 0x00
#define ASN1_CONSTRUCTED 0x20
#define ASN1_TAG_MASK 0x1F
#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)
#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().
*
* Check ASN.1 tag and various errors, decode length field.
* Outputs are length of header (tag + length) and value.
*/
static int asn1_prep(const unsigned char tag,
const unsigned char * const der,
const size_t len,
size_t *phlen,
size_t *pvlen)
{
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;
for (i = 2; i < hlen; i++)
vlen = (vlen << 8) + der[i];
}
if (hlen + vlen > len)
return 0;
*phlen = hlen;
*pvlen = vlen;
return 1;
}
/*
* 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--;
}
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 */
}
/*
* Find an unused handle.
*
* Note that zero is an excluded value (CK_INVALID_HANDLE), hence the
* slightly odd arithmetic.
*
* For object handles, we steal the high-order bit to flag whether the
* handle represents a session object or token object.
*/
static CK_ULONG p11_allocate_unused_handle(const handle_flavor_t flavor)
{
static const char select_format[] =
" SELECT %s_id FROM %s WHERE %s_handle = ?";
const char *table = flavor == handle_flavor_session ? "session" : "object";
sqlite3_stmt *q = NULL;
CK_ULONG handle;
int ret;
if (!sql_check_ok(sql_prepare(&q, select_format, table, table, table)))
goto fail;
for (;;) {
handle = ++next_handle;
next_handle %= 0xFFFFFFFF;
switch (flavor) {
case handle_flavor_session:
break;
case handle_flavor_token_object:
handle |= FLAG_HANDLE_TOKEN;
break;
case handle_flavor_session_object:
handle &= ~FLAG_HANDLE_TOKEN;
break;
}
assert(handle != CK_INVALID_HANDLE);
if (!sql_check_ok(sqlite3_reset(q)) ||
!sql_check_ok(sqlite3_bind_int64(q, 1, handle)))
goto fail;
if ((ret = sqlite3_step(q)) == SQLITE_ROW)
continue;
if (ret == SQLITE_DONE)
break;
sql_whine_step();
goto fail;
}
sqlite3_finalize(q);
return handle;
fail:
sqlite3_finalize(q);
return CK_INVALID_HANDLE;
}
/*
* Translate CKA_TOKEN value to handle flavor.
*/
static handle_flavor_t p11_handle_flavor_from_cka_token(const CK_BBOOL *bbool)
{
assert(bbool != NULL);
return *bbool ? handle_flavor_token_object : handle_flavor_session_object;
}
/*
* Attribute methods.
*/
/*
* Set an attribute for a given object.
*
* It would be trivial to generalize this to take a CK_ATTRIBUTE_PTR
* template instead of a single attribute, at the cost of losing the
* const specifiers (CK_ATTRIBUTE_PTR has an internal non-const void*).
*/
static int p11_attribute_set(const CK_OBJECT_HANDLE object_handle,
const CK_ATTRIBUTE_TYPE type,
const void * const value,
const CK_ULONG length)
{
static const char insert_format[] =
" INSERT OR REPLACE INTO %s_attribute (%s_object_id, type, value)"
" VALUES ((SELECT %s_object_id FROM object WHERE object_handle = ?1), ?2, ?3)";
const char *flavor = is_token_handle(object_handle) ? "token" : "session";
sqlite3_stmt *q = NULL;
int ok = 0;
if (!sql_check_ok(sql_prepare(&q, insert_format, flavor, flavor, flavor)) ||
!sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) ||
!sql_check_ok(sqlite3_bind_int64(q, 2, type)) ||
!sql_check_ok(sqlite3_bind_blob( q, 3, value, length, NULL)) ||
!sql_check_done(sqlite3_step(q)))
goto fail;
ok = 1;
fail:
sqlite3_finalize(q);
return ok;
}
/*
* Get a single attribute from a given object.
*
* This could easily be generalized to take a CK_ATTRIBUTE_PTR, at the
* cost of more complicated error semantics.
*/
static int p11_attribute_get(const CK_OBJECT_HANDLE object_handle,
const CK_ATTRIBUTE_TYPE type,
void *value,
CK_ULONG *length,
const CK_ULONG maxlength)
{
static const char select_format[] =
" SELECT value FROM %s_attribute NATURAL JOIN object"
" WHERE object_handle = ?1 AND type = ?2";
const char *flavor = is_token_handle(object_handle) ? "token" : "session";
sqlite3_stmt *q = NULL;
int ret, ok = 0;
CK_ULONG len;
if (!sql_check_ok(sql_prepare(&q, select_format, flavor)) ||
!sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) ||
!sql_check_ok(sqlite3_bind_int64(q, 2, type)))
goto fail;
ret = sqlite3_step(q);
if (ret == SQLITE_DONE)
goto fail;
if (ret != SQLITE_ROW) {
sql_whine_step();
goto fail;
}
len = sqlite3_column_bytes(q, 0);
if (length != NULL)
*length = len;
if (value != NULL && maxlength < len)
goto fail;
if (value != NULL)
memcpy(value, sqlite3_column_blob(q, 0), len);
ok = 1;
fail:
sqlite3_finalize(q);
return ok;
}
/*
* Wrappers to set and get CK_BBOOL and CK_ULONG values.
*/
static int p11_attribute_set_bbool(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, const CK_BBOOL value)
{
return p11_attribute_set(object_handle, type, &value, sizeof(value));
}
static int p11_attribute_set_ulong(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, const CK_ULONG value)
{
return p11_attribute_set(object_handle, type, &value, sizeof(value));
}
static int p11_attribute_get_bbool(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, CK_BBOOL *value)
{
CK_ULONG length;
return p11_attribute_get(object_handle, type, value, &length, sizeof(*value)) && length == sizeof(*value);
}
static int p11_attribute_get_ulong(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, CK_ULONG *value)
{
CK_ULONG length;
return p11_attribute_get(object_handle, type, value, &length, sizeof(*value)) && length == sizeof(*value);
}
/*
* Find an attribute in a CK_ATTRIBUTE_PTR template. Returns index
* into template, or -1 if not found.
*/
static int p11_attribute_find_in_template(const CK_ATTRIBUTE_TYPE type,
const CK_ATTRIBUTE_PTR template,
const CK_ULONG length)
{
int i;
if (template != NULL)
for (i = 0; i < length; i++)
if (template[i].type == type)
return i;
return -1;
}
/*
* Map a keyusage-related attribute to a keyusage bit flag.
*
* Assumes that calling code has already checked whether this
* attribute is legal for this object class, that attribute which
* should be CK_BBOOLs are of the correct length, etcetera.
*
* To handle all the possible permutations of specified and default
* 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.
*/
static void p11_attribute_apply_keyusage(unsigned *keyusage, const CK_ATTRIBUTE_TYPE type, const CK_BBOOL *value)
{
unsigned flag;
assert(keyusage != NULL && value != NULL);
switch (type) {
case CKA_SIGN: /* Generate signature */
case CKA_VERIFY: /* Verify signature */
flag = CRYPT_KEYUSAGE_DIGITALSIGNATURE;
break;
case CKA_ENCRYPT: /* Encrypt bulk data (seldom used) */
case CKA_DECRYPT: /* Bulk decryption (seldom used) */
flag = CRYPT_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;
break;
default:
return; /* Attribute not related to key usage */
}
if (*value)
*keyusage |= flag;
else
*keyusage &= ~flag;
}
/*
* Descriptor methods. Descriptors are generated at compile time by
* an auxiliary Python script, see attributes.* for details.
*/
/*
* Return the descriptor associated with a particular object class and
* key type.
*/
static const p11_descriptor_t *p11_descriptor_from_key_type(const CK_OBJECT_CLASS object_class,
const CK_KEY_TYPE key_type)
{
int i;
for (i = 0; i < sizeof(p11_descriptor_keyclass_map)/sizeof(*p11_descriptor_keyclass_map); i++) {
const p11_descriptor_keyclass_map_t * const m = &p11_descriptor_keyclass_map[i];
if (m->object_class == object_class && m->key_type == key_type)
return m->descriptor;
}
return NULL;
}
/*
* Find the entry for a particular attribute in a descriptor.
*/
static const p11_attribute_descriptor_t *p11_find_attribute_in_descriptor(const p11_descriptor_t *descriptor,
const CK_ATTRIBUTE_TYPE type)
{
int i;
if (descriptor != NULL && descriptor->attributes != NULL)
for (i = 0; i < descriptor->n_attributes; i++)
if (descriptor->attributes[i].type == type)
return &descriptor->attributes[i];
return NULL;
}
/*
* Check whether an attribute is marked as sensitive. If we don't
* recognize the attribute, report it as sensitive (safer than the
* alternative).
*/
static int p11_attribute_is_sensitive(const p11_descriptor_t *descriptor,
const CK_ATTRIBUTE_TYPE type)
{
const p11_attribute_descriptor_t *a = p11_find_attribute_in_descriptor(descriptor, type);
return a == NULL || (a->flags & P11_DESCRIPTOR_SENSITIVE) != 0;
}
/*
* Object methods.
*/
/*
* Check access rights for an object.
*/
typedef enum { p11_object_access_read, p11_object_access_write } p11_object_access_t;
static CK_RV p11_object_check_rights(const p11_session_t *session,
const CK_OBJECT_HANDLE object_handle,
const p11_object_access_t rights)
{
static const char session_handle_query[] =
" SELECT session_handle FROM session NATURAL JOIN object WHERE object_handle = ?1";
CK_BBOOL object_is_private;
sqlite3_stmt *q = NULL;
CK_RV rv;
if (session == NULL)
lose(CKR_SESSION_HANDLE_INVALID);
/*
* Read-only sessions are, um, read-only.
*/
switch (session->state) {
case CKS_RO_PUBLIC_SESSION:
case CKS_RO_USER_FUNCTIONS:
if (rights == p11_object_access_write)
lose(CKR_SESSION_READ_ONLY);
}
/*
* Private objects don't for sessions in the wrong state.
*/
switch (session->state) {
case CKS_RO_PUBLIC_SESSION:
case CKS_RW_PUBLIC_SESSION:
case CKS_RW_SO_FUNCTIONS:
if (!p11_attribute_get_bbool(object_handle, CKA_PRIVATE, &object_is_private) || object_is_private)
lose(CKR_OBJECT_HANDLE_INVALID);
}
/*
* Session objects are only visible to the session which created them.
*/
if (!is_token_handle(object_handle) &&
(!sql_check_ok(sql_prepare(&q, session_handle_query)) ||
!sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) ||
!sql_check_row(sqlite3_step(q)) ||
sqlite3_column_int64(q, 0) != session->handle))
lose(CKR_OBJECT_HANDLE_INVALID);
/*
* Ran out of reasons to reject, guess we should allow it.
*/
rv = CKR_OK;
fail:
sqlite3_finalize(q);
return rv;
}
/*
* Delete all private objects, probably because user logged out.
*
* In the case of token objects, the object itself remains in the
* token, we're just deleting our handle for the object.
*
* In the case of session objects, the object itself goes away.
*/
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'),"
" t AS (SELECT token_object_id FROM token_attribute WHERE type = %u AND value <> X'00')"
" 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;
if (!sql_check_ok(sql_prepare(&q, delete_format, CKA_PRIVATE, CKA_PRIVATE)) ||
!sql_check_done(sqlite3_step(q)))
goto fail;
ok = 1;
fail:
sqlite3_finalize(q);
return ok;
}
/*
* Create a new object.
*
* This is a bit nasty due to the SQL foreign key constraints and the
* different handling required for session and token objects.
*/
static CK_OBJECT_HANDLE p11_object_create(const p11_session_t *session,
const handle_flavor_t flavor,
const CK_ATTRIBUTE_PTR template,
const CK_ULONG template_length,
const p11_descriptor_t * const descriptor,
const CK_MECHANISM_PTR mechanism)
{
static const char insert_object[] =
" INSERT INTO object (object_handle)"
" VALUES (?)";
static const char insert_token_object[] =
" INSERT INTO token_object DEFAULT VALUES";
static const char insert_session_object[] =
" INSERT INTO session_object (object_id) VALUES (?)";
static const char update_object_session_object[] =
" UPDATE object SET"
" session_id = (SELECT session_id FROM session WHERE session_handle = ?1),"
" session_object_id = ?2"
" WHERE object_id = ?3";
static const char update_object_token_object[] =
" UPDATE object SET token_object_id = ?1 WHERE object_id = ?2";
static const char insert_token_attribute[] =
" INSERT OR REPLACE INTO token_attribute (token_object_id, type, value)"
" VALUES (?1, ?2, ?3)";
static const char insert_session_attribute[] =
" INSERT OR REPLACE INTO session_attribute (session_object_id, type, value)"
" VALUES (?1, ?2, ?3)";
CK_OBJECT_HANDLE object_handle = p11_allocate_unused_handle(flavor);;
sqlite3_int64 object_id, session_object_id, token_object_id;
sqlite3_stmt *q = NULL;
int i, ok = 0;
assert(session != NULL && template != NULL && descriptor != NULL &&
(flavor == handle_flavor_token_object ||
flavor == handle_flavor_session_object));
if (!sql_check_ok(sql_prepare(&q, insert_object)) ||
!sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) ||
!sql_check_done(sqlite3_step(q)))
goto fail;
object_id = sqlite3_last_insert_rowid(sqldb);
sqlite3_finalize(q);
q = NULL;
switch (flavor) {
case handle_flavor_token_object:
if (!sql_check_ok(sql_prepare(&q, insert_token_object)) ||
!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)) ||
!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_ok(sqlite3_bind_int64(q, 1, token_object_id)))
goto fail;
break;
case handle_flavor_session_object:
if (!sql_check_ok(sql_prepare(&q, insert_session_object)) ||
!sql_check_ok(sqlite3_bind_int64(q, 1, object_id)) ||
!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)) ||
!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_ok(sqlite3_bind_int64(q, 1, session_object_id)))
goto fail;
break;
default: /* Suppress GCC warning */
goto fail;
}
/*
* Now populate attributes, starting with the application's
* template, which we assume has already been blessed by the API
* function that called this method.
*/
for (i = 0; i < template_length; i++) {
const CK_ATTRIBUTE_TYPE type = template[i].type;
const void * val = template[i].pValue;
const int len = template[i].ulValueLen;
if (!sql_check_ok(sqlite3_reset(q)) ||
!sql_check_ok(sqlite3_bind_int64(q, 2, type)) ||
!sql_check_ok(sqlite3_bind_blob( q, 3, val, len, NULL)) ||
!sql_check_done(sqlite3_step(q)))
goto fail;
}
/*
* Next, add defaults from the descriptor.
*/
for (i = 0; i < descriptor->n_attributes; i++) {
const CK_ATTRIBUTE_TYPE type = descriptor->attributes[i].type;
const void * val = descriptor->attributes[i].value;
const int len = descriptor->attributes[i].length;
const unsigned flags = descriptor->attributes[i].flags;
if (val == NULL && (flags & P11_DESCRIPTOR_DEFAULT_VALUE) != 0)
val = "";
if (val == NULL || p11_attribute_find_in_template(type, template, template_length) >= 0)
continue;
if (!sql_check_ok(sqlite3_reset(q)) ||
!sql_check_ok(sqlite3_bind_int64(q, 2, type)) ||
!sql_check_ok(sqlite3_bind_blob( q, 3, val, len, NULL)) ||
!sql_check_done(sqlite3_step(q)))
goto fail;
}
/*
* Finally, add generation mechanism attributes as needed.
*/
if (mechanism != NULL &&
(!sql_check_ok(sqlite3_reset(q)) ||
!sql_check_ok(sqlite3_bind_int64(q, 2, CKA_LOCAL)) ||
!sql_check_ok(sqlite3_bind_blob( q, 3, &const_CK_TRUE, sizeof(const_CK_TRUE), NULL)) ||
!sql_check_done(sqlite3_step(q)) ||
!sql_check_ok(sqlite3_reset(q)) ||
!sql_check_ok(sqlite3_bind_int64(q, 2, CKA_KEY_GEN_MECHANISM)) ||
!sql_check_ok(sqlite3_bind_blob( q, 3, &mechanism->mechanism, sizeof(mechanism->mechanism), NULL)) ||
!sql_check_done(sqlite3_step(q))))
goto fail;
/*
* If we made it past all that, we're happy.
*/
ok = 1;
fail:
sqlite3_finalize(q);
return ok ? object_handle : CK_INVALID_HANDLE;
}
/*
* Get the keyid for an object.
*
* This may require calculating the keyid from the CKA_ID attribute.
*/
static int p11_object_get_keyid(const CK_OBJECT_HANDLE object_handle,
char *keyid,
const size_t maxkeyid)
{
static const char select_format[] =
" SELECT keyid FROM %s_object NATURAL JOIN object WHERE object_handle = ?";
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)";
const char *flavor = is_token_handle(object_handle) ? "token" : "session";
sqlite3_stmt *q = NULL;
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)))
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:
sqlite3_finalize(q);
return ok;
}
/*
* Add attributes representing the SPKI value of a key we've
* generated.
*
* 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.
*
* 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.
*/
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 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;
}
/*
* 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.
*/
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;
/*
* Dig the relevant integers out of the ASN.1.
*/
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 (modulus_len > 0 && *modulus == 0x00)
modulus_len--, modulus++;
if (publicExponent_len > 0 && *publicExponent == 0x00)
publicExponent_len--, publicExponent++;
/*
* Insert the attributes and we're done.
*/
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));
}
/*
* Session methods.
*/
/*
* Create a new session.
*/
static p11_session_t *p11_session_new(void)
{
p11_session_t *session = malloc(sizeof(*session));
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;
}
/*
* Free a session.
*/
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
free(session);
}
/*
* Assign a handle to a session and add the session to SQL.
*/
static int p11_session_add(p11_session_t *session)
{
static const char insert_session[] =
" INSERT INTO session (session_handle) VALUES (?)";
sqlite3_stmt *q = NULL;
int ok = 0;
assert(session != NULL);
session->handle = p11_allocate_unused_handle(handle_flavor_session);
if (!sql_check_ok(sql_prepare(&q, insert_session)) ||
!sql_check_ok(sqlite3_bind_int64(q, 1, session->handle)) ||
!sql_check_done(sqlite3_step(q)))
goto fail;
session->link = p11_sessions;
p11_sessions = session;
ok = 1;
fail:
sqlite3_finalize(q);
return ok;
}
/*
* Find a session.
*
* Since we don't expect the total number of sessions to be all that
* high, we use a linked list with a move-to-the-front search. Some
* of the other session methods assume this behavior, so be careful if
* you decide to change it.
*/
static p11_session_t *p11_session_find(const CK_SESSION_HANDLE session_handle)
{
p11_session_t **link, *session;
for (link = &p11_sessions;
(session = *link) != NULL && session->handle != session_handle;
link = &session->link)
;
if (session != NULL && link != &p11_sessions) {
*link = session->link;
session->link = p11_sessions;
p11_sessions = session;
}
return session;
}
/*
* 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)) ||
!sql_check_done(sqlite3_step(q)))
lose(CKR_FUNCTION_FAILED);
/* Check that move-to-the-front behaved as expected */
assert(p11_sessions == session);
p11_sessions = session->link;
p11_session_free(session);
fail:
sqlite3_finalize(q);
return rv;
}
/*
* 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 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);
while (p11_sessions != NULL) {
session = p11_sessions;
p11_sessions = session->link;
p11_session_free(session);
}
fail:
sqlite3_finalize(q);
return rv;
}
/*
* Check session database against login state for consistency.
*
* This is mostly useful in assertions.
*/
static int p11_session_consistent_login(void)
{
p11_session_t *session;
switch (logged_in_as) {
case not_logged_in:
for (session = p11_sessions; session != NULL; session = session->link)
if (session->state != CKS_RO_PUBLIC_SESSION && session->state != CKS_RW_PUBLIC_SESSION)
return 0;
return 1;
case logged_in_as_user:
for (session = p11_sessions; session != NULL; session = session->link)
if (session->state != CKS_RO_USER_FUNCTIONS && session->state != CKS_RW_USER_FUNCTIONS)
return 0;
return 1;
case logged_in_as_so:
for (session = p11_sessions; session != NULL; session = session->link)
if (session->state != CKS_RW_SO_FUNCTIONS)
return 0;
return 1;
default:
return 0;
}
}
/*
* PKCS #11 likes space-padded rather than null-terminated strings.
*/
static int psnprintf(void *buffer_, size_t size, const char *format, ...)
{
char *buffer = buffer_;
size_t i, n;
va_list ap;
va_start(ap, format);
i = n = vsnprintf(buffer, size, format, ap);
va_end(ap);
while (i < size)
buffer[i++] = ' ';
return n;
}
/*
* Template checking and key generation.
*
* This may need refactoring at some point, eg, when we add support
* for C_CreateObject().
*/
/*
* First pass: called once per template entry during initial pass over
* template to handle generic checks that apply regardless of
* attribute type.
*/
static CK_RV p11_check_keypair_attributes_check_template_1(const CK_ATTRIBUTE_TYPE type,
const void * const val,
const size_t len,
const p11_descriptor_t * const descriptor)
{
const p11_attribute_descriptor_t * const atd = p11_find_attribute_in_descriptor(descriptor, type);
CK_RV rv;
/* Attribute not allowed or not allowed for key generation */
if (atd == NULL || (atd->flags & P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE) != 0)
lose(CKR_ATTRIBUTE_TYPE_INVALID);
/* NULL or wrong-sized attribute values */
if (val == NULL || (atd->size != 0 && len != atd->size))
lose(CKR_ATTRIBUTE_VALUE_INVALID);
/* Attributes which only the SO user is allowed to set to CK_TRUE */
if ((atd->flags & P11_DESCRIPTOR_ONLY_SO_USER_CAN_SET) != 0 && logged_in_as != logged_in_as_so && *(CK_BBOOL *) val)
lose(CKR_ATTRIBUTE_VALUE_INVALID);
/* Attributes which don't match mandatory values */
if (atd->value != NULL && (atd->flags & P11_DESCRIPTOR_DEFAULT_VALUE) == 0 && memcmp(val, atd->value, atd->length) != 0)
lose(CKR_TEMPLATE_INCONSISTENT);
rv = CKR_OK;
fail:
return rv;
}
/*
* Second pass: called once per template to check that each attribute
* required for that template has been specified exactly once.
*/
static CK_RV p11_check_keypair_attributes_check_template_2(const p11_session_t *session,
const p11_descriptor_t * const descriptor,
const CK_ATTRIBUTE_PTR template,
const CK_ULONG template_length)
{
const CK_BBOOL *object_is_private;
CK_RV rv;
int i, j;
/*
* Some session states aren't allowed to play with private objects.
*/
switch (session->state) {
case CKS_RO_PUBLIC_SESSION:
case CKS_RW_PUBLIC_SESSION:
case CKS_RW_SO_FUNCTIONS:
if ((i = p11_attribute_find_in_template(CKA_PRIVATE, template, template_length)) >= 0) {
assert(template[i].pValue != NULL);
object_is_private = template[i].pValue;
}
else {
const p11_attribute_descriptor_t * const atd = p11_find_attribute_in_descriptor(descriptor, CKA_PRIVATE);
assert(atd != NULL && atd->value != NULL);
object_is_private = atd->value;
}
if (*object_is_private)
lose(CKR_TEMPLATE_INCONSISTENT);
}
for (i = 0; i < descriptor->n_attributes; i++) {
const p11_attribute_descriptor_t * const atd = &descriptor->attributes[i];
const int required_by_api = (atd->flags & P11_DESCRIPTOR_REQUIRED_BY_GENERATE) != 0;
const int forbidden_by_api = (atd->flags & P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE) != 0;
const int in_descriptor = (atd->flags & P11_DESCRIPTOR_DEFAULT_VALUE) != 0 || atd->value != NULL;
const int pos_in_template = p11_attribute_find_in_template(atd->type, template, template_length);
/* Multiple entries for same attribute */
if (pos_in_template >= 0)
for (j = pos_in_template + 1; j < template_length; j++)
if (template[j].type == atd->type)
lose(CKR_TEMPLATE_INCONSISTENT);
/* Required attribute missing from template */
if (!forbidden_by_api && (required_by_api || !in_descriptor) && pos_in_template < 0) {
fprintf(stderr, "[Missing attribute 0x%lx]\n", atd->type); /* XXX */
lose(CKR_TEMPLATE_INCOMPLETE);
}
}
rv = CKR_OK;
fail:
return rv;
}
/*
* Mechanism-independent checks for templates and descriptors when
* generating new keypairs.
*
* PKCS #11 gives the application far too much rope (including but not
* limited to the ability to supply completely unrelated templates for
* public and private keys in a keypair), so we need to do a fair
* 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.
*
* 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.
*/
static CK_RV p11_check_keypair_attributes(const p11_session_t *session,
const CK_ATTRIBUTE_PTR pPublicKeyTemplate,
const CK_ULONG ulPublicKeyAttributeCount,
const p11_descriptor_t * const public_descriptor,
const CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
const CK_ULONG ulPrivateKeyAttributeCount,
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;
assert(session != NULL &&
pPublicKeyTemplate != NULL && public_descriptor != NULL &&
pPrivateKeyTemplate != NULL && private_descriptor != NULL);
/*
* Read-only sessions can't create keys, doh.
*/
switch (session->state) {
case CKS_RO_PUBLIC_SESSION:
case CKS_RO_USER_FUNCTIONS:
lose(CKR_SESSION_READ_ONLY);
}
/*
* Check values provided in the public and private templates.
*/
for (i = 0; i < ulPublicKeyAttributeCount; i++) {
const CK_ATTRIBUTE_TYPE type = pPublicKeyTemplate[i].type;
const void * const val = pPublicKeyTemplate[i].pValue;
const size_t len = pPublicKeyTemplate[i].ulValueLen;
if ((rv = p11_check_keypair_attributes_check_template_1(type, val, len, public_descriptor)) != CKR_OK)
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++) {
const CK_ATTRIBUTE_TYPE type = pPrivateKeyTemplate[i].type;
const void * const val = pPrivateKeyTemplate[i].pValue;
const size_t len = pPrivateKeyTemplate[i].ulValueLen;
if ((rv = p11_check_keypair_attributes_check_template_1(type, val, len, private_descriptor)) != CKR_OK)
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);
}
/*
* We insist that keyusage be specified for both public and private
* key, and that they match. May not need to be this strict.
*/
if (public_keyusage != private_keyusage || public_keyusage == 0)
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.
*/
if ((rv = p11_check_keypair_attributes_check_template_2(session,
public_descriptor,
pPublicKeyTemplate,
ulPublicKeyAttributeCount)) != CKR_OK ||
(rv = p11_check_keypair_attributes_check_template_2(session,
private_descriptor,
pPrivateKeyTemplate,
ulPrivateKeyAttributeCount)) != CKR_OK)
goto fail;
/*
* If we get this far, we're happy. Maybe.
*/
rv = CKR_OK;
fail:
return rv;
}
/*
* CKM_RSA_PKCS_KEY_PAIR_GEN key pair generation implemetation.
*
* Much mechanism-independent code has already been factored out of
* this function, no doubt much remains that will require further
* refactoring once we implement other mechanisms.
*/
static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session,
const CK_MECHANISM_PTR pMechanism,
const CK_ATTRIBUTE_PTR pPublicKeyTemplate,
const CK_ULONG ulPublicKeyAttributeCount,
const CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
const CK_ULONG ulPrivateKeyAttributeCount,
CK_OBJECT_HANDLE_PTR phPublicKey,
CK_OBJECT_HANDLE_PTR phPrivateKey)
{
CK_OBJECT_HANDLE private_handle = CK_INVALID_HANDLE;
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;
CK_ULONG keysize = 0;
size_t id_len = 0;
CK_RV rv;
int i;
/*
* Do mechanism-independent checks before anything else.
*/
rv = p11_check_keypair_attributes(session,
pPublicKeyTemplate, ulPublicKeyAttributeCount, &p11_descriptor_rsa_public_key,
pPrivateKeyTemplate, ulPrivateKeyAttributeCount, &p11_descriptor_rsa_private_key);
if (rv != CKR_OK)
return rv;
assert(session != NULL && pMechanism != NULL &&
pPublicKeyTemplate != NULL && phPublicKey != NULL &&
pPrivateKeyTemplate != NULL && phPrivateKey != NULL);
memset(keyid, 0, sizeof(keyid));
/*
* Grab values and perform mechanism-specific checks.
*/
for (i = 0; i < ulPublicKeyAttributeCount; i++) {
const CK_ATTRIBUTE_TYPE type = pPublicKeyTemplate[i].type;
const void * const val = pPublicKeyTemplate[i].pValue;
const size_t len = pPublicKeyTemplate[i].ulValueLen;
assert(val != NULL);
switch (type) {
case CKA_TOKEN: /* Object stored on token */
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 */
keysize = *(CK_ULONG *) val;
if ((keysize & 7) != 0)
return CKR_ATTRIBUTE_VALUE_INVALID;
continue;
}
}
for (i = 0; i < ulPrivateKeyAttributeCount; i++) {
const CK_ATTRIBUTE_TYPE type = pPrivateKeyTemplate[i].type;
const void * const val = pPrivateKeyTemplate[i].pValue;
const size_t len = pPrivateKeyTemplate[i].ulValueLen;
assert (val != NULL);
switch (type) {
case CKA_TOKEN: /* Object stored on token */
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.
*/
if (id == NULL || id_len == 0 || keysize == 0 || public_handle_flavor != private_handle_flavor)
return CKR_TEMPLATE_INCOMPLETE;
/*
* If we got this far, create the PKCS #11 objects.
*/
if (!sql_exec("BEGIN"))
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);
/*
* Commit the SQL transaction.
*/
if (!sql_exec("COMMIT"))
lose(CKR_FUNCTION_FAILED);
/*
* All went well, return handles and we're done.
*/
*phPublicKey = public_handle;
*phPrivateKey = private_handle;
return CKR_OK;
fail:
if (ctx != CRYPT_HANDLE_NONE)
cryptDestroyContext(ctx);
if (ctx != CRYPT_HANDLE_NONE && keyid[0] != 0x00)
(void) cryptlib_delete_key(keyid);
if (!sql_exec("ROLLBACK"))
rv = CKR_GENERAL_ERROR;
return rv;
}
/*
* PKCS #11 API functions.
*/
CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
{
int initialized_sql = 0, initialized_cryptlib = 0;
CK_C_INITIALIZE_ARGS_PTR a = pInitArgs;
CK_RV rv;
if (a != NULL) {
int functions_provided = ((a->CreateMutex != NULL) +
(a->DestroyMutex != NULL) +
(a->LockMutex != NULL) +
(a->UnlockMutex != NULL));
/*
* Reserved is, um, reserved.
* Threading parameters must either all be present or all be absent.
*/
if (a->pReserved != NULL || (functions_provided & 3) != 0)
lose(CKR_ARGUMENTS_BAD);
/*
* At present we don't support threads or locking. This may be a
* problem for OpenDNSSEC. Need to figure out what the "obvious"
* system threading mechanism is supposed to be, or make it
* configurable, or something. For the moment, just return the
* correct error code to report that we're lame.
*/
#warning Thread support check disabled, this needs to be fixed
#if 0
if (functions_provided || (a->flags & CKF_OS_LOCKING_OK) != 0)
lose(CKR_CANT_LOCK);
#endif
}
/*
* Initialize SQLite3, opening the database(s) and loading the
* schema and views.
*/
if (!sql_init())
lose(CKR_GENERAL_ERROR);
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)
lose(CKR_GENERAL_ERROR);
#endif
return CKR_OK;
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();
return rv;
}
CK_RV C_Finalize(CK_VOID_PTR pReserved)
{
if (pReserved != NULL)
return CKR_ARGUMENTS_BAD;
/*
* Destroy all current sessions.
*/
p11_session_delete_all();
/*
* Shut down SQLite3.
*/
if (!sql_fini())
return 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();
return CKR_OK;
}
CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
{
/*
* Use pkcs11f.h to build dispatch vector for C_GetFunctionList().
* This should be const, but that's not what PKCS #11 says, oh well.
*/
static CK_FUNCTION_LIST ck_function_list = {
{ CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },
#define CK_PKCS11_FUNCTION_INFO(name) name,
#include "pkcs11f.h"
#undef CK_PKCS11_FUNCTION_INFO
};
if (ppFunctionList == NULL)
return CKR_ARGUMENTS_BAD;
*ppFunctionList = &ck_function_list;
return CKR_OK;
}
CK_RV C_GetSlotList(CK_BBOOL tokenPresent,
CK_SLOT_ID_PTR pSlotList,
CK_ULONG_PTR pulCount)
{
/*
* We only have one slot, and it's hardwired.
*/
if (pulCount == NULL)
return CKR_ARGUMENTS_BAD;
if (pSlotList != NULL && *pulCount < 1)
return CKR_BUFFER_TOO_SMALL;
*pulCount = 1;
if (pSlotList != NULL)
pSlotList[0] = P11_ONE_AND_ONLY_SLOT;
return CKR_OK;
}
CK_RV C_GetTokenInfo(CK_SLOT_ID slotID,
CK_TOKEN_INFO_PTR pInfo)
{
if (pInfo == NULL)
return CKR_ARGUMENTS_BAD;
if (slotID != P11_ONE_AND_ONLY_SLOT)
return CKR_SLOT_ID_INVALID;
memset(pInfo, 0, sizeof(*pInfo));
/*
* No real idea (yet) how we get many of the following parameters.
* See cryptlib's CRYPT_DEVINFO_* attributes for some hints.
*
* pInfo->label is supposed to be set when the token is initialized.
* Not yet sure what that means in our context, but need something
* here or the libhsm test programs will bomb trying to find the
* right token, so hard-wire something for now.
*/
psnprintf(pInfo->label, sizeof(pInfo->label),
"Cryptech Token");
psnprintf(pInfo->manufacturerID, sizeof(pInfo->manufacturerID),
"Cryptech Project");
psnprintf(pInfo->model, sizeof(pInfo->model),
"%04x%04x%04x%04x",
P11_VERSION_HW_MAJOR, P11_VERSION_HW_MINOR,
P11_VERSION_SW_MAJOR, P11_VERSION_SW_MINOR);
psnprintf(pInfo->serialNumber, sizeof(pInfo->serialNumber),
"007");
pInfo->flags = CKF_RNG | CKF_LOGIN_REQUIRED;
#warning Have not yet sorted out token flags
#if 0
CKF_RNG
CKF_WRITE_PROTECTED
CKF_LOGIN_REQUIRED
CKF_USER_PIN_INITIALIZED
CKF_RESTORE_KEY_NOT_NEEDED
CKF_CLOCK_ON_TOKEN
CKF_PROTECTED_AUTHENTICATION_PATH
CKF_DUAL_CRYPTO_OPERATIONS
CKF_TOKEN_INITIALIZED
CKF_SECONDARY_AUTHENTICATION
CKF_USER_PIN_COUNT_LOW
CKF_USER_PIN_FINAL_TRY
CKF_USER_PIN_LOCKED
CKF_USER_PIN_TO_BE_CHANGED
CKF_SO_PIN_COUNT_LOW
CKF_SO_PIN_FINAL_TRY
CKF_SO_PIN_LOCKED
CKF_SO_PIN_TO_BE_CHANGED
CKF_ERROR_STATE
#endif
#warning Much of the TOKEN_INFO we return is nonsense
pInfo->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
pInfo->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
pInfo->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
pInfo->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION;
pInfo->ulMaxPinLen = P11_MAX_PIN_LENGTH;
pInfo->ulMinPinLen = P11_MIN_PIN_LENGTH;
pInfo->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
pInfo->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
pInfo->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
pInfo->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
pInfo->hardwareVersion.major = P11_VERSION_HW_MAJOR;
pInfo->hardwareVersion.minor = P11_VERSION_HW_MINOR;
pInfo->firmwareVersion.major = P11_VERSION_SW_MAJOR;
pInfo->firmwareVersion.minor = P11_VERSION_SW_MINOR;
#warning Need to sort out hardware clock
#if 0
/*
* Eventually we expect cryptech devices to have their own hardware
* clocks. Not implemented yet.
*/
pInfo->utcTime;
#endif
return CKR_OK;
}
CK_RV C_OpenSession(CK_SLOT_ID slotID,
CK_FLAGS flags,
CK_VOID_PTR pApplication,
CK_NOTIFY Notify,
CK_SESSION_HANDLE_PTR phSession)
{
const int parallel_session = (flags & CKF_SERIAL_SESSION) == 0;
const int read_only_session = (flags & CKF_RW_SESSION) == 0;
p11_session_t *session = NULL;
CK_RV rv;
if (slotID != P11_ONE_AND_ONLY_SLOT)
lose(CKR_SLOT_ID_INVALID);
if (phSession == NULL)
lose(CKR_ARGUMENTS_BAD);
if (parallel_session)
lose(CKR_SESSION_PARALLEL_NOT_SUPPORTED);
if ((session = p11_session_new()) == NULL)
lose(CKR_HOST_MEMORY);
switch (logged_in_as) {
case not_logged_in:
session->state = read_only_session ? CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION;
break;
case logged_in_as_user:
session->state = read_only_session ? CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS;
break;
case logged_in_as_so:
if (read_only_session)
lose(CKR_SESSION_READ_WRITE_SO_EXISTS);
session->state = CKS_RW_SO_FUNCTIONS;
break;
}
session->notify = Notify;
session->application = pApplication;
if (!p11_session_add(session))
lose(CKR_FUNCTION_FAILED);
assert(p11_session_consistent_login());
*phSession = session->handle;
return CKR_OK;
fail:
p11_session_free(session);
return rv;
}
CK_RV C_CloseSession(CK_SESSION_HANDLE hSession)
{
return p11_session_delete(hSession);
}
CK_RV C_CloseAllSessions(CK_SLOT_ID slotID)
{
if (slotID != P11_ONE_AND_ONLY_SLOT)
return CKR_SLOT_ID_INVALID;
p11_session_delete_all();
return CKR_OK;
}
CK_RV C_Login(CK_SESSION_HANDLE hSession,
CK_USER_TYPE userType,
CK_UTF8CHAR_PTR pPin,
CK_ULONG ulPinLen)
{
p11_session_t *session;
int crypt_cmd;
if (pPin == NULL)
return CKR_ARGUMENTS_BAD;
/*
* Mind, I don't really know why this function takes a session
* handle, given that the semantics don't seem to call upon us to do
* anything special for "this" session.
*/
if (p11_session_find(hSession) == NULL)
return 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.
*/
if (logged_in_as != not_logged_in)
return CKR_USER_ALREADY_LOGGED_IN;
/*
* 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: return CKR_OPERATION_NOT_INITIALIZED;
default: return 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)
for (session = p11_sessions; session != NULL; session = session->link)
if (session->state == CKS_RO_PUBLIC_SESSION)
return CKR_SESSION_READ_ONLY_EXISTS;
/*
* Ask Cryptlib to log us in. We may need to examine cryptlib error
* return more closely than this.
*/
#if ENABLE_CRYPTLIB_DEVICE
if (cryptSetAttributeString(cryptlib_device, crypt_cmd, pPin, ulPinLen) != CRYPT_OK)
return CKR_PIN_INCORRECT;
#endif
#if ENABLE_CRYPTLIB_SOFTWARE
{
char *newpin;
if (memchr(pPin, '\0', ulPinLen) != NULL)
return CKR_PIN_INCORRECT;
if ((newpin = malloc(ulPinLen + 1)) == NULL)
return 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.
*/
assert(p11_session_consistent_login());
logged_in_as = userType == CKU_SO ? logged_in_as_so : logged_in_as_user;
for (session = p11_sessions; session != NULL; session = session->link) {
switch (session->state) {
case CKS_RO_PUBLIC_SESSION:
assert(userType == CKU_USER);
session->state = CKS_RO_USER_FUNCTIONS;
continue;
case CKS_RW_PUBLIC_SESSION:
session->state = userType == CKU_SO ? CKS_RW_SO_FUNCTIONS : CKS_RW_USER_FUNCTIONS;
continue;
}
}
assert(p11_session_consistent_login());
return CKR_OK;
}
CK_RV C_Logout(CK_SESSION_HANDLE hSession)
{
p11_session_t *session;
int crypt_cmd;
/*
* Mind, I don't really know why this function takes a session
* handle, given that the semantics don't seem to call upon us to do
* anything special for "this" session.
*/
if (p11_session_find(hSession) == NULL)
return 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: return 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)
return CKR_FUNCTION_FAILED;
#endif
#if ENABLE_CRYPTLIB_SOFTWARE
if (pin != NULL)
free(pin);
pin = NULL;
#endif
/*
* Update global login state, then delete any private objects and
* whack every existing session into the right state.
*/
assert(p11_session_consistent_login());
logged_in_as = not_logged_in;
p11_object_delete_all_private();
for (session = p11_sessions; session != NULL; session = session->link) {
switch (session->state) {
case CKS_RO_USER_FUNCTIONS:
session->state = CKS_RO_PUBLIC_SESSION;
continue;
case CKS_RW_USER_FUNCTIONS:
case CKS_RW_SO_FUNCTIONS:
session->state = CKS_RW_PUBLIC_SESSION;
continue;
}
}
assert(p11_session_consistent_login());
return CKR_OK;
}
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";
p11_session_t *session = p11_session_find(hSession);
sqlite3_stmt *q = NULL;
CK_RV rv = CKR_OK;
sqlite3_int64 id;
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))))
lose(CKR_FUNCTION_FAILED);
sqlite3_finalize(q);
q = NULL;
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);
fail:
sqlite3_finalize(q);
return rv;
}
CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession,
CK_OBJECT_HANDLE hObject,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount)
{
static const char select_format[] =
" SELECT value FROM %s_attribute NATURAL JOIN object"
" WHERE object_handle = ?1 AND type = ?2";
const char *flavor = is_token_handle(hObject) ? "token" : "session";
p11_session_t *session = p11_session_find(hSession);
const p11_descriptor_t *descriptor = NULL;
CK_BBOOL cka_sensitive, cka_extractable;
CK_OBJECT_CLASS cka_class;
CK_KEY_TYPE cka_key_type;
int sensitive_object = 0;
sqlite3_stmt *q = NULL;
CK_RV rv = CKR_OK;
int ret, i;
if (pTemplate == NULL)
lose(CKR_ARGUMENTS_BAD);
if ((rv = p11_object_check_rights(session, hObject, p11_object_access_read)) != CKR_OK)
goto fail;
if (!p11_attribute_get_ulong(hObject, CKA_CLASS, &cka_class))
lose(CKR_OBJECT_HANDLE_INVALID);
switch (cka_class) {
case CKO_PRIVATE_KEY:
case CKO_SECRET_KEY:
if (!p11_attribute_get_bbool(hObject, CKA_EXTRACTABLE, &cka_extractable) ||
!p11_attribute_get_bbool(hObject, CKA_SENSITIVE, &cka_sensitive))
lose(CKR_OBJECT_HANDLE_INVALID);
sensitive_object = cka_sensitive || !cka_extractable;
/* Fall through */
case CKO_PUBLIC_KEY:
if (!p11_attribute_get_ulong(hObject, CKA_KEY_TYPE, &cka_key_type))
lose(CKR_OBJECT_HANDLE_INVALID);
descriptor = p11_descriptor_from_key_type(cka_class, cka_key_type);
}
if (!sql_check_ok(sql_prepare(&q, select_format, flavor)) ||
!sql_check_ok(sqlite3_bind_int64(q, 1, hObject)))
lose(CKR_FUNCTION_FAILED);
for (i = 0; i < ulCount; i++) {
if (sensitive_object && p11_attribute_is_sensitive(descriptor, pTemplate[i].type)) {
pTemplate[i].ulValueLen = -1;
rv = CKR_ATTRIBUTE_SENSITIVE;
}
else if (!sql_check_ok(sqlite3_reset(q)) ||
!sql_check_ok(sqlite3_bind_int64(q, 2, pTemplate[i].type)) ||
(ret = sqlite3_step(q)) != SQLITE_ROW) {
if (ret != SQLITE_DONE)
sql_whine_step();
pTemplate[i].ulValueLen = -1;
rv = CKR_ATTRIBUTE_TYPE_INVALID;
}
else if (pTemplate[i].pValue == NULL) {
pTemplate[i].ulValueLen = sqlite3_column_bytes(q, 0);
}
else if (pTemplate[i].ulValueLen >= sqlite3_column_bytes(q, 0)) {
pTemplate[i].ulValueLen = sqlite3_column_bytes(q, 0);
memcpy(pTemplate[i].pValue, sqlite3_column_blob(q, 0), pTemplate[i].ulValueLen);
}
else {
pTemplate[i].ulValueLen = -1;
rv = CKR_BUFFER_TOO_SMALL;
}
}
fail:
sqlite3_finalize(q);
return rv;
}
CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount)
{
static const char select_missing[] =
" WITH"
" known AS (SELECT token_object_id FROM object WHERE token_object_id IS NOT NULL)"
" SELECT token_object_id FROM token_object WHERE token_object_id NOT IN known";
static const char insert_missing[] =
" INSERT INTO object (object_handle, token_object_id) VALUES (?1, ?2)";
static const char create_format[] =
" CREATE TEMPORARY TABLE findobjects_%lu AS"
" SELECT object_id FROM object NATURAL LEFT JOIN session"
" WHERE session_handle IS NULL OR session_handle = ?1";
static const char drop_format[] =
" DROP TABLE IF EXISTS findobjects_%lu";
static const char delete_format[] =
" WITH"
" matches AS (SELECT object_id"
" FROM object NATURAL JOIN session_attribute"
" WHERE type = ?1 AND value = ?2"
" UNION"
" SELECT object_id"
" FROM object NATURAL JOIN token_attribute"
" WHERE type = ?1 AND value = ?2)"
" DELETE FROM findobjects_%lu WHERE object_id NOT IN matches";
static const char select_format[] =
" SELECT object_handle FROM findobjects_%lu NATURAL JOIN object ORDER BY object_id";
p11_session_t *session = p11_session_find(hSession);
sqlite3_stmt *q1 = NULL, *q2 = NULL;
CK_RV rv = CKR_OK;
int i, ret;
if (session == NULL)
lose(CKR_SESSION_HANDLE_INVALID);
if (ulCount > 0 && pTemplate == NULL)
lose(CKR_ARGUMENTS_BAD);
if (session->find_query != NULL)
lose(CKR_OPERATION_ACTIVE);
/*
* Assign handles to any token objects that don't have them yet.
*/
if (!sql_check_ok(sql_prepare(&q1, select_missing)) ||
!sql_check_ok(sql_prepare(&q2, insert_missing)))
lose(CKR_FUNCTION_FAILED);
while ((ret = sqlite3_step(q1)) == SQLITE_ROW) {
sqlite3_int64 token_object_id = sqlite3_column_int64(q1, 0);
CK_OBJECT_HANDLE object_handle = p11_allocate_unused_handle(handle_flavor_token_object);
if (!sql_check_ok(sqlite3_reset(q2)) ||
!sql_check_ok(sqlite3_bind_int64(q2, 1, object_handle)) ||
!sql_check_ok(sqlite3_bind_int64(q2, 2, token_object_id)) ||
!sql_check_done(sqlite3_step(q2)))
lose(CKR_FUNCTION_FAILED);
}
if (ret != SQLITE_DONE) {
sql_whine_step();
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,
* then prune based on login status and whatever filter attributes
* the caller supplied.
*/
if (!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)))
lose(CKR_FUNCTION_FAILED);
/*
* We only see private objects when logged in as the regular user.
*/
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)) ||
!sql_check_done(sqlite3_step(q1)))
lose(CKR_FUNCTION_FAILED);
}
/*
* Filter through the caller-supplied template.
*
* NB: This doesn't support some of the more obscure searches, such
* as searches for sessions or hardware features. Too much rope
* already, worry about those if we ever really need them.
*/
for (i = 0; i < ulCount; i++)
if (!sql_check_ok(sqlite3_reset(q1)) ||
!sql_check_ok(sqlite3_bind_int64(q1, 1, pTemplate[i].type)) ||
!sql_check_ok(sqlite3_bind_blob( q1, 2, pTemplate[i].pValue,
pTemplate[i].ulValueLen, NULL)) ||
!sql_check_done(sqlite3_step(q1)))
lose(CKR_FUNCTION_FAILED);
/*
* Stash a prepared query in the session object which will return
* whatever object handles survived all that filtering.
*/
if (!sql_check_ok(sql_prepare(&session->find_query, select_format, hSession)))
lose(CKR_FUNCTION_FAILED);
session->find_query_done = 0;
fail:
sqlite3_finalize(q1);
sqlite3_finalize(q2);
return rv;
}
CK_RV C_FindObjects(CK_SESSION_HANDLE hSession,
CK_OBJECT_HANDLE_PTR phObject,
CK_ULONG ulMaxObjectCount,
CK_ULONG_PTR pulObjectCount)
{
p11_session_t *session = p11_session_find(hSession);
int i, ret = SQLITE_OK;
CK_RV rv = CKR_OK;
if (session == NULL)
lose(CKR_SESSION_HANDLE_INVALID);
if (session->find_query == NULL)
lose(CKR_OPERATION_NOT_INITIALIZED);
if (phObject == NULL || pulObjectCount == NULL)
lose(CKR_ARGUMENTS_BAD);
/*
* C_FindObjectsInit() did all the heavy lifting, we just have to
* return the resulting handles.
*/
i = 0;
if (!session->find_query_done)
while (i < ulMaxObjectCount && (ret = sqlite3_step(session->find_query)) == SQLITE_ROW)
phObject[i++] = (CK_OBJECT_HANDLE) sqlite3_column_int64(session->find_query, 0);
switch (ret) {
case SQLITE_DONE:
session->find_query_done = 1;
break;
case SQLITE_OK:
case SQLITE_ROW:
break;
default:
sql_whine_step();
lose(CKR_FUNCTION_FAILED);
}
*pulObjectCount = i;
fail:
return rv;
}
CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
{
static const char drop_format[] =
" DROP TABLE IF EXISTS findobjects_%lu";
p11_session_t *session = p11_session_find(hSession);
sqlite3_stmt *q = NULL;
CK_RV rv = CKR_OK;
if (session == NULL)
lose(CKR_SESSION_HANDLE_INVALID);
if (session->find_query == NULL)
lose(CKR_OPERATION_NOT_INITIALIZED);
/*
* 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)) ||
!sql_check_done(sqlite3_step(q)))
lose(CKR_FUNCTION_FAILED);
fail:
sqlite3_finalize(q);
return rv;
}
CK_RV C_DigestInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism)
{
p11_session_t *session = p11_session_find(hSession);
CRYPT_ALGO_TYPE algo;
unsigned hash_len;
CK_RV rv;
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
if (pMechanism == NULL)
return CKR_ARGUMENTS_BAD;
if (session->digest_context != CRYPT_HANDLE_NONE)
return 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;
default: return 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);
return CKR_OK;
fail:
if (session->digest_context != CRYPT_HANDLE_NONE)
cryptDestroyContext(session->digest_context);
session->digest_context = CRYPT_HANDLE_NONE;
return rv;
}
CK_RV C_Digest(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pData,
CK_ULONG ulDataLen,
CK_BYTE_PTR pDigest,
CK_ULONG_PTR pulDigestLen)
{
p11_session_t *session = p11_session_find(hSession);
CK_RV rv;
int len;
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
if (pData == NULL || pulDigestLen == NULL)
return CKR_ARGUMENTS_BAD;
if (session->digest_context == CRYPT_HANDLE_NONE)
return 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 CKR_OK;
}
if (cryptEncrypt(session->digest_context, pData, ulDataLen) != CRYPT_OK)
lose(CKR_FUNCTION_FAILED);
if (ulDataLen != 0 &&
cryptEncrypt(session->digest_context, pData, 0) != CRYPT_OK)
lose(CKR_FUNCTION_FAILED);
if (cryptGetAttributeString(session->digest_context,
CRYPT_CTXINFO_HASHVALUE, NULL, &len) != CRYPT_OK)
lose(CKR_FUNCTION_FAILED);
if (len > *pulDigestLen)
lose(CKR_BUFFER_TOO_SMALL);
if (cryptGetAttributeString(session->digest_context,
CRYPT_CTXINFO_HASHVALUE, pDigest, &len) != CRYPT_OK)
lose(CKR_FUNCTION_FAILED);
*pulDigestLen = len;
rv = CKR_OK; /* Fall through */
fail:
cryptDestroyContext(session->digest_context);
session->digest_context = CRYPT_HANDLE_NONE;
return rv;
}
CK_RV C_SignInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hKey)
{
p11_session_t *session = p11_session_find(hSession);
char keyid[CRYPT_MAX_HASHSIZE * 2 + 1];
CRYPT_ALGO_TYPE sign_algo, hash_algo;
unsigned hash_size = 0;
int key_algo;
CK_RV rv;
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
if (pMechanism == NULL)
return CKR_ARGUMENTS_BAD;
if (session->sign_key_context != CRYPT_HANDLE_NONE ||
session->sign_digest_context != CRYPT_HANDLE_NONE)
return CKR_OPERATION_ACTIVE;
if ((rv = p11_object_check_rights(session, hKey, p11_object_access_read)) != CKR_OK)
goto fail;
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;
default: return CKR_MECHANISM_INVALID;
}
assert((hash_size & 7) == 0);
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);
return CKR_OK;
fail:
if (session->sign_key_context != CRYPT_HANDLE_NONE)
cryptDestroyContext(session->sign_key_context);
session->sign_key_context = CRYPT_HANDLE_NONE;
if (session->sign_digest_context != CRYPT_HANDLE_NONE)
cryptDestroyContext(session->sign_digest_context);
session->sign_digest_context = CRYPT_HANDLE_NONE;
return rv;
}
CK_RV C_Sign(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pData,
CK_ULONG ulDataLen,
CK_BYTE_PTR pSignature,
CK_ULONG_PTR pulSignatureLen)
{
p11_session_t *session = p11_session_find(hSession);
int len, algo;
CK_RV rv;
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
if (pData == NULL || pulSignatureLen == NULL)
return CKR_ARGUMENTS_BAD;
if (session->sign_key_context == CRYPT_HANDLE_NONE)
return 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;
if (session->sign_digest_context == CRYPT_HANDLE_NONE)
cryptDestroyContext(ctx);
if (len == 0)
lose(CKR_FUNCTION_FAILED);
}
else if (session->sign_digest_context != CRYPT_HANDLE_NONE) {
/*
* Caller wanted a hash-and-sign operation, so we can use cryptCreateSignature().
*/
if (cryptEncrypt(session->sign_digest_context, pData, ulDataLen) != CRYPT_OK)
lose(CKR_FUNCTION_FAILED);
if (ulDataLen != 0 &&
cryptEncrypt(session->sign_digest_context, pData, 0) != CRYPT_OK)
lose(CKR_FUNCTION_FAILED);
if (cryptCreateSignature(pSignature, *pulSignatureLen, &len,
session->sign_key_context,
session->sign_digest_context) != CRYPT_OK)
lose(CKR_FUNCTION_FAILED);
}
else {
/*
* Caller wanted a pure-signature operation, have to use
* cryptDeCrypt() [sic].
*
* 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)?
*/
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.
*/
if (len > *pulSignatureLen)
lose(CKR_BUFFER_TOO_SMALL);
if (ulDataLen > len - 11)
return CKR_DATA_LEN_RANGE;
pSignature[0] = 0x00;
pSignature[1] = 0x01;
memset(pSignature + 2, 0xFF, len - 3 - ulDataLen);
pSignature[len - ulDataLen - 1] = 0x00;
memcpy(pSignature + len - ulDataLen, pData, ulDataLen);
#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
break;
default:
lose(CKR_FUNCTION_FAILED);
}
/*
* 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.
*/
if (cryptDecrypt(session->sign_key_context, pSignature, len) != CRYPT_OK)
lose(CKR_FUNCTION_FAILED);
}
*pulSignatureLen = len;
rv = CKR_OK; /* Fall through */
fail:
if (session->sign_digest_context != CRYPT_HANDLE_NONE)
cryptDestroyContext(session->sign_digest_context);
session->sign_digest_context = CRYPT_HANDLE_NONE;
cryptDestroyContext(session->sign_key_context);
session->sign_key_context = CRYPT_HANDLE_NONE;
return rv;
}
/*
* 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;
}
CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_ATTRIBUTE_PTR pPublicKeyTemplate,
CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
CK_ULONG ulPrivateKeyAttributeCount,
CK_OBJECT_HANDLE_PTR phPublicKey,
CK_OBJECT_HANDLE_PTR phPrivateKey)
{
p11_session_t *session = p11_session_find(hSession);
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
if (pMechanism == NULL ||
pPublicKeyTemplate == NULL || phPublicKey == NULL ||
pPrivateKeyTemplate == NULL || phPrivateKey == NULL)
return CKR_ARGUMENTS_BAD;
switch (pMechanism->mechanism) {
case CKM_RSA_PKCS_KEY_PAIR_GEN:
return generate_keypair_rsa_pkcs(session, pMechanism,
pPublicKeyTemplate, ulPublicKeyAttributeCount,
pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
phPublicKey, phPrivateKey);
default:
return CKR_MECHANISM_INVALID;
}
}
CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR RandomData,
CK_ULONG ulRandomLen)
{
p11_session_t *session = p11_session_find(hSession);
CRYPT_CONTEXT ctx = CRYPT_HANDLE_NONE;
CK_RV rv = CKR_OK;
if (session == NULL)
return CKR_SESSION_HANDLE_INVALID;
if (RandomData == NULL)
return 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)
lose(CKR_FUNCTION_FAILED);
fail:
if (ctx != CRYPT_HANDLE_NONE)
(void) cryptDestroyContext(ctx);
return rv;
}
/*
* Stubs for unsupported functions below here. Per the PKCS #11
* specification, it's OK to skip implementing almost any function in
* the API, but if one does so, one must provide a stub which returns
* CKR_FUNCTION_NOT_SUPPORTED, because every slot in the dispatch
* vector must be populated. We could reuse a single stub for all the
* unimplemented slots, but the type signatures wouldn't match, which
* would require some nasty casts I'd rather avoid.
*
* Many of these functions would be straightforward to implement, but
* there are enough bald yaks in this saga already.
*/
CK_RV C_GetInfo(CK_INFO_PTR pInfo)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_GetSlotInfo(CK_SLOT_ID slotID,
CK_SLOT_INFO_PTR pInfo)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_GetMechanismList(CK_SLOT_ID slotID,
CK_MECHANISM_TYPE_PTR pMechanismList,
CK_ULONG_PTR pulCount)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID,
CK_MECHANISM_TYPE type,
CK_MECHANISM_INFO_PTR pInfo)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_InitToken(CK_SLOT_ID slotID,
CK_UTF8CHAR_PTR pPin,
CK_ULONG ulPinLen,
CK_UTF8CHAR_PTR pLabel)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_InitPIN(CK_SESSION_HANDLE hSession,
CK_UTF8CHAR_PTR pPin,
CK_ULONG ulPinLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_SetPIN(CK_SESSION_HANDLE hSession,
CK_UTF8CHAR_PTR pOldPin,
CK_ULONG ulOldLen,
CK_UTF8CHAR_PTR pNewPin,
CK_ULONG ulNewLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession,
CK_SESSION_INFO_PTR pInfo)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pOperationState,
CK_ULONG_PTR pulOperationStateLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pOperationState,
CK_ULONG ulOperationStateLen,
CK_OBJECT_HANDLE hEncryptionKey,
CK_OBJECT_HANDLE hAuthenticationKey)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_CreateObject(CK_SESSION_HANDLE hSession,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount,
CK_OBJECT_HANDLE_PTR phObject)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_CopyObject(CK_SESSION_HANDLE hSession,
CK_OBJECT_HANDLE hObject,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount,
CK_OBJECT_HANDLE_PTR phNewObject)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession,
CK_OBJECT_HANDLE hObject,
CK_ULONG_PTR pulSize)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession,
CK_OBJECT_HANDLE hObject,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_EncryptInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hKey)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_Encrypt(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pData,
CK_ULONG ulDataLen,
CK_BYTE_PTR pEncryptedData,
CK_ULONG_PTR pulEncryptedDataLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pPart,
CK_ULONG ulPartLen,
CK_BYTE_PTR pEncryptedPart,
CK_ULONG_PTR pulEncryptedPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pLastEncryptedPart,
CK_ULONG_PTR pulLastEncryptedPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hKey)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_Decrypt(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pEncryptedData,
CK_ULONG ulEncryptedDataLen,
CK_BYTE_PTR pData,
CK_ULONG_PTR pulDataLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pEncryptedPart,
CK_ULONG ulEncryptedPartLen,
CK_BYTE_PTR pPart,
CK_ULONG_PTR pulPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pLastPart,
CK_ULONG_PTR pulLastPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pPart,
CK_ULONG ulPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DigestKey(CK_SESSION_HANDLE hSession,
CK_OBJECT_HANDLE hKey)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pDigest,
CK_ULONG_PTR pulDigestLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pPart,
CK_ULONG ulPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_SignFinal(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pSignature,
CK_ULONG_PTR pulSignatureLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hKey)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_SignRecover(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pData,
CK_ULONG ulDataLen,
CK_BYTE_PTR pSignature,
CK_ULONG_PTR pulSignatureLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hKey )
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_Verify(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pData,
CK_ULONG ulDataLen,
CK_BYTE_PTR pSignature,
CK_ULONG ulSignatureLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pPart,
CK_ULONG ulPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pSignature,
CK_ULONG ulSignatureLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hKey)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_VerifyRecover(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pSignature,
CK_ULONG ulSignatureLen,
CK_BYTE_PTR pData,
CK_ULONG_PTR pulDataLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pPart,
CK_ULONG ulPartLen,
CK_BYTE_PTR pEncryptedPart,
CK_ULONG_PTR pulEncryptedPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pEncryptedPart,
CK_ULONG ulEncryptedPartLen,
CK_BYTE_PTR pPart,
CK_ULONG_PTR pulPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pPart,
CK_ULONG ulPartLen,
CK_BYTE_PTR pEncryptedPart,
CK_ULONG_PTR pulEncryptedPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pEncryptedPart,
CK_ULONG ulEncryptedPartLen,
CK_BYTE_PTR pPart,
CK_ULONG_PTR pulPartLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_WrapKey(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hWrappingKey,
CK_OBJECT_HANDLE hKey,
CK_BYTE_PTR pWrappedKey,
CK_ULONG_PTR pulWrappedKeyLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hUnwrappingKey,
CK_BYTE_PTR pWrappedKey,
CK_ULONG ulWrappedKeyLen,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
CK_OBJECT_HANDLE_PTR phKey)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hBaseKey,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
CK_OBJECT_HANDLE_PTR phKey)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession,
CK_BYTE_PTR pSeed,
CK_ULONG ulSeedLen)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_CancelFunction(CK_SESSION_HANDLE hSession)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
CK_RV C_WaitForSlotEvent(CK_FLAGS flags,
CK_SLOT_ID_PTR pSlot,
CK_VOID_PTR pRserved)
{ return CKR_FUNCTION_NOT_SUPPORTED; }
/*
* "Any programmer who fails to comply with the standard naming, formatting,
* or commenting conventions should be shot. If it so happens that it is
* inconvenient to shoot him, then he is to be politely requested to recode
* his program in adherence to the above standard."
* -- Michael Spier, Digital Equipment Corporation
*
* Local variables:
* indent-tabs-mode: nil
* End:
*/