aboutsummaryrefslogtreecommitdiff
path: root/lib/hcrypto/evp-pkcs11.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hcrypto/evp-pkcs11.c')
-rw-r--r--lib/hcrypto/evp-pkcs11.c207
1 files changed, 129 insertions, 78 deletions
diff --git a/lib/hcrypto/evp-pkcs11.c b/lib/hcrypto/evp-pkcs11.c
index 93af9b4564c0..325bb0afd104 100644
--- a/lib/hcrypto/evp-pkcs11.c
+++ b/lib/hcrypto/evp-pkcs11.c
@@ -60,7 +60,7 @@
#include <ref/pkcs11.h>
#if __sun && !defined(PKCS11_MODULE_PATH)
-# if _LP64
+# ifdef _LP64
# define PKCS11_MODULE_PATH "/usr/lib/64/libpkcs11.so"
# else
# define PKCS11_MODULE_PATH "/usr/lib/libpkcs11.so"
@@ -87,7 +87,6 @@ p11_cleanup(EVP_CIPHER_CTX *ctx);
struct pkcs11_cipher_ctx {
CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hSecret;
- int cipher_init_done;
};
struct pkcs11_md_ctx {
@@ -95,12 +94,14 @@ struct pkcs11_md_ctx {
};
static void *pkcs11_module_handle;
-static void
-p11_module_init_once(void *context)
+
+static CK_RV
+p11_module_load(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
{
CK_RV rv;
- CK_FUNCTION_LIST_PTR module;
CK_RV (*C_GetFunctionList_fn)(CK_FUNCTION_LIST_PTR_PTR);
+
+ *ppFunctionList = NULL;
if (!issuid()) {
char *pkcs11ModulePath = getenv("PKCS11_MODULE_PATH");
@@ -109,7 +110,7 @@ p11_module_init_once(void *context)
dlopen(pkcs11ModulePath,
RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP | RTLD_NODELETE);
if (pkcs11_module_handle == NULL)
- fprintf(stderr, "p11_module_init(%s): %s\n", pkcs11ModulePath, dlerror());
+ fprintf(stderr, "p11_module_load(%s): %s\n", pkcs11ModulePath, dlerror());
}
}
#ifdef PKCS11_MODULE_PATH
@@ -118,47 +119,63 @@ p11_module_init_once(void *context)
dlopen(PKCS11_MODULE_PATH,
RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP | RTLD_NODELETE);
if (pkcs11_module_handle == NULL)
- fprintf(stderr, "p11_module_init(%s): %s\n", PKCS11_MODULE_PATH, dlerror());
+ fprintf(stderr, "p11_module_load(%s): %s\n", PKCS11_MODULE_PATH, dlerror());
}
#endif
if (pkcs11_module_handle == NULL)
- goto cleanup;
+ return CKR_LIBRARY_LOAD_FAILED;
C_GetFunctionList_fn = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))
dlsym(pkcs11_module_handle, "C_GetFunctionList");
- if (C_GetFunctionList_fn == NULL)
- goto cleanup;
+ if (C_GetFunctionList_fn == NULL) {
+ dlclose(pkcs11_module_handle);
+ return CKR_LIBRARY_LOAD_FAILED;
+ }
- rv = C_GetFunctionList_fn(&module);
- if (rv != CKR_OK)
- goto cleanup;
+ rv = C_GetFunctionList_fn(ppFunctionList);
+ if (rv != CKR_OK) {
+ dlclose(pkcs11_module_handle);
+ return rv;
+ }
- rv = module->C_Initialize(NULL);
- if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
- rv = CKR_OK;
- if (rv == CKR_OK)
- *((CK_FUNCTION_LIST_PTR_PTR)context) = module;
+ return CKR_OK;
+}
-cleanup:
- if (pkcs11_module_handle != NULL && p11_module == NULL) {
- dlclose(pkcs11_module_handle);
- pkcs11_module_handle = NULL;
- }
- /* else leak pkcs11_module_handle */
+static void
+p11_module_load_once(void *context)
+{
+ p11_module_load((CK_FUNCTION_LIST_PTR_PTR)context);
}
static CK_RV
p11_module_init(void)
{
- static heim_base_once_t init_module = HEIM_BASE_ONCE_INIT;
+ static heim_base_once_t once = HEIM_BASE_ONCE_INIT;
+ CK_RV rv;
- heim_base_once_f(&init_module, &p11_module, p11_module_init_once);
+ heim_base_once_f(&once, &p11_module, p11_module_load_once);
- return p11_module != NULL ? CKR_OK : CKR_LIBRARY_LOAD_FAILED;
+ if (p11_module == NULL)
+ return CKR_LIBRARY_LOAD_FAILED;
+
+ /*
+ * Call C_Initialize() on every call, because it will be invalid after fork().
+ * Caching the initialization status using a once control and invalidating it
+ * on fork provided no measurable performance benefit on Solaris 11. Other
+ * approaches would not be thread-safe or would involve more intrusive code
+ * changes, such as exposing heimbase's atomics.
+ */
+ rv = p11_module->C_Initialize(NULL);
+ if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
+ rv = CKR_OK;
+
+ return rv;
}
static CK_RV
-p11_session_init(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE_PTR phSession)
+p11_session_init(CK_MECHANISM_TYPE mechanismType,
+ CK_SESSION_HANDLE_PTR phSession,
+ CK_FLAGS *pFlags)
{
CK_RV rv;
CK_ULONG i, ulSlotCount = 0;
@@ -168,6 +185,8 @@ p11_session_init(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE_PTR phSessio
if (phSession != NULL)
*phSession = CK_INVALID_HANDLE;
+ *pFlags = 0;
+
rv = p11_module_init();
if (rv != CKR_OK)
goto cleanup;
@@ -198,8 +217,10 @@ p11_session_init(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE_PTR phSessio
*/
for (i = 0; i < ulSlotCount; i++) {
rv = p11_module->C_GetMechanismInfo(pSlotList[i], mechanismType, &info);
- if (rv == CKR_OK)
- break;
+ if (rv == CKR_OK) {
+ *pFlags = info.flags;
+ break;
+ }
}
if (i == ulSlotCount) {
@@ -220,9 +241,16 @@ cleanup:
}
static int
-p11_mech_available_p(CK_MECHANISM_TYPE mechanismType)
+p11_mech_available_p(CK_MECHANISM_TYPE mechanismType, CK_FLAGS reqFlags)
{
- return p11_session_init(mechanismType, NULL) == CKR_OK;
+ CK_RV rv;
+ CK_FLAGS flags;
+
+ rv = p11_session_init(mechanismType, NULL, &flags);
+ if (rv != CKR_OK)
+ return 0;
+
+ return (flags & reqFlags) == reqFlags;
}
static CK_KEY_TYPE
@@ -281,20 +309,49 @@ p11_key_init(EVP_CIPHER_CTX *ctx,
{ CKA_VALUE, (void *)key, ctx->key_len },
{ op, &bTrue, sizeof(bTrue) }
};
+ CK_MECHANISM mechanism = {
+ mechanismType,
+ ctx->cipher->iv_len ? ctx->iv : NULL,
+ ctx->cipher->iv_len
+ };
struct pkcs11_cipher_ctx *p11ctx = (struct pkcs11_cipher_ctx *)ctx->cipher_data;
- p11ctx->cipher_init_done = 0;
+ CK_FLAGS flags;
- rv = p11_session_init(mechanismType, &p11ctx->hSession);
- if (rv != CKR_OK)
- goto cleanup;
+ rv = CKR_OK;
- assert(p11_module != NULL);
+ if (p11ctx->hSession != CK_INVALID_HANDLE && key != NULL)
+ p11_cleanup(ctx); /* refresh session with new key */
- rv = p11_module->C_CreateObject(p11ctx->hSession, attributes,
- sizeof(attributes) / sizeof(attributes[0]),
- &p11ctx->hSecret);
- if (rv != CKR_OK)
- goto cleanup;
+ if (p11ctx->hSession == CK_INVALID_HANDLE) {
+ rv = p11_session_init(mechanismType, &p11ctx->hSession, &flags);
+ if (rv != CKR_OK)
+ goto cleanup;
+
+ if ((flags & (CKF_ENCRYPT|CKF_DECRYPT)) != (CKF_ENCRYPT|CKF_DECRYPT)) {
+ rv = CKR_MECHANISM_INVALID;
+ goto cleanup;
+ }
+ }
+
+ if (key != NULL) {
+ assert(p11_module != NULL);
+ assert(p11ctx->hSecret == CK_INVALID_HANDLE);
+
+ rv = p11_module->C_CreateObject(p11ctx->hSession, attributes,
+ sizeof(attributes) / sizeof(attributes[0]),
+ &p11ctx->hSecret);
+ if (rv != CKR_OK)
+ goto cleanup;
+ }
+
+ if (p11ctx->hSecret != CK_INVALID_HANDLE) {
+ if (op == CKA_ENCRYPT)
+ rv = p11_module->C_EncryptInit(p11ctx->hSession, &mechanism, p11ctx->hSecret);
+ else
+ rv = p11_module->C_DecryptInit(p11ctx->hSession, &mechanism, p11ctx->hSecret);
+ if (rv != CKR_OK)
+ goto cleanup;
+ }
cleanup:
if (rv != CKR_OK)
@@ -310,37 +367,17 @@ p11_do_cipher(EVP_CIPHER_CTX *ctx,
unsigned int size)
{
struct pkcs11_cipher_ctx *p11ctx = (struct pkcs11_cipher_ctx *)ctx->cipher_data;
- CK_RV rv = CKR_OK;
+ CK_RV rv;
CK_ULONG ulCipherTextLen = size;
- CK_MECHANISM_TYPE mechanismType = (CK_MECHANISM_TYPE)ctx->cipher->app_data;
- CK_MECHANISM mechanism = {
- mechanismType,
- ctx->cipher->iv_len ? ctx->iv : NULL,
- ctx->cipher->iv_len
- };
assert(p11_module != NULL);
- /* The EVP layer only ever calls us with complete cipher blocks */
assert(EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_STREAM_CIPHER ||
(size % ctx->cipher->block_size) == 0);
- if (ctx->encrypt) {
- if (!p11ctx->cipher_init_done) {
- rv = p11_module->C_EncryptInit(p11ctx->hSession, &mechanism, p11ctx->hSecret);
- if (rv == CKR_OK)
- p11ctx->cipher_init_done = 1;
- }
- if (rv == CKR_OK)
- rv = p11_module->C_EncryptUpdate(p11ctx->hSession, (unsigned char *)in, size, out, &ulCipherTextLen);
- } else {
- if (!p11ctx->cipher_init_done) {
- rv = p11_module->C_DecryptInit(p11ctx->hSession, &mechanism, p11ctx->hSecret);
- if (rv == CKR_OK)
- p11ctx->cipher_init_done = 1;
- }
- if (rv == CKR_OK)
- rv = p11_module->C_DecryptUpdate(p11ctx->hSession, (unsigned char *)in, size, out, &ulCipherTextLen);
- }
+ if (ctx->encrypt)
+ rv = p11_module->C_EncryptUpdate(p11ctx->hSession, (unsigned char *)in, size, out, &ulCipherTextLen);
+ else
+ rv = p11_module->C_DecryptUpdate(p11ctx->hSession, (unsigned char *)in, size, out, &ulCipherTextLen);
return rv == CKR_OK;
}
@@ -350,8 +387,6 @@ p11_cleanup(EVP_CIPHER_CTX *ctx)
{
struct pkcs11_cipher_ctx *p11ctx = (struct pkcs11_cipher_ctx *)ctx->cipher_data;
- assert(p11_module != NULL);
-
if (p11ctx->hSecret != CK_INVALID_HANDLE) {
p11_module->C_DestroyObject(p11ctx->hSession, p11ctx->hSecret);
p11ctx->hSecret = CK_INVALID_HANDLE;
@@ -365,20 +400,33 @@ p11_cleanup(EVP_CIPHER_CTX *ctx)
}
static int
+p11_md_cleanup(EVP_MD_CTX *ctx);
+
+static int
p11_md_hash_init(CK_MECHANISM_TYPE mechanismType, EVP_MD_CTX *ctx)
{
struct pkcs11_md_ctx *p11ctx = (struct pkcs11_md_ctx *)ctx;
CK_RV rv;
+ CK_FLAGS flags;
+ CK_MECHANISM mechanism = { mechanismType, NULL, 0 };
- rv = p11_session_init(mechanismType, &p11ctx->hSession);
- if (rv == CKR_OK) {
- CK_MECHANISM mechanism = { mechanismType, NULL, 0 };
+ if (p11ctx->hSession != CK_INVALID_HANDLE)
+ p11_md_cleanup(ctx);
- assert(p11_module != NULL);
+ rv = p11_session_init(mechanismType, &p11ctx->hSession, &flags);
+ if (rv != CKR_OK)
+ goto cleanup;
- rv = p11_module->C_DigestInit(p11ctx->hSession, &mechanism);
+ if ((flags & CKF_DIGEST) != CKF_DIGEST) {
+ rv = CKR_MECHANISM_INVALID;
+ goto cleanup;
}
+ assert(p11_module != NULL);
+
+ rv = p11_module->C_DigestInit(p11ctx->hSession, &mechanism);
+
+ cleanup:
return rv == CKR_OK;
}
@@ -389,8 +437,11 @@ p11_md_update(EVP_MD_CTX *ctx, const void *data, size_t length)
CK_RV rv;
assert(p11_module != NULL);
+ assert(data != NULL || length == 0);
- rv = p11_module->C_DigestUpdate(p11ctx->hSession, (unsigned char *)data, length);
+ rv = p11_module->C_DigestUpdate(p11ctx->hSession,
+ data ? (CK_BYTE_PTR)data : (CK_BYTE_PTR)"",
+ length);
return rv == CKR_OK;
}
@@ -435,7 +486,7 @@ p11_md_cleanup(EVP_MD_CTX *ctx)
block_size, \
key_len, \
iv_len, \
- flags, \
+ (flags) | EVP_CIPH_ALWAYS_CALL_INIT, \
p11_key_init, \
p11_do_cipher, \
p11_cleanup, \
@@ -449,7 +500,7 @@ p11_md_cleanup(EVP_MD_CTX *ctx)
const EVP_CIPHER * \
hc_EVP_pkcs11_##name(void) \
{ \
- if (p11_mech_available_p(mechanismType)) \
+ if (p11_mech_available_p(mechanismType, CKF_ENCRYPT|CKF_DECRYPT)) \
return &pkcs11_##name; \
else \
return NULL; \
@@ -499,7 +550,7 @@ p11_md_cleanup(EVP_MD_CTX *ctx)
p11_md_cleanup \
}; \
\
- if (p11_mech_available_p(mechanismType)) \
+ if (p11_mech_available_p(mechanismType, CKF_DIGEST)) \
return &name; \
else \
return NULL; \