 5c70e5015e
			
		
	
	5c70e5015e
	
	
	
		
			
			Before committing to a PKCS#11 mechanism, check that it can provide the required encryption or digest services by validating the flags returned by C_GetMechanismInfo().
		
			
				
	
	
		
			833 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			833 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2015-2016, Secure Endpoints Inc.
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  *
 | |
|  * - Redistributions of source code must retain the above copyright
 | |
|  *   notice, this list of conditions and the following disclaimer.
 | |
|  *
 | |
|  * - 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 HOLDER 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.
 | |
|  */
 | |
| 
 | |
| /* PKCS#11 provider */
 | |
| 
 | |
| #include <config.h>
 | |
| #include <roken.h>
 | |
| #include <assert.h>
 | |
| 
 | |
| #ifndef HAVE_DLFCN_H
 | |
| #error PKCS11 support requires dlfcn.h
 | |
| #endif
 | |
| 
 | |
| #include <heimbase.h>
 | |
| 
 | |
| #include <evp.h>
 | |
| #include <evp-hcrypto.h>
 | |
| #include <evp-pkcs11.h>
 | |
| 
 | |
| #include <ref/pkcs11.h>
 | |
| 
 | |
| #if __sun && !defined(PKCS11_MODULE_PATH)
 | |
| # ifdef _LP64
 | |
| # define PKCS11_MODULE_PATH "/usr/lib/64/libpkcs11.so"
 | |
| # else
 | |
| # define PKCS11_MODULE_PATH "/usr/lib/libpkcs11.so"
 | |
| # endif
 | |
| #elif defined(__linux__)
 | |
| /*
 | |
|  * XXX We should have an autoconf check for OpenCryptoki and such
 | |
|  * things.  However, there's no AC_CHECK_OBJECT(), and we'd have to
 | |
|  * write one.  Today I'm feeling lazy.  Another possibility would be to
 | |
|  * have a symlink from the libdir we'll install into, and then we could
 | |
|  * dlopen() that on all platforms.
 | |
|  *
 | |
|  * XXX Also, we should pick an appropriate shared object based on 32- vs
 | |
|  * 64-bits.
 | |
|  */
 | |
| # define PKCS11_MODULE_PATH "/usr/lib/pkcs11/PKCS11_API.so"
 | |
| #endif
 | |
| 
 | |
| static CK_FUNCTION_LIST_PTR p11_module;
 | |
| 
 | |
| static int
 | |
| p11_cleanup(EVP_CIPHER_CTX *ctx);
 | |
| 
 | |
| struct pkcs11_cipher_ctx {
 | |
|     CK_SESSION_HANDLE hSession;
 | |
|     CK_OBJECT_HANDLE hSecret;
 | |
| };
 | |
| 
 | |
| struct pkcs11_md_ctx {
 | |
|     CK_SESSION_HANDLE hSession;
 | |
| };
 | |
| 
 | |
| static void *pkcs11_module_handle;
 | |
| 
 | |
| static CK_RV
 | |
| p11_module_load(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
 | |
| {
 | |
|     CK_RV rv;
 | |
|     CK_RV (*C_GetFunctionList_fn)(CK_FUNCTION_LIST_PTR_PTR);
 | |
|     char *pkcs11ModulePath = secure_getenv("PKCS11_MODULE_PATH");
 | |
| 
 | |
|     *ppFunctionList = NULL;
 | |
| 
 | |
|     if (pkcs11ModulePath != NULL) {
 | |
|         pkcs11_module_handle =
 | |
|             dlopen(pkcs11ModulePath,
 | |
|                    RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP | RTLD_NODELETE);
 | |
|         if (pkcs11_module_handle == NULL)
 | |
|             fprintf(stderr, "p11_module_load(%s): %s\n", pkcs11ModulePath, dlerror());
 | |
|     }
 | |
| #ifdef PKCS11_MODULE_PATH
 | |
|     if (pkcs11_module_handle == NULL) {
 | |
| 	pkcs11_module_handle =
 | |
| 	    dlopen(PKCS11_MODULE_PATH,
 | |
| 		   RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP | RTLD_NODELETE);
 | |
| 	if (pkcs11_module_handle == NULL)
 | |
|             fprintf(stderr, "p11_module_load(%s): %s\n", PKCS11_MODULE_PATH, dlerror());
 | |
|     }
 | |
| #endif
 | |
|     if (pkcs11_module_handle == NULL)
 | |
|         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) {
 | |
|         dlclose(pkcs11_module_handle);
 | |
|         return CKR_LIBRARY_LOAD_FAILED;
 | |
|     }
 | |
| 
 | |
|     rv = C_GetFunctionList_fn(ppFunctionList);
 | |
|     if (rv != CKR_OK) {
 | |
|         dlclose(pkcs11_module_handle);
 | |
|         return rv;
 | |
|     }
 | |
| 
 | |
|     return CKR_OK;
 | |
| }
 | |
| 
 | |
| 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 once = HEIM_BASE_ONCE_INIT;
 | |
|     CK_RV rv;
 | |
| 
 | |
|     heim_base_once_f(&once, &p11_module, p11_module_load_once);
 | |
| 
 | |
|     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,
 | |
|                  CK_FLAGS *pFlags)
 | |
| {
 | |
|     CK_RV rv;
 | |
|     CK_ULONG i, ulSlotCount = 0;
 | |
|     CK_SLOT_ID_PTR pSlotList = NULL;
 | |
|     CK_MECHANISM_INFO info;
 | |
| 
 | |
|     if (phSession != NULL)
 | |
|         *phSession = CK_INVALID_HANDLE;
 | |
| 
 | |
|     *pFlags = 0;
 | |
| 
 | |
|     rv = p11_module_init();
 | |
|     if (rv != CKR_OK)
 | |
|         goto cleanup;
 | |
| 
 | |
|     assert(p11_module != NULL);
 | |
| 
 | |
|     rv = p11_module->C_GetSlotList(CK_FALSE, NULL, &ulSlotCount);
 | |
|     if (rv != CKR_OK)
 | |
|         goto cleanup;
 | |
| 
 | |
|     pSlotList = (CK_SLOT_ID_PTR)calloc(ulSlotCount, sizeof(CK_SLOT_ID));
 | |
|     if (pSlotList == NULL) {
 | |
|         rv = CKR_HOST_MEMORY;
 | |
|         goto cleanup;
 | |
|     }
 | |
| 
 | |
|     rv = p11_module->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
 | |
|     if (rv != CKR_OK)
 | |
|         goto cleanup;
 | |
| 
 | |
|     /*
 | |
|      * Note that this approach of using the first slot that supports the desired
 | |
|      * mechanism may not always be what the user wants (for example it may prefer
 | |
|      * software to hardware crypto). We're going to assume that this code will be
 | |
|      * principally used on Solaris (which has a meta-slot provider that sorts by
 | |
|      * hardware first) or in situations where the user can configure the slots in
 | |
|      * order of provider preference. In the future we should make this configurable.
 | |
|      */
 | |
|     for (i = 0; i < ulSlotCount; i++) {
 | |
|         rv = p11_module->C_GetMechanismInfo(pSlotList[i], mechanismType, &info);
 | |
|         if (rv == CKR_OK) {
 | |
| 	    *pFlags = info.flags;
 | |
| 	    break;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (i == ulSlotCount) {
 | |
|         rv = CKR_MECHANISM_INVALID;
 | |
|         goto cleanup;
 | |
|     }
 | |
| 
 | |
|     if (phSession != NULL) {
 | |
|         rv = p11_module->C_OpenSession(pSlotList[i], CKF_SERIAL_SESSION, NULL, NULL, phSession);
 | |
|         if (rv != CKR_OK)
 | |
|             goto cleanup;
 | |
|     }
 | |
| 
 | |
| cleanup:
 | |
|     free(pSlotList);
 | |
| 
 | |
|     return rv;
 | |
| }
 | |
| 
 | |
| static int
 | |
| p11_mech_available_p(CK_MECHANISM_TYPE mechanismType, CK_FLAGS reqFlags)
 | |
| {
 | |
|     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
 | |
| p11_key_type_for_mech(CK_MECHANISM_TYPE mechanismType)
 | |
| {
 | |
|     CK_KEY_TYPE keyType = 0;
 | |
| 
 | |
|     switch (mechanismType) {
 | |
|     case CKM_RC2_CBC:
 | |
|         keyType = CKK_RC2;
 | |
|         break;
 | |
|     case CKM_RC4:
 | |
|         keyType = CKK_RC4;
 | |
|         break;
 | |
|     case CKM_DES_CBC:
 | |
|         keyType = CKK_DES;
 | |
|         break;
 | |
|     case CKM_DES3_CBC:
 | |
|         keyType = CKK_DES3;
 | |
|         break;
 | |
|     case CKM_AES_CBC:
 | |
|     case CKM_AES_CFB8:
 | |
|         keyType = CKK_AES;
 | |
|         break;
 | |
|     case CKM_CAMELLIA_CBC:
 | |
|         keyType = CKK_CAMELLIA;
 | |
|         break;
 | |
|     default:
 | |
|         assert(0 && "Unknown PKCS#11 mechanism type");
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     return keyType;
 | |
| }
 | |
| 
 | |
| static int
 | |
| p11_key_init(EVP_CIPHER_CTX *ctx,
 | |
|              const unsigned char *key,
 | |
|              const unsigned char *iv,
 | |
|              int encp)
 | |
| {
 | |
|     CK_RV rv;
 | |
|     CK_BBOOL bFalse = CK_FALSE;
 | |
|     CK_BBOOL bTrue = CK_TRUE;
 | |
|     CK_MECHANISM_TYPE mechanismType = (CK_MECHANISM_TYPE)ctx->cipher->app_data;
 | |
|     CK_KEY_TYPE keyType = p11_key_type_for_mech(mechanismType);
 | |
|     CK_OBJECT_CLASS objectClass = CKO_SECRET_KEY;
 | |
|     CK_ATTRIBUTE_TYPE op = encp ? CKA_ENCRYPT : CKA_DECRYPT;
 | |
|     CK_ATTRIBUTE attributes[] = {
 | |
|         { CKA_EXTRACTABLE,      &bFalse,        sizeof(bFalse)          },
 | |
|         { CKA_CLASS,            &objectClass,   sizeof(objectClass)     },
 | |
|         { CKA_KEY_TYPE,         &keyType,       sizeof(keyType)         },
 | |
|         { CKA_TOKEN,            &bFalse,        sizeof(bFalse)          },
 | |
|         { CKA_PRIVATE,          &bFalse,        sizeof(bFalse)          },
 | |
|         { CKA_SENSITIVE,        &bTrue,         sizeof(bTrue)           },
 | |
|         { 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;
 | |
|     CK_FLAGS flags;
 | |
| 
 | |
|     rv = CKR_OK;
 | |
| 
 | |
|     if (p11ctx->hSession != CK_INVALID_HANDLE && key != NULL)
 | |
|         p11_cleanup(ctx); /* refresh session with new key */
 | |
| 
 | |
|     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)
 | |
|         p11_cleanup(ctx);
 | |
| 
 | |
|     return rv == CKR_OK;
 | |
| }
 | |
| 
 | |
| static int
 | |
| p11_do_cipher(EVP_CIPHER_CTX *ctx,
 | |
|               unsigned char *out,
 | |
|               const unsigned char *in,
 | |
|               unsigned int size)
 | |
| {
 | |
|     struct pkcs11_cipher_ctx *p11ctx = (struct pkcs11_cipher_ctx *)ctx->cipher_data;
 | |
|     CK_RV rv;
 | |
|     CK_ULONG ulCipherTextLen = size;
 | |
| 
 | |
|     assert(p11_module != NULL);
 | |
|     assert(EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_STREAM_CIPHER ||
 | |
|            (size % ctx->cipher->block_size) == 0);
 | |
| 
 | |
|     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;
 | |
| }
 | |
| 
 | |
| static int
 | |
| p11_cleanup(EVP_CIPHER_CTX *ctx)
 | |
| {
 | |
|     struct pkcs11_cipher_ctx *p11ctx = (struct pkcs11_cipher_ctx *)ctx->cipher_data;
 | |
| 
 | |
|     if (p11ctx->hSecret != CK_INVALID_HANDLE)  {
 | |
|         p11_module->C_DestroyObject(p11ctx->hSession, p11ctx->hSecret);
 | |
|         p11ctx->hSecret = CK_INVALID_HANDLE;
 | |
|     }
 | |
|     if (p11ctx->hSession != CK_INVALID_HANDLE) {
 | |
|         p11_module->C_CloseSession(p11ctx->hSession);
 | |
|         p11ctx->hSession = CK_INVALID_HANDLE;
 | |
|     }
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| 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 };
 | |
| 
 | |
|     if (p11ctx->hSession != CK_INVALID_HANDLE)
 | |
|         p11_md_cleanup(ctx);
 | |
| 
 | |
|     rv = p11_session_init(mechanismType, &p11ctx->hSession, &flags);
 | |
|     if (rv != CKR_OK)
 | |
| 	goto cleanup;
 | |
| 
 | |
|     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;
 | |
| }
 | |
| 
 | |
| static int
 | |
| p11_md_update(EVP_MD_CTX *ctx, const void *data, size_t length)
 | |
| {
 | |
|     struct pkcs11_md_ctx *p11ctx = (struct pkcs11_md_ctx *)ctx;
 | |
|     CK_RV rv;
 | |
| 
 | |
|     assert(p11_module != NULL);
 | |
|     assert(data != NULL || length == 0);
 | |
| 
 | |
|     rv = p11_module->C_DigestUpdate(p11ctx->hSession,
 | |
|                                     data ? (CK_BYTE_PTR)data : (CK_BYTE_PTR)"",
 | |
|                                     length);
 | |
| 
 | |
|     return rv == CKR_OK;
 | |
| }
 | |
| 
 | |
| static int
 | |
| p11_md_final(void *digest, EVP_MD_CTX *ctx)
 | |
| {
 | |
|     struct pkcs11_md_ctx *p11ctx = (struct pkcs11_md_ctx *)ctx;
 | |
|     CK_RV rv;
 | |
|     CK_ULONG digestLen = 0;
 | |
| 
 | |
|     assert(p11_module != NULL);
 | |
| 
 | |
|     rv = p11_module->C_DigestFinal(p11ctx->hSession, NULL, &digestLen);
 | |
|     if (rv == CKR_OK)
 | |
|         rv = p11_module->C_DigestFinal(p11ctx->hSession, digest, &digestLen);
 | |
| 
 | |
|     return rv == CKR_OK;
 | |
| }
 | |
| 
 | |
| static int
 | |
| p11_md_cleanup(EVP_MD_CTX *ctx)
 | |
| {
 | |
|     struct pkcs11_md_ctx *p11ctx = (struct pkcs11_md_ctx *)ctx;
 | |
|     CK_RV rv;
 | |
| 
 | |
|     assert(p11_module != NULL);
 | |
| 
 | |
|     rv = p11_module->C_CloseSession(p11ctx->hSession);
 | |
|     if (rv == CKR_OK)
 | |
|         p11ctx->hSession = CK_INVALID_HANDLE;
 | |
| 
 | |
|     return rv == CKR_OK;
 | |
| }
 | |
| 
 | |
| #define PKCS11_CIPHER_ALGORITHM(name, mechanismType, block_size,        \
 | |
|                                 key_len, iv_len, flags)                 \
 | |
|                                                                         \
 | |
|     static EVP_CIPHER                                                   \
 | |
|     pkcs11_##name = {                                                   \
 | |
|         0,                                                              \
 | |
|         block_size,                                                     \
 | |
|         key_len,                                                        \
 | |
|         iv_len,                                                         \
 | |
|         (flags) | EVP_CIPH_ALWAYS_CALL_INIT,                            \
 | |
|         p11_key_init,                                                   \
 | |
|         p11_do_cipher,                                                  \
 | |
|         p11_cleanup,                                                    \
 | |
|         sizeof(struct pkcs11_cipher_ctx),                               \
 | |
|         NULL,                                                           \
 | |
|         NULL,                                                           \
 | |
|         NULL,                                                           \
 | |
|         (void *)mechanismType                                           \
 | |
|     };                                                                  \
 | |
|                                                                         \
 | |
|     const EVP_CIPHER *                                                  \
 | |
|     hc_EVP_pkcs11_##name(void)                                          \
 | |
|     {                                                                   \
 | |
|         if (p11_mech_available_p(mechanismType, CKF_ENCRYPT|CKF_DECRYPT)) \
 | |
|             return &pkcs11_##name;                                      \
 | |
|         else                                                            \
 | |
|             return NULL;                                                \
 | |
|     }                                                                   \
 | |
|                                                                         \
 | |
|     static void                                                         \
 | |
|     pkcs11_hcrypto_##name##_init_once(void *context)                    \
 | |
|     {                                                                   \
 | |
|         const EVP_CIPHER *cipher;                                       \
 | |
|                                                                         \
 | |
|         cipher = hc_EVP_pkcs11_ ##name();                               \
 | |
|         if (cipher == NULL && HCRYPTO_FALLBACK)                         \
 | |
|             cipher = hc_EVP_hcrypto_ ##name();                          \
 | |
|                                                                         \
 | |
|         *((const EVP_CIPHER **)context) = cipher;                       \
 | |
|     }                                                                   \
 | |
|                                                                         \
 | |
|     const EVP_CIPHER *                                                  \
 | |
|     hc_EVP_pkcs11_hcrypto_##name(void)                                  \
 | |
|     {                                                                   \
 | |
|         static const EVP_CIPHER *__cipher;                              \
 | |
|         static heim_base_once_t __init = HEIM_BASE_ONCE_INIT;           \
 | |
|                                                                         \
 | |
|         heim_base_once_f(&__init, &__cipher,                            \
 | |
|                          pkcs11_hcrypto_##name##_init_once);            \
 | |
|                                                                         \
 | |
|         return __cipher;                                                \
 | |
|     }
 | |
| 
 | |
| #define PKCS11_MD_ALGORITHM(name, mechanismType, hash_size, block_size) \
 | |
|                                                                         \
 | |
|     static int p11_##name##_init(EVP_MD_CTX *ctx)                       \
 | |
|     {                                                                   \
 | |
|         return p11_md_hash_init(mechanismType, ctx);                    \
 | |
|     }                                                                   \
 | |
|                                                                         \
 | |
|     const EVP_MD *                                                      \
 | |
|     hc_EVP_pkcs11_##name(void)                                          \
 | |
|     {                                                                   \
 | |
|         static struct hc_evp_md name = {                                \
 | |
|             hash_size,                                                  \
 | |
|             block_size,                                                 \
 | |
|             sizeof(struct pkcs11_md_ctx),                               \
 | |
|             p11_##name##_init,                                          \
 | |
|             p11_md_update,                                              \
 | |
|             p11_md_final,                                               \
 | |
|             p11_md_cleanup                                              \
 | |
|         };                                                              \
 | |
|                                                                         \
 | |
|         if (p11_mech_available_p(mechanismType, CKF_DIGEST))            \
 | |
|             return &name;                                               \
 | |
|         else                                                            \
 | |
|             return NULL;                                                \
 | |
|     }                                                                   \
 | |
|                                                                         \
 | |
|     static void                                                         \
 | |
|     pkcs11_hcrypto_##name##_init_once(void *context)                    \
 | |
|     {                                                                   \
 | |
|         const EVP_MD *md;                                               \
 | |
|                                                                         \
 | |
|         md = hc_EVP_pkcs11_ ##name();                                   \
 | |
|         if (md == NULL && HCRYPTO_FALLBACK)                             \
 | |
|             md = hc_EVP_hcrypto_ ##name();                              \
 | |
|                                                                         \
 | |
|         *((const EVP_MD **)context) = md;                               \
 | |
|     }                                                                   \
 | |
|                                                                         \
 | |
|     const EVP_MD *                                                      \
 | |
|     hc_EVP_pkcs11_hcrypto_##name(void)                                  \
 | |
|     {                                                                   \
 | |
|         static const EVP_MD *__md;                                      \
 | |
|         static heim_base_once_t __init = HEIM_BASE_ONCE_INIT;           \
 | |
|                                                                         \
 | |
|         heim_base_once_f(&__init, &__md,                                \
 | |
|                          pkcs11_hcrypto_##name##_init_once);            \
 | |
|                                                                         \
 | |
|         return __md;                                                    \
 | |
|     }
 | |
| 
 | |
| #define PKCS11_MD_ALGORITHM_UNAVAILABLE(name)                           \
 | |
|                                                                         \
 | |
|     const EVP_MD *                                                      \
 | |
|     hc_EVP_pkcs11_##name(void)                                          \
 | |
|     {                                                                   \
 | |
|         return NULL;                                                    \
 | |
|     }                                                                   \
 | |
|                                                                         \
 | |
|     const EVP_MD *                                                      \
 | |
|     hc_EVP_pkcs11_hcrypto_##name(void)                                  \
 | |
|     {                                                                   \
 | |
|         return hc_EVP_hcrypto_ ##name();                                \
 | |
|     }
 | |
| 
 | |
| /**
 | |
|  * The triple DES cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the DES-EDE3-CBC EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(des_ede3_cbc,
 | |
|                         CKM_DES3_CBC,
 | |
|                         8,
 | |
|                         24,
 | |
|                         8,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The DES cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the DES-CBC EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(des_cbc,
 | |
|                         CKM_DES_CBC,
 | |
|                         8,
 | |
|                         8,
 | |
|                         8,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The AES-128 cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the AES-128-CBC EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(aes_128_cbc,
 | |
|                         CKM_AES_CBC,
 | |
|                         16,
 | |
|                         16,
 | |
|                         16,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The AES-192 cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the AES-192-CBC EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(aes_192_cbc,
 | |
|                         CKM_AES_CBC,
 | |
|                         16,
 | |
|                         24,
 | |
|                         16,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The AES-256 cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the AES-256-CBC EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(aes_256_cbc,
 | |
|                         CKM_AES_CBC,
 | |
|                         16,
 | |
|                         32,
 | |
|                         16,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The AES-128 CFB8 cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the AES-128-CFB8 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(aes_128_cfb8,
 | |
|                         CKM_AES_CFB8,
 | |
|                         16,
 | |
|                         16,
 | |
|                         16,
 | |
|                         EVP_CIPH_CFB8_MODE)
 | |
| 
 | |
| /**
 | |
|  * The AES-192 CFB8 cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the AES-192-CFB8 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(aes_192_cfb8,
 | |
|                         CKM_AES_CFB8,
 | |
|                         16,
 | |
|                         24,
 | |
|                         16,
 | |
|                         EVP_CIPH_CFB8_MODE)
 | |
| 
 | |
| /**
 | |
|  * The AES-256 CFB8 cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the AES-256-CFB8 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(aes_256_cfb8,
 | |
|                         CKM_AES_CFB8,
 | |
|                         16,
 | |
|                         32,
 | |
|                         16,
 | |
|                         EVP_CIPH_CFB8_MODE)
 | |
| 
 | |
| /**
 | |
|  * The RC2 cipher type - PKCS#11
 | |
|  *
 | |
|  * @return the RC2 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(rc2_cbc,
 | |
|                         CKM_RC2_CBC,
 | |
|                         8,
 | |
|                         16,
 | |
|                         8,
 | |
|                         EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH)
 | |
| 
 | |
| /**
 | |
|  * The RC2-40 cipher type - PKCS#11
 | |
|  *
 | |
|  * @return the RC2-40 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(rc2_40_cbc,
 | |
|                         CKM_RC2_CBC,
 | |
|                         8,
 | |
|                         5,
 | |
|                         8,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The RC2-64 cipher type - PKCS#11
 | |
|  *
 | |
|  * @return the RC2-64 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(rc2_64_cbc,
 | |
|                         CKM_RC2_CBC,
 | |
|                         8,
 | |
|                         8,
 | |
|                         8,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The Camellia-128 cipher type - PKCS#11
 | |
|  *
 | |
|  * @return the Camellia-128 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(camellia_128_cbc,
 | |
|                         CKM_CAMELLIA_CBC,
 | |
|                         16,
 | |
|                         16,
 | |
|                         16,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The Camellia-198 cipher type - PKCS#11
 | |
|  *
 | |
|  * @return the Camellia-198 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(camellia_192_cbc,
 | |
|                         CKM_CAMELLIA_CBC,
 | |
|                         16,
 | |
|                         24,
 | |
|                         16,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The Camellia-256 cipher type - PKCS#11
 | |
|  *
 | |
|  * @return the Camellia-256 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(camellia_256_cbc,
 | |
|                         CKM_CAMELLIA_CBC,
 | |
|                         16,
 | |
|                         32,
 | |
|                         16,
 | |
|                         EVP_CIPH_CBC_MODE)
 | |
| 
 | |
| /**
 | |
|  * The RC4 cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the RC4 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(rc4,
 | |
|                         CKM_RC4,
 | |
|                         1,
 | |
|                         16,
 | |
|                         0,
 | |
|                         EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH)
 | |
| 
 | |
| /**
 | |
|  * The RC4-40 cipher type (PKCS#11 provider)
 | |
|  *
 | |
|  * @return the RC4 EVP_CIPHER pointer.
 | |
|  *
 | |
|  * @ingroup hcrypto_evp
 | |
|  */
 | |
| 
 | |
| PKCS11_CIPHER_ALGORITHM(rc4_40,
 | |
|                         CKM_RC4,
 | |
|                         1,
 | |
|                         5,
 | |
|                         0,
 | |
|                         EVP_CIPH_STREAM_CIPHER | EVP_CIPH_VARIABLE_LENGTH)
 | |
| 
 | |
| PKCS11_MD_ALGORITHM(md2,    CKM_MD2,    16, 16)
 | |
| #ifdef CKM_MD4 /* non-standard extension */
 | |
| PKCS11_MD_ALGORITHM(md4,    CKM_MD4,    16, 64)
 | |
| #else
 | |
| PKCS11_MD_ALGORITHM_UNAVAILABLE(md4)
 | |
| #endif
 | |
| PKCS11_MD_ALGORITHM(md5,    CKM_MD5,    16, 64)
 | |
| PKCS11_MD_ALGORITHM(sha1,   CKM_SHA_1,  20, 64)
 | |
| PKCS11_MD_ALGORITHM(sha256, CKM_SHA256, 32, 64)
 | |
| PKCS11_MD_ALGORITHM(sha384, CKM_SHA384, 48, 128)
 | |
| PKCS11_MD_ALGORITHM(sha512, CKM_SHA512, 64, 128)
 |