/* * 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 #include #include #include #include #include #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 /* * Whether to include POSIX-specific features. */ #ifndef USE_POSIX #define USE_POSIX 1 #endif #if USE_POSIX #include #include #include #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; /* * Mutex callbacks. */ static CK_CREATEMUTEX mutex_cb_create; static CK_DESTROYMUTEX mutex_cb_destroy; static CK_LOCKMUTEX mutex_cb_lock; static CK_UNLOCKMUTEX mutex_cb_unlock; /* * Global mutex. We may want something finer grained later, but this * will suffice to comply with the API requirements. */ static CK_VOID_PTR p11_global_mutex; /* * (POSIX-specific) process which last called C_Initialize(). */ #if USE_POSIX static pid_t initialized_pid; #endif /* * Syntactic sugar for functions returning CK_RV complex enough to * need cleanup actions on failure. Also does very basic logging for * debug-by-printf(). * * NB: This uses a variable ("rv") and a goto target ("fail") which * must be defined in the calling environment. We could make these * arguments to the macro, but doing so would make the code less * readable without significantly reducing the voodoo factor. */ #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); } /* * Thread mutex utilities. We need to handle three separate cases: * * 1) User doesn't care about mutexes; * 2) User wants us to use "OS" mutexes; * 3) User wants us to use user-specified mutexs. * * For "OS" mutexes, read POSIX Threads mutexes, at least for now. * * PKCS #11 sort of has a fourth case, but it's really just license * for us to pick either the second or third case at whim. * * To simplify the rest of the API, we provide a POSIX-based * implementation which uses the same API an user-provided mutex * implementation would be required to use, use null function pointers * to represent the case where the user doesn't need mutexes at all, * and wrap the whole thing in trivial macros to insulate the rest of * the code from the grotty details. */ /* * Basic macros. */ #define mutex_create(_m_) (mutex_cb_create == NULL ? CKR_OK : mutex_cb_create(_m_)) #define mutex_destroy(_m_) (mutex_cb_destroy == NULL ? CKR_OK : mutex_cb_destroy(_m_)) #define mutex_lock(_m_) (mutex_cb_lock == NULL ? CKR_OK : mutex_cb_lock(_m_)) #define mutex_unlock(_m_) (mutex_cb_unlock == NULL ? CKR_OK : mutex_cb_unlock(_m_)) /* * Slightly higher-level macros for common operations. */ #define mutex_lock_or_return_failure(_m_) \ do { \ CK_RV _rv = mutex_lock(_m_); \ if (_rv != CKR_OK) \ return _rv; \ } while (0) #define mutex_unlock_return_with_rv(_rv_, _m_) \ do { \ CK_RV _rv1 = _rv_; \ CK_RV _rv2 = mutex_unlock(_m_); \ return _rv1 == CKR_OK ? _rv2 : _rv1; \ } while (0) /* * Mutex implementation using POSIX mutexes. */ #if USE_POSIX static CK_RV posix_mutex_create(CK_VOID_PTR_PTR ppMutex) { pthread_mutex_t *m = NULL; CK_RV rv; if (ppMutex == NULL) lose(CKR_GENERAL_ERROR); if ((m = malloc(sizeof(*m))) == NULL) lose(CKR_HOST_MEMORY); switch (pthread_mutex_init(m, NULL)) { case 0: *ppMutex = m; return CKR_OK; case ENOMEM: lose(CKR_HOST_MEMORY); default: lose(CKR_GENERAL_ERROR); } fail: if (m != NULL) free(m); return rv; } static CK_RV posix_mutex_destroy(CK_VOID_PTR pMutex) { CK_RV rv; if (pMutex == NULL) lose(CKR_MUTEX_BAD); switch (pthread_mutex_destroy(pMutex)) { case 0: free(pMutex); return CKR_OK; case EINVAL: lose(CKR_MUTEX_BAD); case EBUSY: /* * PKCS #11 mutex semantics are a bad match for POSIX here, * leaving us only the nuclear option. Feh. Fall through. */ default: lose(CKR_GENERAL_ERROR); } fail: return rv; } static CK_RV posix_mutex_lock(CK_VOID_PTR pMutex) { CK_RV rv; if (pMutex == NULL) lose(CKR_MUTEX_BAD); switch (pthread_mutex_lock(pMutex)) { case 0: return CKR_OK; case EINVAL: lose(CKR_MUTEX_BAD); default: lose(CKR_GENERAL_ERROR); } fail: return rv; } static CK_RV posix_mutex_unlock(CK_VOID_PTR pMutex) { CK_RV rv; if (pMutex == NULL) lose(CKR_MUTEX_BAD); switch (pthread_mutex_unlock(pMutex)) { case 0: return CKR_OK; case EINVAL: lose(CKR_MUTEX_BAD); case EPERM: lose(CKR_MUTEX_NOT_LOCKED); default: lose(CKR_GENERAL_ERROR); } fail: return rv; } #endif /* USE_POSIX */ /* * 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; /* * We'd like to detect the error of calling this method more than * once in a single process without an intervening call to * C_Finalize(), but there's no completely portable way to do that * when faced with things like the POSIX fork() system call. For * the moment, we use a POSIX-specific check, but may need to * generalize this for other platforms. */ #if USE_POSIX if (initialized_pid == getpid()) lose(CKR_CRYPTOKI_ALREADY_INITIALIZED); #endif /* * Sort out what the user wants to do about mutexes. Default is not * to use mutexes at all. * * There's a chicken and egg problem here: setting up the global * mutex and mutex function pointers creates a race condition, and * there's no obvious action we can take which is robust in the face * of pathological behavior by the caller such as simultaneous calls * to this method with incompatible mutex primitives. * * Given that (a) it's an error to call this method more than once * in the same process without an intervening F_Finalize() call, and * given that (b) we haven't actually promised to do any kind of * locking at all until this method returns CKR_OK, we punt * responsibility for this pathological case back to the caller. */ mutex_cb_create = NULL; mutex_cb_destroy = NULL; mutex_cb_lock = NULL; mutex_cb_unlock = NULL; if (a != NULL) { const int functions_provided = ((a->CreateMutex != NULL) + (a->DestroyMutex != NULL) + (a->LockMutex != NULL) + (a->UnlockMutex != NULL)); /* * Reserved is, um, reserved. * Mutex parameters must either all be present or all be absent. */ if (a->pReserved != NULL || (functions_provided & 3) != 0) lose(CKR_ARGUMENTS_BAD); /* * If the user provided mutex functions, use them. Otherwise, if * the user wants locking, use POSIX mutexes or return an error * depending on whether we have POSIX mutexes available. * Otherwise, we don't need to use mutexes. */ if (functions_provided) { mutex_cb_create = a->CreateMutex; mutex_cb_destroy = a->DestroyMutex; mutex_cb_lock = a->LockMutex; mutex_cb_unlock = a->UnlockMutex; } else if ((a->flags & CKF_OS_LOCKING_OK) != 0) { #if USE_POSIX mutex_cb_create = posix_mutex_create; mutex_cb_destroy = posix_mutex_destroy; mutex_cb_lock = posix_mutex_lock; mutex_cb_unlock = posix_mutex_unlock; #else lose(CKR_CANT_LOCK); #endif } } /* * Now that we know which mutex implementation to use, set up a * global mutex. We may want something finer grained later, but * this is enough to preserve the basic API semantics. * * Open question whether we should lock at this point, given that * until we return we haven't promised to do locking. Skip for now * as it's simpler, fix later if it turns out to be a problem. */ if ((rv = mutex_create(&p11_global_mutex)) != CKR_OK) goto fail; /* * 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 #if USE_POSIX initialized_pid = getpid(); #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) { CK_RV rv = CKR_OK; if (pReserved != NULL) return CKR_ARGUMENTS_BAD; mutex_lock_or_return_failure(p11_global_mutex); /* * Destroy all current sessions. */ p11_session_delete_all(); /* * Shut down SQLite3. */ if (!sql_fini()) lose(CKR_GENERAL_ERROR); /* * Shut down hardware device and exit cryptlib. Is there any point * in checking error codes here? */ #if ENABLE_CRYPTLIB_DEVICE if (cryptlib_device != CRYPT_HANDLE_NONE) cryptDeviceClose(cryptlib_device); cryptlib_device = CRYPT_HANDLE_NONE; #endif cryptEnd(); /* * By this point we're pretty well committed to shutting down, so * there's not much to be done if these mutex operations fail. */ rv = mutex_unlock(p11_global_mutex); (void) mutex_destroy(p11_global_mutex); p11_global_mutex = NULL; return rv; fail: (void) mutex_unlock(p11_global_mutex); return rv; } 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. * * This doesn't touch anything requiring locks, nor should it. */ 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. * No locking required here as long as this holds. */ 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) { /* * No locking required here as long as we're just returning constants. */ 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; mutex_lock_or_return_failure(p11_global_mutex); 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()); if ((rv = mutex_unlock(p11_global_mutex)) != CKR_OK) goto fail; *phSession = session->handle; return CKR_OK; fail: p11_session_free(session); (void) mutex_unlock(p11_global_mutex); return rv; } CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) { CK_RV rv; mutex_lock_or_return_failure(p11_global_mutex); rv = p11_session_delete(hSession); mutex_unlock_return_with_rv(rv, p11_global_mutex); } CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) { if (slotID != P11_ONE_AND_ONLY_SLOT) return CKR_SLOT_ID_INVALID; mutex_lock_or_return_failure(p11_global_mutex); p11_session_delete_all(); return mutex_unlock(p11_global_mutex); } CK_RV C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { p11_session_t *session; CK_RV rv = CKR_OK; int crypt_cmd; mutex_lock_or_return_failure(p11_global_mutex); if (pPin == NULL) lose(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) lose(CKR_SESSION_HANDLE_INVALID); /* * This is where the combination of pure-software and hardware * starts to get confusing. See the CRYPT_DEVINFO_* attributes for * the operations we can do during device setup (setting PINs, * logging in using pins, etc). * * All fine, but behaves somewhat differently from the case where * we're doing everything in software and using the PIN primarily as * the encryption password for the PKCS #15 keyring. * * In the long run just want the hardware interface. This will * require cleanup. */ /* * We don't currently support re-login without an intervening * logout, so reject the login attempt if we're already logged in. */ if (logged_in_as != not_logged_in) lose(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: lose(CKR_OPERATION_NOT_INITIALIZED); default: lose(CKR_USER_TYPE_INVALID); } /* * Read-only SO is an illegal state, so reject the login attempt if * we have any read-only sessions and we're trying to log in as SO. */ if (userType == CKU_SO) for (session = p11_sessions; session != NULL; session = session->link) if (session->state == CKS_RO_PUBLIC_SESSION) lose(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) lose(CKR_PIN_INCORRECT); #endif #if ENABLE_CRYPTLIB_SOFTWARE { char *newpin; if (memchr(pPin, '\0', ulPinLen) != NULL) lose(CKR_PIN_INCORRECT); if ((newpin = malloc(ulPinLen + 1)) == NULL) lose(CKR_HOST_MEMORY); memcpy(newpin, pPin, ulPinLen); newpin[ulPinLen] = '\0'; if (pin != NULL) free(pin); pin = newpin; } #endif /* * Update global login state, then whack each session into correct new state. */ 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()); fail: mutex_unlock_return_with_rv(rv, p11_global_mutex); } CK_RV C_Logout(CK_SESSION_HANDLE hSession) { p11_session_t *session; CK_RV rv = CKR_OK; int crypt_cmd; mutex_lock_or_return_failure(p11_global_mutex); /* * 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) lose(CKR_SESSION_HANDLE_INVALID); switch (logged_in_as) { case logged_in_as_user: crypt_cmd = CRYPT_DEVINFO_AUTHENT_USER; break; case logged_in_as_so: crypt_cmd = CRYPT_DEVINFO_AUTHENT_SUPERVISOR; break; case not_logged_in: lose(CKR_USER_NOT_LOGGED_IN); } /* * This is a bit problematic, because Cryptlib doesn't have a logout * function per se. For lack of a better idea, construe logout as a * new authentication attempt with an empty PIN. This is a little * weird, but at least it's something we can use as a relatively * clear signal to the HAL, and it's consistent with the way * cryptlib does things like terminating digest inputs. */ #if ENABLE_CRYPTLIB_DEVICE if (cryptSetAttributeString(cryptlib_device, crypt_cmd, "", 0) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); #endif #if ENABLE_CRYPTLIB_SOFTWARE if (pin != NULL) free(pin); pin = NULL; #endif /* * 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()); fail: mutex_unlock_return_with_rv(rv, p11_global_mutex); } 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; sqlite3_stmt *q = NULL; sqlite3_int64 id; CK_RV rv = CKR_OK; mutex_lock_or_return_failure(p11_global_mutex); session = p11_session_find(hSession); if ((rv = p11_object_check_rights(session, hObject, p11_object_access_write)) != CKR_OK) goto fail; if (!sql_check_ok(sql_prepare(&q, select_format, flavor, flavor)) || !sql_check_ok(sqlite3_bind_int64(q, 1, hObject))) lose(CKR_FUNCTION_FAILED); switch (sqlite3_step(q)) { case SQLITE_ROW: break; case SQLITE_DONE: lose(CKR_OBJECT_HANDLE_INVALID); default: sql_whine_step(); lose(CKR_FUNCTION_FAILED); } id = sqlite3_column_int64(q, 0); if (sqlite3_column_type(q, 1) == SQLITE_TEXT && cryptlib_delete_key((const char *) sqlite3_column_text(q, 1)) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); sqlite3_finalize(q); q = NULL; if (is_token_handle(hObject) && (!sql_check_ok(sql_prepare(&q, delete_token_object)) || !sql_check_ok(sqlite3_bind_int64(q, 1, id)) || !sql_check_done(sqlite3_step(q)))) 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); mutex_unlock_return_with_rv(rv, p11_global_mutex); } 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; 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; int ret, i; mutex_lock_or_return_failure(p11_global_mutex); if (pTemplate == NULL) lose(CKR_ARGUMENTS_BAD); session = p11_session_find(hSession); 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); rv = CKR_OK; 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); mutex_unlock_return_with_rv(rv, p11_global_mutex); } 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; sqlite3_stmt *q1 = NULL, *q2 = NULL; CK_RV rv = CKR_OK; int i, ret; mutex_lock_or_return_failure(p11_global_mutex); if ((session = p11_session_find(hSession)) == 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); mutex_unlock_return_with_rv(rv, p11_global_mutex); } CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { p11_session_t *session; int i, ret = SQLITE_OK; CK_RV rv = CKR_OK; mutex_lock_or_return_failure(p11_global_mutex); if ((session = p11_session_find(hSession)) == 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: mutex_unlock_return_with_rv(rv, p11_global_mutex); } CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession) { static const char drop_format[] = " DROP TABLE IF EXISTS findobjects_%lu"; p11_session_t *session; sqlite3_stmt *q = NULL; CK_RV rv = CKR_OK; mutex_lock_or_return_failure(p11_global_mutex); if ((session = p11_session_find(hSession)) == 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); mutex_unlock_return_with_rv(rv, p11_global_mutex); } CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) { p11_session_t *session; CRYPT_ALGO_TYPE algo; unsigned hash_len = 0; CK_RV rv = CKR_OK; mutex_lock_or_return_failure(p11_global_mutex); if ((session = p11_session_find(hSession)) == NULL) lose(CKR_SESSION_HANDLE_INVALID); if (pMechanism == NULL) lose(CKR_ARGUMENTS_BAD); if (session->digest_context != CRYPT_HANDLE_NONE) lose(CKR_OPERATION_ACTIVE); switch (pMechanism->mechanism) { case CKM_SHA_1: algo = CRYPT_ALGO_SHA1; break; case CKM_SHA256: algo = CRYPT_ALGO_SHA2; hash_len = 256; break; case CKM_SHA384: algo = CRYPT_ALGO_SHA2; hash_len = 384; break; case CKM_SHA512: algo = CRYPT_ALGO_SHA2; hash_len = 512; break; default: lose(CKR_MECHANISM_INVALID); } assert((hash_len & 7) == 0); if (cryptlib_create_context(&session->digest_context, algo) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); if (algo == CRYPT_ALGO_SHA2 && cryptSetAttribute(session->digest_context, CRYPT_CTXINFO_BLOCKSIZE, hash_len >> 3) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); return mutex_unlock(p11_global_mutex); fail: if (session != NULL && session->digest_context != CRYPT_HANDLE_NONE) { cryptDestroyContext(session->digest_context); session->digest_context = CRYPT_HANDLE_NONE; } mutex_unlock_return_with_rv(rv, p11_global_mutex); } 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; CK_RV rv = CKR_OK; int len; mutex_lock_or_return_failure(p11_global_mutex); if ((session = p11_session_find(hSession)) == NULL) lose(CKR_SESSION_HANDLE_INVALID); if (pData == NULL || pulDigestLen == NULL) lose(CKR_ARGUMENTS_BAD); if (session->digest_context == CRYPT_HANDLE_NONE) lose(CKR_OPERATION_NOT_INITIALIZED); if (pDigest == NULL) { if (cryptGetAttribute(session->digest_context, CRYPT_CTXINFO_BLOCKSIZE, &len) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); *pulDigestLen = len; return mutex_unlock(p11_global_mutex); } if (cryptEncrypt(session->digest_context, pData, ulDataLen) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); 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: if (session != NULL && session->digest_context != CRYPT_HANDLE_NONE) { cryptDestroyContext(session->digest_context); session->digest_context = CRYPT_HANDLE_NONE; } mutex_unlock_return_with_rv(rv, p11_global_mutex); } CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { p11_session_t *session; char keyid[CRYPT_MAX_HASHSIZE * 2 + 1]; CRYPT_ALGO_TYPE sign_algo, hash_algo; unsigned hash_size = 0; int need_cleanup = 0; int key_algo; CK_RV rv = CKR_OK; mutex_lock_or_return_failure(p11_global_mutex); if ((session = p11_session_find(hSession)) == NULL) lose(CKR_SESSION_HANDLE_INVALID); if (pMechanism == NULL) lose(CKR_ARGUMENTS_BAD); if (session->sign_key_context != CRYPT_HANDLE_NONE || session->sign_digest_context != CRYPT_HANDLE_NONE) lose(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); need_cleanup = 1; if (!p11_object_get_keyid(hKey, keyid, sizeof(keyid)) || cryptlib_load_key(&session->sign_key_context, keyid) != CRYPT_OK || cryptGetAttribute(session->sign_key_context, CRYPT_CTXINFO_ALGO, &key_algo) != CRYPT_OK) lose(CKR_KEY_HANDLE_INVALID); if (sign_algo != key_algo) lose(CKR_KEY_TYPE_INCONSISTENT); if (hash_algo != CRYPT_ALGO_NONE && cryptlib_create_context(&session->sign_digest_context, hash_algo) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); if (hash_algo == CRYPT_ALGO_SHA2 && cryptSetAttribute(session->sign_digest_context, CRYPT_CTXINFO_BLOCKSIZE, hash_size >> 3) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); need_cleanup = 0; rv = CKR_OK; /* Fall through */ fail: assert(!need_cleanup || session != NULL); if (need_cleanup && session->sign_key_context != CRYPT_HANDLE_NONE) { cryptDestroyContext(session->sign_key_context); session->sign_key_context = CRYPT_HANDLE_NONE; } if (need_cleanup && session->sign_digest_context != CRYPT_HANDLE_NONE) { cryptDestroyContext(session->sign_digest_context); session->sign_digest_context = CRYPT_HANDLE_NONE; } mutex_unlock_return_with_rv(rv, p11_global_mutex); } 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; int len, algo; CK_RV rv; mutex_lock_or_return_failure(p11_global_mutex); if ((session = p11_session_find(hSession)) == NULL) lose(CKR_SESSION_HANDLE_INVALID); if (pData == NULL || pulSignatureLen == NULL) lose(CKR_ARGUMENTS_BAD); if (session->sign_key_context == CRYPT_HANDLE_NONE) lose(CKR_OPERATION_NOT_INITIALIZED); if (pSignature == NULL) { /* * Caller just wants to know the signature length, which we can * get from cryptCreateSignature(), using a dummy hash context if * necessary. * * There may be an easier way: at least for RSA, reading the key's * CRYPT_CTXINFO_KEYSIZE would give us the answer. But the * constraint that messages_size == key_size doesn't necessarily * hold for all asymmetric algorithms, so best to be safe here. */ CRYPT_CONTEXT ctx = session->sign_digest_context; if (ctx == CRYPT_HANDLE_NONE && cryptCreateContext(&ctx, CRYPT_UNUSED, CRYPT_ALGO_SHA2) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); if (cryptCreateSignature(NULL, 0, &len, session->sign_key_context, ctx) != CRYPT_OK) len = 0; 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 != NULL && session->sign_digest_context != CRYPT_HANDLE_NONE) { cryptDestroyContext(session->sign_digest_context); session->sign_digest_context = CRYPT_HANDLE_NONE; } if (session != NULL && session->sign_key_context != CRYPT_HANDLE_NONE) { cryptDestroyContext(session->sign_key_context); session->sign_key_context = CRYPT_HANDLE_NONE; } mutex_unlock_return_with_rv(rv, p11_global_mutex); } /* * libhsm only uses C_GenerateKey() for DSA parameter generation. * More general use presumably wants this for things like generating * symmetric keys for later wrapping by asymmetric keys. */ CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) { return CKR_FUNCTION_NOT_SUPPORTED; } /* * If there's any method in this entire package which really needs a * more complex mutex structure than the single global mutex, it's * probably this one. Key generation can take a looooong time. * Drive off that bridge when we get to it. */ 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; CK_RV rv; mutex_lock_or_return_failure(p11_global_mutex); if ((session = p11_session_find(hSession)) == NULL) lose(CKR_SESSION_HANDLE_INVALID); if (pMechanism == NULL || pPublicKeyTemplate == NULL || phPublicKey == NULL || pPrivateKeyTemplate == NULL || phPrivateKey == NULL) lose(CKR_ARGUMENTS_BAD); switch (pMechanism->mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: rv = generate_keypair_rsa_pkcs(session, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey); break; default: lose(CKR_MECHANISM_INVALID); } fail: mutex_unlock_return_with_rv(rv, p11_global_mutex); } CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData, CK_ULONG ulRandomLen) { p11_session_t *session; CRYPT_CONTEXT ctx = CRYPT_HANDLE_NONE; CK_RV rv = CKR_OK; mutex_lock_or_return_failure(p11_global_mutex); if ((session = p11_session_find(hSession)) == NULL) lose(CKR_SESSION_HANDLE_INVALID); if (RandomData == NULL) lose(CKR_ARGUMENTS_BAD); /* * Cryptlib doesn't expose the raw TRNG, but, per the manual, block * cipher encryption output with a randomly generated key is good * enough for most sane purposes. * * Not certain why the Cryptlib manual suggests using CFB mode * instead of OFB mode here, but going with the manual for now. */ if (cryptCreateContext(&ctx, CRYPT_UNUSED, CRYPT_ALGO_AES) != CRYPT_OK || cryptSetAttribute(ctx, CRYPT_CTXINFO_MODE, CRYPT_MODE_CFB) != CRYPT_OK || cryptGenerateKey(ctx) != CRYPT_OK || cryptEncrypt(ctx, RandomData, ulRandomLen) != CRYPT_OK) lose(CKR_FUNCTION_FAILED); fail: if (ctx != CRYPT_HANDLE_NONE) (void) cryptDestroyContext(ctx); mutex_unlock_return_with_rv(rv, p11_global_mutex); } /* * 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: */