/* * COPYRIGHT (c) International Business Machines Corp. 2001-2017 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ /* Modified for S390 by Robert Burroughs */ #include #include // for memcmp() et al #include #include #include // for dlopen() #include #ifndef NOAES #include #endif #include "pkcs11types.h" #include "p11util.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "trace.h" #include #ifndef EC_DH #define NO_EC #warning "Your Libica does not provide ECC support, use Libica 3.3.0 or newer for ECC." #endif #include "tok_specific.h" #include "tok_struct.h" #ifndef NO_EC #include "ec_defs.h" #include "openssl/obj_mac.h" #include #endif #include #define ICA_MAX_MECH_LIST_ENTRIES 98 typedef struct { ica_adapter_handle_t adapter_handle; int ica_ec_support_available; MECH_LIST_ELEMENT mech_list[ICA_MAX_MECH_LIST_ENTRIES]; CK_ULONG mech_list_len; } ica_private_data_t; // Linux really does not need these so we just dummy them up // so the common code across platforms is usable... #define KEYTYPE_MODEXPO 1 #define KEYTYPE_PKCSCRT 2 #define MAX_GENERIC_KEY_SIZE 256 const char manuf[] = "IBM"; const char model[] = "ICA"; const char descr[] = "IBM ICA token"; const char label[] = "icatok"; static pthread_mutex_t rngmtx = PTHREAD_MUTEX_INITIALIZER; #define LIBICA_SHARED_LIB "libica.so.3" #define BIND(dso, sym) do { \ if (p_##sym == NULL) \ *(void **)(&p_##sym) = dlsym(dso, #sym); \ } while (0) #ifndef NO_EC typedef ICA_EC_KEY *(*ica_ec_key_new_t) (unsigned int nid, unsigned int *privlen); typedef int (*ica_ec_key_init_t) (const unsigned char *X, const unsigned char *Y, const unsigned char *D, ICA_EC_KEY *key); typedef int (*ica_ec_key_generate_t) (ica_adapter_handle_t adapter_handle, ICA_EC_KEY *key); typedef int (*ica_ecdh_derive_secret_t) (ica_adapter_handle_t adapter_handle, const ICA_EC_KEY *privkey_A, const ICA_EC_KEY *pubkey_B, unsigned char *z, unsigned int z_length); typedef int (*ica_ecdsa_sign_t) (ica_adapter_handle_t adapter_handle, const ICA_EC_KEY *privkey, const unsigned char *hash, unsigned int hash_length, unsigned char *signature, unsigned int signature_length); typedef int (*ica_ecdsa_verify_t) (ica_adapter_handle_t adapter_handle, const ICA_EC_KEY *pubkey, const unsigned char *hash, unsigned int hash_length, const unsigned char *signature, unsigned int signature_length); typedef int (*ica_ec_key_get_public_key_t) (ICA_EC_KEY *key, unsigned char *q, unsigned int *q_len); typedef int (*ica_ec_key_get_private_key_t) (ICA_EC_KEY *key, unsigned char *d, unsigned int *d_len); typedef void (*ica_ec_key_free_t) (ICA_EC_KEY *key); static ica_ec_key_new_t p_ica_ec_key_new; static ica_ec_key_init_t p_ica_ec_key_init; static ica_ec_key_generate_t p_ica_ec_key_generate; static ica_ecdh_derive_secret_t p_ica_ecdh_derive_secret; static ica_ecdsa_sign_t p_ica_ecdsa_sign; static ica_ecdsa_verify_t p_ica_ecdsa_verify; static ica_ec_key_get_public_key_t p_ica_ec_key_get_public_key; static ica_ec_key_get_private_key_t p_ica_ec_key_get_private_key; static ica_ec_key_free_t p_ica_ec_key_free; static CK_RV mech_list_ica_initialize(STDLL_TokData_t *tokdata); #define ICATOK_EC_MAX_D_LEN 66 /* secp521 */ #define ICATOK_EC_MAX_Q_LEN (2*ICATOK_EC_MAX_D_LEN) #define ICATOK_EC_MAX_SIG_LEN ICATOK_EC_MAX_Q_LEN #define ICATOK_EC_MAX_Z_LEN ICATOK_EC_MAX_D_LEN static CK_RV ecc_support_in_libica_available(void) { if (p_ica_ec_key_new != NULL && p_ica_ec_key_init != NULL && p_ica_ec_key_generate != NULL && p_ica_ecdh_derive_secret != NULL && p_ica_ecdsa_sign != NULL && p_ica_ecdsa_verify != NULL && p_ica_ec_key_get_public_key != NULL && p_ica_ec_key_get_private_key != NULL && p_ica_ec_key_free != NULL) return 1; return 0; } #endif #ifdef SHA512_224 typedef unsigned int (*ica_sha512_224_t)(unsigned int message_part, unsigned int input_length, unsigned char *input_data, sha512_context_t *sha_context, unsigned char *output_data); static ica_sha512_224_t p_ica_sha512_224; #endif #ifdef SHA512_256 typedef unsigned int (*ica_sha512_256_t)(unsigned int message_part, unsigned int input_length, unsigned char *input_data, sha512_context_t *sha_context, unsigned char *output_data); static ica_sha512_256_t p_ica_sha512_256; #endif #ifdef SHA3_224 typedef unsigned int (*ica_sha3_224_t)(unsigned int message_part, unsigned int input_length, unsigned char *input_data, sha3_224_context_t *sha_context, unsigned char *output_data); static ica_sha3_224_t p_ica_sha3_224; #endif #ifdef SHA3_256 typedef unsigned int (*ica_sha3_256_t)(unsigned int message_part, unsigned int input_length, unsigned char *input_data, sha3_256_context_t *sha_context, unsigned char *output_data); static ica_sha3_256_t p_ica_sha3_256; #endif #ifdef SHA3_384 typedef unsigned int (*ica_sha3_384_t)(unsigned int message_part, unsigned int input_length, unsigned char *input_data, sha3_384_context_t *sha_context, unsigned char *output_data); static ica_sha3_384_t p_ica_sha3_384; #endif #ifdef SHA3_512 typedef unsigned int (*ica_sha3_512_t)(unsigned int message_part, unsigned int input_length, unsigned char *input_data, sha3_512_context_t *sha_context, unsigned char *output_data); static ica_sha3_512_t p_ica_sha3_512; #endif static CK_RV load_libica(void) { void *ibmca_dso = NULL; /* Load libica */ ibmca_dso = dlopen(LIBICA_SHARED_LIB, RTLD_NOW); if (ibmca_dso == NULL) { TRACE_ERROR("%s: dlopen(%s) failed\n", __func__, LIBICA_SHARED_LIB); return CKR_FUNCTION_FAILED; } #ifndef NO_EC /* Try to resolve all needed functions for ecc support */ BIND(ibmca_dso, ica_ec_key_new); BIND(ibmca_dso, ica_ec_key_init); BIND(ibmca_dso, ica_ec_key_generate); BIND(ibmca_dso, ica_ecdh_derive_secret); BIND(ibmca_dso, ica_ecdsa_sign); BIND(ibmca_dso, ica_ecdsa_verify); BIND(ibmca_dso, ica_ec_key_get_public_key); BIND(ibmca_dso, ica_ec_key_get_private_key); BIND(ibmca_dso, ica_ec_key_free); #endif #ifdef SHA512_224 BIND(ibmca_dso, ica_sha512_224); #endif #ifdef SHA512_256 BIND(ibmca_dso, ica_sha512_256); #endif #ifdef SHA3_224 BIND(ibmca_dso, ica_sha3_224); #endif #ifdef SHA3_256 BIND(ibmca_dso, ica_sha3_256); #endif #ifdef SHA3_384 BIND(ibmca_dso, ica_sha3_384); #endif #ifdef SHA3_512 BIND(ibmca_dso, ica_sha3_512); #endif return CKR_OK; } CK_RV token_specific_rng(STDLL_TokData_t *tokdata, CK_BYTE *output, CK_ULONG bytes) { unsigned int rc; UNUSED(tokdata); pthread_mutex_lock(&rngmtx); rc = ica_random_number_generate((unsigned int) bytes, output); if (rc != 0) { pthread_mutex_unlock(&rngmtx); return CKR_GENERAL_ERROR; /* report error */ } pthread_mutex_unlock(&rngmtx); return CKR_OK; } CK_RV token_specific_init(STDLL_TokData_t *tokdata, CK_SLOT_ID SlotNumber, char *conf_name) { ica_private_data_t *ica_data; CK_ULONG rc = CKR_OK; UNUSED(conf_name); ica_data = (ica_private_data_t *)calloc(1, sizeof(ica_private_data_t)); tokdata->private_data = ica_data; rc = load_libica(); if (rc != CKR_OK) goto out; #ifndef NO_EC ica_data->ica_ec_support_available = ecc_support_in_libica_available(); #endif rc = mech_list_ica_initialize(tokdata); if (rc != CKR_OK) { TRACE_ERROR("mech_list_ica_initialize failed\n"); goto out; } tokdata->mech_list = ica_data->mech_list; tokdata->mech_list_len = ica_data->mech_list_len; TRACE_INFO("ica %s slot=%lu running\n", __func__, SlotNumber); rc = ica_open_adapter(&ica_data->adapter_handle); if (rc != 0) { TRACE_ERROR("ica_open_adapter failed\n"); goto out; } out: if (rc != CKR_OK) { free(ica_data); tokdata->private_data = NULL; } return rc; } CK_RV token_specific_final(STDLL_TokData_t *tokdata, CK_BBOOL in_fork_initializer) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; UNUSED(in_fork_initializer); TRACE_INFO("ica %s running\n", __func__); ica_close_adapter(ica_data->adapter_handle); free(ica_data); tokdata->private_data = NULL; return CKR_OK; } // count_ones_in_byte: for use in adjust_des_key_parity_bits below static CK_BYTE count_ones_in_byte(CK_BYTE byte) { CK_BYTE and_mask, // bit selector number_of_ones = 0; for (and_mask = 1; and_mask != 0; and_mask <<= 1) // for each bit, if (byte & and_mask) // if it's a one, ++number_of_ones; // count it return number_of_ones; } #define EVEN_PARITY TRUE #define ODD_PARITY FALSE // adjust_des_key_parity_bits: to conform to NIST spec for DES and 3DES keys static void adjust_des_key_parity_bits(CK_BYTE *des_key, CK_ULONG key_size, CK_BBOOL parity) { CK_ULONG i; for (i = 0; i < key_size; i++) // look at each byte in the key { if ((count_ones_in_byte(des_key[i]) % 2) ^ (parity == ODD_PARITY)) { // if parity for this byte isn't what it should be, // flip the parity (least significant) bit des_key[i] ^= 1; } } } CK_RV token_specific_des_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **des_key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { *des_key = malloc(keysize); if (*des_key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; // Nothing different to do for DES or TDES here as this is just // random data... Validation handles the rest // Only check for weak keys when DES. if (keysize == (3 * DES_KEY_SIZE)) { rng_generate(tokdata, *des_key, keysize); adjust_des_key_parity_bits(*des_key, keysize, ODD_PARITY); } else { do { rng_generate(tokdata, *des_key, keysize); adjust_des_key_parity_bits(*des_key, keysize, ODD_PARITY); } while (des_check_weak_key(*des_key) == TRUE); } // we really need to validate the key for parity etc... // we should do that here... The caller validates the single des keys // against the known and suspected poor keys..<< return CKR_OK; } CK_RV token_specific_des_ecb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE encrypt) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); /* * checks for input and output data length and block sizes * are already being carried out in mech_des.c * so we skip those */ if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (encrypt) { rc = ica_des_ecb(in_data, out_data, in_data_len, attr->pValue, ICA_ENCRYPT); } else { rc = ica_des_ecb(in_data, out_data, in_data_len, attr->pValue, ICA_DECRYPT); } if (rc != 0) { rc = CKR_FUNCTION_FAILED; TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); } else { *out_data_len = in_data_len; rc = CKR_OK; } return rc; } CK_RV token_specific_des_cbc(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); /* * checks for input and output data length and block sizes * are already being carried out in mech_des.c * so we skip those */ // get the key value if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (encrypt) { rc = ica_des_cbc(in_data, out_data, in_data_len, attr->pValue, init_v, ICA_ENCRYPT); } else { rc = ica_des_cbc(in_data, out_data, in_data_len, attr->pValue, init_v, ICA_DECRYPT); } if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } else { *out_data_len = in_data_len; rc = CKR_OK; } return rc; } CK_RV token_specific_tdes_ecb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE encrypt) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE keytype; CK_BYTE key_value[3 * DES_KEY_SIZE]; UNUSED(tokdata); /* * checks for input and output data length and block sizes * are already being carried out in mech_des3.c * so we skip those */ // get the key type rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); if (rc == FALSE) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return CKR_FUNCTION_FAILED; } keytype = *(CK_KEY_TYPE *) attr->pValue; // get the key value if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (keytype == CKK_DES2) { memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); } else { memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); } if (encrypt) { rc = ica_3des_ecb(in_data, out_data, in_data_len, key_value, ICA_ENCRYPT); } else { rc = ica_3des_ecb(in_data, out_data, in_data_len, key_value, ICA_DECRYPT); } if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } else { *out_data_len = in_data_len; rc = CKR_OK; } return rc; } CK_RV token_specific_tdes_cbc(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE keytype; CK_BYTE key_value[3 * DES_KEY_SIZE]; UNUSED(tokdata); /* * checks for input and output data length and block sizes * are already being carried out in mech_des3.c * so we skip those */ // get the key type rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); if (rc == FALSE) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return CKR_FUNCTION_FAILED; } keytype = *(CK_KEY_TYPE *) attr->pValue; // get the key value if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (keytype == CKK_DES2) { memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); } else { memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); } if (encrypt) { rc = ica_3des_cbc(in_data, out_data, in_data_len, key_value, init_v, ICA_ENCRYPT); } else { rc = ica_3des_cbc(in_data, out_data, in_data_len, key_value, init_v, ICA_DECRYPT); } if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } else { *out_data_len = in_data_len; rc = CKR_OK; } return rc; } /* * * 0 Use the decrypt function. * 1 Use the encrypt function. */ CK_RV token_specific_tdes_ofb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_BYTE *out_data, CK_ULONG data_len, OBJECT *key, CK_BYTE *iv, uint_32 direction) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } rc = ica_3des_ofb(in_data, out_data, (unsigned int) data_len, (unsigned char *) attr->pValue, (unsigned char *) iv, direction); if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } return rc; } /* * 0 Use the decrypt function. * 1 Use the encrypt function. */ CK_RV token_specific_tdes_cfb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_BYTE *out_data, CK_ULONG data_len, OBJECT *key, CK_BYTE *iv, uint_32 cfb_len, uint_32 direction) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } rc = ica_3des_cfb(in_data, out_data, (unsigned int) data_len, (unsigned char *) attr->pValue, (unsigned char *) iv, cfb_len, direction); if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } return rc; } CK_RV token_specific_tdes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE keytype; CK_BYTE key_value[3 * DES_KEY_SIZE]; UNUSED(tokdata); // get the key type rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); if (rc == FALSE) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return CKR_FUNCTION_FAILED; } keytype = *(CK_KEY_TYPE *) attr->pValue; // get the key value if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (keytype == CKK_DES2) { memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); } else { memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); } rc = ica_3des_cmac_intermediate(message, (unsigned long) message_len, (unsigned char *) key_value, mac); if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } return rc; } CK_RV token_specific_tdes_cmac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac, CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *ctx) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; CK_KEY_TYPE keytype; CK_BYTE key_value[3 * DES_KEY_SIZE]; UNUSED(tokdata); UNUSED(ctx); // get the key type rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr); if (rc == FALSE) { TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n"); return CKR_FUNCTION_FAILED; } keytype = *(CK_KEY_TYPE *) attr->pValue; // get the key value if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (keytype == CKK_DES2) { memcpy(key_value, attr->pValue, 2 * DES_KEY_SIZE); memcpy(key_value + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE); } else { memcpy(key_value, attr->pValue, 3 * DES_KEY_SIZE); } if (first && last) { rc = ica_3des_cmac(message, (unsigned long) message_len, mac, DES_BLOCK_SIZE, key_value, ICA_ENCRYPT); } else if (!last) { rc = ica_3des_cmac_intermediate(message, (unsigned long) message_len, key_value, mac); } else { rc = ica_3des_cmac_last(message, (unsigned long) message_len, mac, DES_BLOCK_SIZE, key_value, mac, ICA_ENCRYPT); } if (rc != 0) { TRACE_ERROR("%s: rc: %lu\n", ock_err(ERR_FUNCTION_FAILED), rc); rc = CKR_FUNCTION_FAILED; } return rc; } /* * Init SHA data structures */ CK_RV token_specific_sha_init(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_MECHANISM *mech) { unsigned int ctxsize, devctxsize; struct oc_sha_ctx *sc; UNUSED(tokdata); ctxsize = (sizeof(struct oc_sha_ctx) + 0x000F) & ~0x000F; switch (mech->mechanism) { case CKM_SHA_1: devctxsize = sizeof(sha_context_t); break; case CKM_SHA224: case CKM_SHA256: devctxsize = sizeof(sha256_context_t); break; case CKM_SHA384: case CKM_SHA512: #ifdef SHA512_224 case CKM_SHA512_224: #endif #ifdef SHA512_256 case CKM_SHA512_256: #endif devctxsize = sizeof(sha512_context_t); break; #ifdef SHA3_224 case CKM_IBM_SHA3_224: devctxsize = sizeof(sha3_224_context_t); break; #endif #ifdef SHA3_256 case CKM_IBM_SHA3_256: devctxsize = sizeof(sha3_256_context_t); break; #endif #ifdef SHA3_384 case CKM_IBM_SHA3_384: devctxsize = sizeof(sha3_384_context_t); break; #endif #ifdef SHA3_512 case CKM_IBM_SHA3_512: devctxsize = sizeof(sha3_512_context_t); break; #endif default: return CKR_MECHANISM_INVALID; } /* (re)alloc ctx in one memory area */ if (ctx->context) free(ctx->context); ctx->context_len = 0; ctx->context = malloc(ctxsize + devctxsize); if (ctx->context == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } memset(ctx->context, 0, ctxsize + devctxsize); ctx->context_len = ctxsize + devctxsize; sc = (struct oc_sha_ctx *) ctx->context; sc->dev_ctx_offs = ctxsize; sc->message_part = SHA_MSG_PART_ONLY; switch (mech->mechanism) { case CKM_SHA_1: sc->hash_len = SHA1_HASH_SIZE; sc->hash_blksize = SHA1_BLOCK_SIZE; break; case CKM_SHA224: sc->hash_len = SHA224_HASH_SIZE; sc->hash_blksize = SHA224_BLOCK_SIZE; break; case CKM_SHA256: sc->hash_len = SHA256_HASH_SIZE; sc->hash_blksize = SHA256_BLOCK_SIZE; break; case CKM_SHA384: sc->hash_len = SHA384_HASH_SIZE; sc->hash_blksize = SHA384_BLOCK_SIZE; break; case CKM_SHA512: sc->hash_len = SHA512_HASH_SIZE; sc->hash_blksize = SHA512_BLOCK_SIZE; break; #ifdef SHA512_224 case CKM_SHA512_224: sc->hash_len = SHA224_HASH_SIZE; sc->hash_blksize = SHA512_BLOCK_SIZE; break; #endif #ifdef SHA512_256 case CKM_SHA512_256: sc->hash_len = SHA256_HASH_SIZE; sc->hash_blksize = SHA512_BLOCK_SIZE; break; #endif #ifdef SHA3_224 case CKM_IBM_SHA3_224: sc->hash_len = SHA3_224_HASH_SIZE; sc->hash_blksize = SHA3_224_BLOCK_SIZE; break; #endif #ifdef SHA3_256 case CKM_IBM_SHA3_256: sc->hash_len = SHA3_256_HASH_SIZE; sc->hash_blksize = SHA3_256_BLOCK_SIZE; break; #endif #ifdef SHA3_384 case CKM_IBM_SHA3_384: sc->hash_len = SHA3_384_HASH_SIZE; sc->hash_blksize = SHA3_384_BLOCK_SIZE; break; #endif #ifdef SHA3_512 case CKM_IBM_SHA3_512: sc->hash_len = SHA3_512_HASH_SIZE; sc->hash_blksize = SHA3_512_BLOCK_SIZE; break; #endif } return CKR_OK; } CK_RV token_specific_sha(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len) { int rc; CK_RV rv = CKR_OK; struct oc_sha_ctx *sc; void *dev_ctx; UNUSED(tokdata); if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; if (!in_data || !out_data) return CKR_ARGUMENTS_BAD; sc = (struct oc_sha_ctx *) ctx->context; dev_ctx = ((CK_BYTE *) sc) + sc->dev_ctx_offs; if (*out_data_len < sc->hash_len) return CKR_BUFFER_TOO_SMALL; sc->message_part = SHA_MSG_PART_ONLY; switch (ctx->mech.mechanism) { case CKM_SHA_1: { sha_context_t *ica_sha_ctx = (sha_context_t *) dev_ctx; rc = ica_sha1(sc->message_part, in_data_len, in_data, ica_sha_ctx, sc->hash); break; } case CKM_SHA224: { sha256_context_t *ica_sha2_ctx = (sha256_context_t *) dev_ctx; rc = ica_sha224(sc->message_part, in_data_len, in_data, ica_sha2_ctx, sc->hash); break; } case CKM_SHA256: { sha256_context_t *ica_sha2_ctx = (sha256_context_t *) dev_ctx; rc = ica_sha256(sc->message_part, in_data_len, in_data, ica_sha2_ctx, sc->hash); break; } case CKM_SHA384: { sha512_context_t *ica_sha3_ctx = (sha512_context_t *) dev_ctx; rc = ica_sha384(sc->message_part, in_data_len, in_data, ica_sha3_ctx, sc->hash); break; } case CKM_SHA512: { sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; rc = ica_sha512(sc->message_part, in_data_len, in_data, ica_sha5_ctx, sc->hash); break; } #ifdef SHA512_224 case CKM_SHA512_224: { sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; if (p_ica_sha512_224 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha512_224(sc->message_part, in_data_len, in_data, ica_sha5_ctx, sc->hash); break; } #endif #ifdef SHA512_256 case CKM_SHA512_256: { sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; if (p_ica_sha512_256 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha512_256(sc->message_part, in_data_len, in_data, ica_sha5_ctx, sc->hash); break; } #endif #ifdef SHA3_224 case CKM_IBM_SHA3_224: { sha3_224_context_t *ica_sha3_ctx = (sha3_224_context_t *) dev_ctx; if (p_ica_sha3_224 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha3_224(sc->message_part, in_data_len, in_data, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_256 case CKM_IBM_SHA3_256: { sha3_256_context_t *ica_sha3_ctx = (sha3_256_context_t *) dev_ctx; if (p_ica_sha3_256 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha3_256(sc->message_part, in_data_len, in_data, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_384 case CKM_IBM_SHA3_384: { sha3_384_context_t *ica_sha3_ctx = (sha3_384_context_t *) dev_ctx; if (p_ica_sha3_384 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha3_384(sc->message_part, in_data_len, in_data, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_512 case CKM_IBM_SHA3_512: { sha3_512_context_t *ica_sha3_ctx = (sha3_512_context_t *) dev_ctx; if (p_ica_sha3_512 == NULL) return CKR_MECHANISM_INVALID; rc = p_ica_sha3_512(sc->message_part, in_data_len, in_data, ica_sha3_ctx, sc->hash); break; } #endif default: return CKR_MECHANISM_INVALID; } if (rc == CKR_OK) { memcpy(out_data, sc->hash, sc->hash_len); *out_data_len = sc->hash_len; } else { rv = CKR_FUNCTION_FAILED; } return rv; } static CK_RV ica_sha_call(DIGEST_CONTEXT *ctx, CK_BYTE *data, CK_ULONG data_len) { struct oc_sha_ctx *sc = (struct oc_sha_ctx *) ctx->context; void *dev_ctx = ((CK_BYTE *) sc) + sc->dev_ctx_offs; CK_RV ret; switch (ctx->mech.mechanism) { case CKM_SHA_1: { sha_context_t *ica_sha_ctx = (sha_context_t *) dev_ctx; if (ica_sha_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = ica_sha1(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } case CKM_SHA224: { sha256_context_t *ica_sha_ctx = (sha256_context_t *) dev_ctx; if (ica_sha_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = ica_sha224(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } case CKM_SHA256: { sha256_context_t *ica_sha_ctx = (sha256_context_t *) dev_ctx; if (ica_sha_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = ica_sha256(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } case CKM_SHA384: { sha512_context_t *ica_sha_ctx = (sha512_context_t *) dev_ctx; if (ica_sha_ctx->runningLengthLow == 0 && ica_sha_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = ica_sha384(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } case CKM_SHA512: { sha512_context_t *ica_sha_ctx = (sha512_context_t *) dev_ctx; if (ica_sha_ctx->runningLengthLow == 0 && ica_sha_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = ica_sha512(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #ifdef SHA512_224 case CKM_SHA512_224: { sha512_context_t *ica_sha_ctx = (sha512_context_t *) dev_ctx; if (p_ica_sha512_224 == NULL) return CKR_MECHANISM_INVALID; if (ica_sha_ctx->runningLengthLow == 0 && ica_sha_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = p_ica_sha512_224(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #endif #ifdef SHA512_256 case CKM_SHA512_256: { sha512_context_t *ica_sha_ctx = (sha512_context_t *) dev_ctx; if (p_ica_sha512_256 == NULL) return CKR_MECHANISM_INVALID; if (ica_sha_ctx->runningLengthLow == 0 && ica_sha_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = p_ica_sha512_256(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #endif #ifdef SHA3_224 case CKM_IBM_SHA3_224: { sha3_224_context_t *ica_sha_ctx = (sha3_224_context_t *) dev_ctx; if (p_ica_sha3_224 == NULL) return CKR_MECHANISM_INVALID; if (ica_sha_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = p_ica_sha3_224(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #endif #ifdef SHA3_256 case CKM_IBM_SHA3_256: { sha3_256_context_t *ica_sha_ctx = (sha3_256_context_t *) dev_ctx; if (p_ica_sha3_256 == NULL) return CKR_MECHANISM_INVALID; if (ica_sha_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = p_ica_sha3_256(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #endif #ifdef SHA3_384 case CKM_IBM_SHA3_384: { sha3_384_context_t *ica_sha_ctx = (sha3_384_context_t *) dev_ctx; if (p_ica_sha3_384 == NULL) return CKR_MECHANISM_INVALID; if (ica_sha_ctx->runningLengthLow == 0 && ica_sha_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = p_ica_sha3_384(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #endif #ifdef SHA3_512 case CKM_IBM_SHA3_512: { sha3_512_context_t *ica_sha_ctx = (sha3_512_context_t *) dev_ctx; if (p_ica_sha3_512 == NULL) return CKR_MECHANISM_INVALID; if (ica_sha_ctx->runningLengthLow == 0 && ica_sha_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_FIRST; else sc->message_part = SHA_MSG_PART_MIDDLE; ret = p_ica_sha3_512(sc->message_part, data_len, data, ica_sha_ctx, sc->hash); break; } #endif default: return CKR_MECHANISM_INVALID; } return (ret ? CKR_FUNCTION_FAILED : CKR_OK); } CK_RV token_specific_sha_update(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len) { struct oc_sha_ctx *sc; int fill, len, rest, ret; UNUSED(tokdata); if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; if (!in_data_len) return CKR_OK; if (!in_data) return CKR_ARGUMENTS_BAD; sc = (struct oc_sha_ctx *) ctx->context; /* if less than blocksize, save to context buffer for next time */ if (sc->tail_len + in_data_len < sc->hash_blksize) { memcpy(sc->tail + sc->tail_len, in_data, in_data_len); sc->tail_len += in_data_len; return CKR_OK; } /* we have at least one block */ /* if some leftovers from the last update are available copy together one block into the tail buffer and hash it */ if (sc->tail_len) { fill = sc->hash_blksize - sc->tail_len; memcpy(sc->tail + sc->tail_len, in_data, fill); /* hash blksize bytes from the tail buffer */ ret = ica_sha_call(ctx, sc->tail, sc->hash_blksize); if (ret != CKR_OK) return ret; /* tail buffer is empty now */ sc->tail_len = 0; /* adjust input data pointer and input data len */ in_data += fill; in_data_len -= fill; /* if there is no more data to process, we are done */ if (!in_data_len) return CKR_OK; } /* The tail buffer is empty now, and in_data_len is > 0. * Calculate amount of remaining bytes... */ rest = in_data_len % sc->hash_blksize; /* and amount of bytes fitting into hash blocks */ len = in_data_len - rest; /* process the full hash blocks */ if (len > 0) { /* hash len bytes from input starting at the beginning */ ret = ica_sha_call(ctx, in_data, len); if (ret != CKR_OK) return ret; /* adjust input data pointer */ in_data += len; } /* Store remaining bytes into the empty tail buffer */ if (rest > 0) { memcpy(sc->tail, in_data, rest); sc->tail_len = rest; } return CKR_OK; } CK_RV token_specific_sha_final(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len) { int rc; CK_RV rv = CKR_OK; struct oc_sha_ctx *sc; void *dev_ctx; UNUSED(tokdata); if (!ctx || !ctx->context) return CKR_OPERATION_NOT_INITIALIZED; if (!out_data || !out_data_len) return CKR_ARGUMENTS_BAD; sc = (struct oc_sha_ctx *) ctx->context; dev_ctx = ((CK_BYTE *) sc) + sc->dev_ctx_offs; sc->message_part = SHA_MSG_PART_FINAL; if (*out_data_len < sc->hash_len) return CKR_BUFFER_TOO_SMALL; switch (ctx->mech.mechanism) { case CKM_SHA_1: { sha_context_t *ica_sha1_ctx = (sha_context_t *) dev_ctx; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha1_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = ica_sha1(sc->message_part, sc->tail_len, (unsigned char *) sc->tail, ica_sha1_ctx, sc->hash); break; } case CKM_SHA224: { sha256_context_t *ica_sha2_ctx = (sha256_context_t *) dev_ctx; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha2_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = ica_sha224(sc->message_part, sc->tail_len, sc->tail, ica_sha2_ctx, sc->hash); break; } case CKM_SHA256: { sha256_context_t *ica_sha2_ctx = (sha256_context_t *) dev_ctx; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha2_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = ica_sha256(sc->message_part, sc->tail_len, sc->tail, ica_sha2_ctx, sc->hash); break; } case CKM_SHA384: { sha512_context_t *ica_sha3_ctx = (sha512_context_t *) dev_ctx; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha3_ctx->runningLengthLow == 0 && ica_sha3_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = ica_sha384(sc->message_part, sc->tail_len, sc->tail, ica_sha3_ctx, sc->hash); break; } case CKM_SHA512: { sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha5_ctx->runningLengthLow == 0 && ica_sha5_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = ica_sha512(sc->message_part, sc->tail_len, sc->tail, ica_sha5_ctx, sc->hash); break; } #ifdef SHA512_224 case CKM_SHA512_224: { sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; if (p_ica_sha512_224 == NULL) return CKR_MECHANISM_INVALID; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha5_ctx->runningLengthLow == 0 && ica_sha5_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha512_224(sc->message_part, sc->tail_len, sc->tail, ica_sha5_ctx, sc->hash); break; } #endif #ifdef SHA512_256 case CKM_SHA512_256: { sha512_context_t *ica_sha5_ctx = (sha512_context_t *) dev_ctx; if (p_ica_sha512_256 == NULL) return CKR_MECHANISM_INVALID; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha5_ctx->runningLengthLow == 0 && ica_sha5_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha512_256(sc->message_part, sc->tail_len, sc->tail, ica_sha5_ctx, sc->hash); break; } #endif #ifdef SHA3_224 case CKM_IBM_SHA3_224: { sha3_224_context_t *ica_sha3_ctx = (sha3_224_context_t *) dev_ctx; if (p_ica_sha3_224 == NULL) return CKR_MECHANISM_INVALID; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha3_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha3_224(sc->message_part, sc->tail_len, sc->tail, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_256 case CKM_IBM_SHA3_256: { sha3_256_context_t *ica_sha3_ctx = (sha3_256_context_t *) dev_ctx; if (p_ica_sha3_256 == NULL) return CKR_MECHANISM_INVALID; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha3_ctx->runningLength == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha3_256(sc->message_part, sc->tail_len, sc->tail, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_384 case CKM_IBM_SHA3_384: { sha3_384_context_t *ica_sha3_ctx = (sha3_384_context_t *) dev_ctx; if (p_ica_sha3_384 == NULL) return CKR_MECHANISM_INVALID; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha3_ctx->runningLengthLow == 0 && ica_sha3_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha3_384(sc->message_part, sc->tail_len, sc->tail, ica_sha3_ctx, sc->hash); break; } #endif #ifdef SHA3_512 case CKM_IBM_SHA3_512: { sha3_512_context_t *ica_sha3_ctx = (sha3_512_context_t *) dev_ctx; if (p_ica_sha3_512 == NULL) return CKR_MECHANISM_INVALID; /* accommodate multi-part when input was so small * that we never got to call into libica until final */ if (ica_sha3_ctx->runningLengthLow == 0 && ica_sha3_ctx->runningLengthHigh == 0) sc->message_part = SHA_MSG_PART_ONLY; rc = p_ica_sha3_512(sc->message_part, sc->tail_len, sc->tail, ica_sha3_ctx, sc->hash); break; } #endif default: return CKR_MECHANISM_INVALID; } if (rc != CKR_OK) { rv = CKR_FUNCTION_FAILED; goto out; } memcpy(out_data, sc->hash, sc->hash_len); *out_data_len = sc->hash_len; out: return rv; } #ifndef LITE #define LITE #endif /* Creates a libICA modulus+exponent key representation using * PKCS#11 attributes */ static ica_rsa_key_mod_expo_t *rsa_convert_mod_expo_key(CK_ATTRIBUTE *modulus, CK_ATTRIBUTE *mod_bits, CK_ATTRIBUTE *exponent) { CK_BYTE *ptr = NULL; ica_rsa_key_mod_expo_t *modexpokey = NULL; /* We need at least the modulus and a (public|private) exponent */ if (!modulus || !exponent) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return NULL; } modexpokey = (ica_rsa_key_mod_expo_t *) calloc(1, sizeof(ica_rsa_key_mod_expo_t)); if (modexpokey == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err; } /* We can't rely solely on CKA_MODULUS_BITS here since Private Keys * using the modulus + private exponent representation may also go * through this path. Use modulus length in bytes as key_length if * no mod_bits is present */ if (mod_bits != NULL && mod_bits->ulValueLen && (*(CK_ULONG *) mod_bits->pValue)) { modexpokey->key_length = ((*(CK_ULONG *) mod_bits->pValue) + 7) / 8; } else { modexpokey->key_length = modulus->ulValueLen; } /* maybe I'm over-cautious here */ if ((modulus->ulValueLen > modexpokey->key_length) || (exponent->ulValueLen > modexpokey->key_length)) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); goto err; } modexpokey->modulus = (unsigned char *) calloc(1, modexpokey->key_length); if (modexpokey->modulus == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err; } /* right-justified fields */ ptr = modexpokey->modulus + modexpokey->key_length - modulus->ulValueLen; memcpy(ptr, modulus->pValue, modexpokey->key_length); modexpokey->exponent = (unsigned char *) calloc(1, modexpokey->key_length); if (modexpokey->exponent == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err; } ptr = modexpokey->exponent + modexpokey->key_length - exponent->ulValueLen; memcpy(ptr, exponent->pValue, exponent->ulValueLen); return modexpokey; err: free(modexpokey->modulus); free(modexpokey->exponent); free(modexpokey); return NULL; } /* Creates a libICA CRT key representation using * PKCS#11 attributes */ static ica_rsa_key_crt_t *rsa_convert_crt_key(CK_ATTRIBUTE *modulus, CK_ATTRIBUTE *prime1, CK_ATTRIBUTE *prime2, CK_ATTRIBUTE *exp1, CK_ATTRIBUTE *exp2, CK_ATTRIBUTE *coeff) { CK_BYTE *ptr = NULL; ica_rsa_key_crt_t *crtkey = NULL; /* All the above params are required to build a CRT key * that can be used by libICA. Private Keys with modulus * and private exponent should use rsa_convert_mod_expo_key() */ if (!modulus || !prime1 || !prime2 || !exp1 || !exp2 || !coeff) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return NULL; } else { crtkey = (ica_rsa_key_crt_t *) calloc(1, sizeof(ica_rsa_key_crt_t)); if (crtkey == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return NULL; } /* use modulus length in bytes as key_length */ crtkey->key_length = modulus->ulValueLen; /* buffers pointed by p, q, dp, dq and qInverse in struct * ica_rsa_key_crt_t must be of size key_legth/2 or larger. * p, dp and qInverse have an additional 8-byte padding. */ /* need to allocate the buffers. Also, all fields are * right-aligned, thus the use for ptr */ /* FIXME: if individual components lengths are bigger then * what we support in libICA then we're in trouble, * but maybe explicitly checking them is being over-zealous? */ if ((prime1->ulValueLen > (crtkey->key_length / 2)) || (prime2->ulValueLen > (crtkey->key_length / 2)) || (exp1->ulValueLen > (crtkey->key_length / 2)) || (exp2->ulValueLen > (crtkey->key_length / 2)) || (coeff->ulValueLen > (crtkey->key_length / 2))) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); goto err_crtkey; } crtkey->p = (unsigned char *) calloc(1, (crtkey->key_length / 2) + 8); if (crtkey->p == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->p + (crtkey->key_length / 2) + 8 - prime1->ulValueLen; memcpy(ptr, prime1->pValue, prime1->ulValueLen); crtkey->q = (unsigned char *) calloc(1, crtkey->key_length / 2); if (crtkey->q == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->q + (crtkey->key_length / 2) - prime2->ulValueLen; memcpy(ptr, prime2->pValue, prime2->ulValueLen); crtkey->dp = (unsigned char *) calloc(1, (crtkey->key_length / 2) + 8); if (crtkey->dp == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->dp + (crtkey->key_length / 2) + 8 - exp1->ulValueLen; memcpy(ptr, exp1->pValue, exp1->ulValueLen); crtkey->dq = (unsigned char *) calloc(1, crtkey->key_length / 2); if (crtkey->dq == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->dq + (crtkey->key_length / 2) - exp2->ulValueLen; memcpy(ptr, exp2->pValue, exp2->ulValueLen); crtkey->qInverse = (unsigned char *) calloc(1, (crtkey->key_length / 2) + 8); if (crtkey->qInverse == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto err_crtkey; } ptr = crtkey->qInverse + (crtkey->key_length / 2) + 8 - coeff->ulValueLen; memcpy(ptr, coeff->pValue, coeff->ulValueLen); return crtkey; } err_crtkey: free(crtkey->p); free(crtkey->q); free(crtkey->dp); free(crtkey->dq); free(crtkey->qInverse); free(crtkey); return NULL; } // static CK_RV os_specific_rsa_keygen(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_ATTRIBUTE *publ_exp = NULL; CK_ATTRIBUTE *attr = NULL; CK_BYTE *ptr = NULL; CK_ULONG mod_bits; CK_BBOOL flag; unsigned long tmpsize; CK_RV rc; ica_rsa_key_mod_expo_t *publKey = NULL; ica_rsa_key_crt_t *privKey = NULL; flag = template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr); if (!flag) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; // should never happen } mod_bits = *(CK_ULONG *) attr->pValue; flag = template_attribute_find(publ_tmpl, CKA_PUBLIC_EXPONENT, &publ_exp); if (!flag) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } // FIXME: is this check really necessary? if (mod_bits < 512 || mod_bits > 4096) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); return CKR_KEY_SIZE_RANGE; } /* libICA replicates the openSSL requirement that the public exponent * can't be larger than the size of an unsigned long */ if (publ_exp->ulValueLen > sizeof(unsigned long)) { TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE)); return CKR_KEY_SIZE_RANGE; } /* Build publKey: * The buffers in ica_rsa_key_mod_expo_t must be * allocated by the caller, with key_length size * use calloc() so that memory is zeroed (right alignment) */ publKey = (ica_rsa_key_mod_expo_t *) calloc(1, sizeof(ica_rsa_key_mod_expo_t)); if (publKey == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } /* key_length is in terms of bytes */ publKey->key_length = ((mod_bits + 7) / 8); publKey->modulus = (unsigned char *) calloc(1, publKey->key_length); if (publKey->modulus == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto pubkey_cleanup; } publKey->exponent = (unsigned char *) calloc(1, publKey->key_length); if (publKey->exponent == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto pubkey_cleanup; } /* Use the provided public exponent: * all fields must be right-aligned, so make * sure we only use the rightmost part */ /* We know the pub_exp attribute has it's value in BIG ENDIAN * * byte order, and we're assuming we're on s390(x) which is also * * BIG ENDIAN, so no byte swapping required. * * FIXME: Will need to fix that if porting for little endian */ ptr = publKey->exponent + publKey->key_length - publ_exp->ulValueLen; memcpy(ptr, publ_exp->pValue, publ_exp->ulValueLen); /* If the public exponent is zero, libica will generate a random one * * If it is an even number, then we have a problem. Use ptr to cast * * to unsigned int and check */ ptr = publKey->exponent + publKey->key_length - sizeof(unsigned long); if (*((unsigned long *) ptr) != 0 && *((unsigned long *) ptr) % 2 == 0) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCONSISTENT)); return CKR_TEMPLATE_INCONSISTENT; } /* Build privKey: * buffers pointed by p, q, dp, dq and qInverse in struct * ica_rsa_key_crt_t must be of size key_legth/2 or larger. * p, dp and qInverse have an additional 8-byte padding */ privKey = (ica_rsa_key_crt_t *) calloc(1, sizeof(ica_rsa_key_crt_t)); if (privKey == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto pubkey_cleanup; } /* modexpo and crt key lengths are always the same */ privKey->key_length = publKey->key_length; privKey->p = (unsigned char *) calloc(1, (privKey->key_length / 2) + 8); if (privKey->p == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto privkey_cleanup; } privKey->q = (unsigned char *) calloc(1, privKey->key_length / 2); if (privKey->q == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto privkey_cleanup; } privKey->dp = (unsigned char *) calloc(1, (privKey->key_length / 2) + 8); if (privKey->dp == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto privkey_cleanup; } privKey->dq = (unsigned char *) calloc(1, privKey->key_length / 2); if (privKey->dq == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto privkey_cleanup; } privKey->qInverse = (unsigned char *) calloc(1, (privKey->key_length / 2) + 8); if (privKey->qInverse == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto privkey_cleanup; } rc = ica_rsa_key_generate_crt(ica_data->adapter_handle, (unsigned int) mod_bits, publKey, privKey); if (rc) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto privkey_cleanup; } /* Build the PKCS#11 public key */ // modulus: n // tmpsize = publKey->key_length; ptr = p11_bigint_trim(publKey->modulus, &tmpsize); if (tmpsize != publKey->key_length) { /* This is bad */ TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto privkey_cleanup; } rc = build_attribute(CKA_MODULUS, ptr, tmpsize, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } template_update_attribute(publ_tmpl, attr); // public exponent // tmpsize = publKey->key_length; ptr = p11_bigint_trim(publKey->exponent, &tmpsize); rc = build_attribute(CKA_PUBLIC_EXPONENT, ptr, tmpsize, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build attribute failed\n"); goto privkey_cleanup; } template_update_attribute(publ_tmpl, attr); // local = TRUE // flag = TRUE; rc = build_attribute(CKA_LOCAL, &flag, sizeof(CK_BBOOL), &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } template_update_attribute(publ_tmpl, attr); // // now, do the private key // // public exponent: e // tmpsize = publKey->key_length; ptr = p11_bigint_trim(publKey->exponent, &tmpsize); rc = build_attribute(CKA_PUBLIC_EXPONENT, ptr, tmpsize, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } template_update_attribute(priv_tmpl, attr); // modulus: n // tmpsize = publKey->key_length; ptr = p11_bigint_trim(publKey->modulus, &tmpsize); if (tmpsize != publKey->key_length) { /* This is bad */ TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto privkey_cleanup; } rc = build_attribute(CKA_MODULUS, ptr, tmpsize, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } template_update_attribute(priv_tmpl, attr); // exponent 1: d mod(p-1) // tmpsize = privKey->key_length / 2; ptr = p11_bigint_trim(privKey->dp + 8, &tmpsize); rc = build_attribute(CKA_EXPONENT_1, ptr, tmpsize, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } template_update_attribute(priv_tmpl, attr); // exponent 2: d mod(q-1) // tmpsize = privKey->key_length / 2; ptr = p11_bigint_trim(privKey->dq, &tmpsize); rc = build_attribute(CKA_EXPONENT_2, ptr, tmpsize, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } template_update_attribute(priv_tmpl, attr); // prime #1: p // tmpsize = privKey->key_length / 2; ptr = p11_bigint_trim(privKey->p + 8, &tmpsize); rc = build_attribute(CKA_PRIME_1, ptr, tmpsize, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } template_update_attribute(priv_tmpl, attr); // prime #2: q // tmpsize = privKey->key_length / 2; ptr = p11_bigint_trim(privKey->q, &tmpsize); rc = build_attribute(CKA_PRIME_2, privKey->q, privKey->key_length / 2, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } template_update_attribute(priv_tmpl, attr); // CRT coefficient: q_inverse mod(p) // tmpsize = privKey->key_length / 2; ptr = p11_bigint_trim(privKey->qInverse + 8, &tmpsize); rc = build_attribute(CKA_COEFFICIENT, ptr, tmpsize, &attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto privkey_cleanup; } template_update_attribute(priv_tmpl, attr); privkey_cleanup: free(privKey->p); free(privKey->q); free(privKey->dp); free(privKey->dq); free(privKey->qInverse); free(privKey); pubkey_cleanup: free(publKey->modulus); free(publKey->exponent); free(publKey); return rc; } CK_RV token_specific_rsa_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { CK_RV rc; UNUSED(tokdata); rc = os_specific_rsa_keygen(tokdata, publ_tmpl, priv_tmpl); if (rc != CKR_OK) TRACE_DEVEL("os_specific_rsa_keygen failed\n"); return rc; } // // static CK_RV os_specific_rsa_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_ATTRIBUTE *modulus = NULL; CK_ATTRIBUTE *pub_exp = NULL; CK_ATTRIBUTE *mod_bits = NULL; ica_rsa_key_mod_expo_t *publKey = NULL; CK_RV rc; /* mech_sra.c:ckm_rsa_encrypt accepts only CKO_PUBLIC_KEY */ template_attribute_find(key_obj->template, CKA_MODULUS, &modulus); template_attribute_find(key_obj->template, CKA_MODULUS_BITS, &mod_bits); template_attribute_find(key_obj->template, CKA_PUBLIC_EXPONENT, &pub_exp); publKey = rsa_convert_mod_expo_key(modulus, mod_bits, pub_exp); if (publKey == NULL) { TRACE_ERROR("rsa_convert_mod_expo_key failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* in_data must be in big endian format. 'in_data' size in bits must not * exceed the bit length of the key, and size in bytes must * be of the same length of the key */ // FIXME: we're not cheking the size in bits of in_data - but how could we? if (publKey->key_length != in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); rc = CKR_DATA_LEN_RANGE; goto cleanup_pubkey; } rc = ica_rsa_mod_expo(ica_data->adapter_handle, in_data, publKey, out_data); if (rc != 0) { if (rc == EINVAL) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); rc = CKR_ARGUMENTS_BAD; } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } goto cleanup_pubkey; } rc = CKR_OK; cleanup_pubkey: free(publKey->modulus); free(publKey->exponent); free(publKey); done: return rc; } // // static CK_RV os_specific_rsa_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key_obj) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_ATTRIBUTE *modulus = NULL; CK_ATTRIBUTE *prime1 = NULL; CK_ATTRIBUTE *prime2 = NULL; CK_ATTRIBUTE *exp1 = NULL; CK_ATTRIBUTE *exp2 = NULL; CK_ATTRIBUTE *coeff = NULL; CK_ATTRIBUTE *priv_exp = NULL; ica_rsa_key_crt_t *crtKey = NULL; ica_rsa_key_mod_expo_t *modexpoKey = NULL; CK_RV rc; /* mech_rsa.c:ckm_rsa_decrypt accepts only CKO_PRIVATE_KEY, * but Private Key can have 2 representations (see PKCS#1): * - Modulus + private exponent * - p, q, dp, dq and qInv (CRT format) * The former should use ica_rsa_key_mod_expo_t and the latter * ica_rsa_key_crt_t. Detect what representation this * key_obj has and use the proper convert function */ template_attribute_find(key_obj->template, CKA_MODULUS, &modulus); template_attribute_find(key_obj->template, CKA_PRIVATE_EXPONENT, &priv_exp); template_attribute_find(key_obj->template, CKA_PRIME_1, &prime1); template_attribute_find(key_obj->template, CKA_PRIME_2, &prime2); template_attribute_find(key_obj->template, CKA_EXPONENT_1, &exp1); template_attribute_find(key_obj->template, CKA_EXPONENT_2, &exp2); template_attribute_find(key_obj->template, CKA_COEFFICIENT, &coeff); /* Need to check for CRT Key format *BEFORE* check for mod_expo key, * that's because opencryptoki *HAS* a CKA_PRIVATE_EXPONENT attribute * even in CRT keys (but with zero length) */ // FIXME: Checking for non-zero lengths anyway (might be overkill) if (modulus && modulus->ulValueLen && prime1 && prime1->ulValueLen && prime2 && prime2->ulValueLen && exp1 && exp1->ulValueLen && exp2 && exp2->ulValueLen && coeff && coeff->ulValueLen) { /* ica_rsa_key_crt_t representation */ crtKey = rsa_convert_crt_key(modulus, prime1, prime2, exp1, exp2, coeff); if (crtKey == NULL) { TRACE_ERROR("rsa_convert_crt_key failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* same check as above */ if (crtKey->key_length != in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; goto crt_cleanup; } rc = ica_rsa_crt(ica_data->adapter_handle, in_data, crtKey, out_data); if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } else { rc = CKR_OK; } goto crt_cleanup; } else if (modulus && modulus->ulValueLen && priv_exp && priv_exp->ulValueLen) { /* ica_rsa_key_mod_expo_t representation */ modexpoKey = rsa_convert_mod_expo_key(modulus, NULL, priv_exp); if (modexpoKey == NULL) { TRACE_ERROR("rsa_convert_mod_expo_key failed\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* in_data must be in big endian format. Size in bits must not * exceed the bit length of the key, and size in bytes must * be the same */ // FIXME: we're not cheking the size in bits of in_data // - but how could we? if (modexpoKey->key_length != in_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; goto modexpo_cleanup; } rc = ica_rsa_mod_expo(ica_data->adapter_handle, in_data, modexpoKey, out_data); if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } else { rc = CKR_OK; } goto modexpo_cleanup; } else { /* should never happen */ TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID)); rc = CKR_MECHANISM_PARAM_INVALID; goto done; } crt_cleanup: free(crtKey->p); free(crtKey->q); free(crtKey->dp); free(crtKey->dq); free(crtKey->qInverse); free(crtKey); goto done; modexpo_cleanup: free(modexpoKey->modulus); free(modexpoKey->exponent); free(modexpoKey); done: return rc; } CK_RV token_specific_rsa_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { CK_RV rc; CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return CKR_FUNCTION_FAILED; } else { modulus_bytes = attr->ulValueLen; } /* format the data */ rc = rsa_format_block(tokdata, in_data, in_data_len, clear, modulus_bytes, PKCS_BT_2); if (rc != CKR_OK) { TRACE_DEVEL("rsa_format_block failed\n"); return rc; } rc = os_specific_rsa_encrypt(tokdata, clear, modulus_bytes, cipher, key_obj); if (rc == CKR_OK) { memcpy(out_data, cipher, modulus_bytes); *out_data_len = modulus_bytes; } else { TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); } return rc; } CK_RV token_specific_rsa_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { CK_BYTE out[MAX_RSA_KEYLEN]; CK_RV rc; UNUSED(tokdata); rc = os_specific_rsa_decrypt(tokdata, in_data, in_data_len, out, key_obj); if (rc != CKR_OK) { TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); return rc; } rc = rsa_parse_block(out, in_data_len, out_data, out_data_len, PKCS_BT_2); if (rc != CKR_OK) { TRACE_DEVEL("rsa_parse_block failed\n"); return rc; } /* * For PKCS #1 v1.5 padding, out_data_len must be less * than in_data_len (which is modulus_bytes) - 11. */ if (*out_data_len > (in_data_len - 11)) { TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE)); rc = CKR_ENCRYPTED_DATA_LEN_RANGE; } return rc; } CK_RV token_specific_rsa_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { CK_ATTRIBUTE *attr = NULL; CK_BBOOL flag; CK_RV rc; CK_BYTE data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; UNUSED(tokdata); UNUSED(sess); flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return CKR_FUNCTION_FAILED; } else { modulus_bytes = attr->ulValueLen; } rc = rsa_format_block(tokdata, in_data, in_data_len, data, modulus_bytes, PKCS_BT_1); if (rc != CKR_OK) { TRACE_DEVEL("rsa_format_block failed\n"); return rc; } /* signing is a private key operation --> decrypt */ rc = os_specific_rsa_decrypt(tokdata, data, modulus_bytes, sig, key_obj); if (rc == CKR_OK) { memcpy(out_data, sig, modulus_bytes); *out_data_len = modulus_bytes; } else { TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); } return rc; } CK_RV token_specific_rsa_verify(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG sig_len, OBJECT *key_obj) { CK_RV rc; CK_BYTE out[MAX_RSA_KEYLEN], out_data[MAX_RSA_KEYLEN]; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_ULONG modulus_bytes, out_data_len; UNUSED(tokdata); UNUSED(sess); UNUSED(sig_len); out_data_len = MAX_RSA_KEYLEN; flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return CKR_FUNCTION_FAILED; } else { modulus_bytes = attr->ulValueLen; } rc = os_specific_rsa_encrypt(tokdata, signature, modulus_bytes, out, key_obj); if (rc != CKR_OK) { /* * Return CKR_SIGNATURE_INVALID in case of CKR_ARGUMENTS_BAD * because we dont know why the RSA op failed and it may have * failed due to a tampered signature being greater or equal * to the modulus. */ TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); return rc == CKR_ARGUMENTS_BAD ? CKR_SIGNATURE_INVALID : rc; } rc = rsa_parse_block(out, modulus_bytes, out_data, &out_data_len, PKCS_BT_1); if (rc == CKR_ENCRYPTED_DATA_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); return CKR_SIGNATURE_INVALID; } else if (rc != CKR_OK) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (in_data_len != out_data_len) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); return CKR_SIGNATURE_INVALID; } if (CRYPTO_memcmp(in_data, out_data, out_data_len) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); return CKR_SIGNATURE_INVALID; } return CKR_OK; } CK_RV token_specific_rsa_verify_recover(STDLL_TokData_t *tokdata, CK_BYTE *signature, CK_ULONG sig_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { CK_RV rc; CK_BYTE out[MAX_RSA_KEYLEN]; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_ULONG modulus_bytes; UNUSED(tokdata); UNUSED(sig_len); flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return CKR_FUNCTION_FAILED; } else { modulus_bytes = attr->ulValueLen; } rc = os_specific_rsa_encrypt(tokdata, signature, modulus_bytes, out, key_obj); if (rc != CKR_OK) { TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); return rc; } rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_1); if (rc == CKR_ENCRYPTED_DATA_INVALID) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); return CKR_SIGNATURE_INVALID; } else if (rc != CKR_OK) { TRACE_DEVEL("rsa_parse_block failed\n"); } return rc; } CK_RV token_specific_rsa_x509_encrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { CK_RV rc; CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN]; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_ULONG modulus_bytes; UNUSED(tokdata); flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return CKR_FUNCTION_FAILED; } else { modulus_bytes = attr->ulValueLen; } // prepad with zeros // memset(clear, 0x0, modulus_bytes - in_data_len); memcpy(&clear[modulus_bytes - in_data_len], in_data, in_data_len); rc = os_specific_rsa_encrypt(tokdata, clear, modulus_bytes, cipher, key_obj); if (rc == CKR_OK) { memcpy(out_data, cipher, modulus_bytes); *out_data_len = modulus_bytes; } else { TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); } return rc; } CK_RV token_specific_rsa_x509_decrypt(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { CK_RV rc; CK_BYTE out[MAX_RSA_KEYLEN]; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_ULONG modulus_bytes; UNUSED(tokdata); UNUSED(in_data_len); flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return CKR_FUNCTION_FAILED; } else { modulus_bytes = attr->ulValueLen; } rc = os_specific_rsa_decrypt(tokdata, in_data, modulus_bytes, out, key_obj); if (rc == CKR_OK) { memcpy(out_data, out, modulus_bytes); *out_data_len = modulus_bytes; } else { TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); } return rc; } CK_RV token_specific_rsa_x509_sign(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { CK_RV rc; CK_BYTE data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN]; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_ULONG modulus_bytes; UNUSED(tokdata); flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return CKR_FUNCTION_FAILED; } else { modulus_bytes = attr->ulValueLen; } // prepad with zeros // memset(data, 0x0, modulus_bytes - in_data_len); memcpy(&data[modulus_bytes - in_data_len], in_data, in_data_len); rc = os_specific_rsa_decrypt(tokdata, data, modulus_bytes, sig, key_obj); if (rc == CKR_OK) { memcpy(out_data, sig, modulus_bytes); *out_data_len = modulus_bytes; } else { TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); } return rc; } CK_RV token_specific_rsa_x509_verify(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG sig_len, OBJECT *key_obj) { CK_RV rc; CK_BYTE out[MAX_RSA_KEYLEN]; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_ULONG modulus_bytes; UNUSED(tokdata); UNUSED(sig_len); flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return CKR_FUNCTION_FAILED; } else { modulus_bytes = attr->ulValueLen; } rc = os_specific_rsa_encrypt(tokdata, signature, modulus_bytes, out, key_obj); if (rc == CKR_OK) { CK_ULONG pos1, pos2, len; // it should be noted that in_data_len is not necessarily // the same as the modulus length // for (pos1 = 0; pos1 < in_data_len; pos1++) if (in_data[pos1] != 0) break; for (pos2 = 0; pos2 < modulus_bytes; pos2++) if (out[pos2] != 0) break; // at this point, pos1 and pos2 point to the first non-zero // bytes in the input data and the decrypted signature // (the recovered data), respectively. // if ((in_data_len - pos1) != (modulus_bytes - pos2)) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); return CKR_SIGNATURE_INVALID; } len = in_data_len - pos1; if (CRYPTO_memcmp(&in_data[pos1], &out[pos2], len) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); return CKR_SIGNATURE_INVALID; } return CKR_OK; } else { TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); } return rc; } CK_RV token_specific_rsa_x509_verify_recover(STDLL_TokData_t *tokdata, CK_BYTE *signature, CK_ULONG sig_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { CK_RV rc; CK_BYTE out[MAX_RSA_KEYLEN]; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_ULONG modulus_bytes; UNUSED(tokdata); UNUSED(sig_len); flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); return CKR_FUNCTION_FAILED; } else { modulus_bytes = attr->ulValueLen; } rc = os_specific_rsa_encrypt(tokdata, signature, modulus_bytes, out, key_obj); if (rc == CKR_OK) { memcpy(out_data, out, modulus_bytes); *out_data_len = modulus_bytes; } else { TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); } return rc; } CK_RV token_specific_rsa_oaep_encrypt(STDLL_TokData_t *tokdata, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *hash, CK_ULONG hlen) { CK_RV rc; CK_BYTE cipher[MAX_RSA_KEYLEN]; CK_ULONG modulus_bytes; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_BYTE *em_data = NULL; OBJECT *key_obj = NULL; CK_RSA_PKCS_OAEP_PARAMS_PTR oaepParms = NULL; if (!in_data || !out_data || !hash) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } oaepParms = (CK_RSA_PKCS_OAEP_PARAMS_PTR) ctx->mech.pParameter; rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); return rc; } flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } else { modulus_bytes = attr->ulValueLen; } /* pkcs1v2.2, section 7.1.1 Step 2: * EME-OAEP encoding. */ em_data = (CK_BYTE *) malloc(modulus_bytes); if (em_data == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } rc = encode_eme_oaep(tokdata, in_data, in_data_len, em_data, modulus_bytes, oaepParms->mgf, hash, hlen); if (rc != CKR_OK) goto done; rc = os_specific_rsa_encrypt(tokdata, em_data, modulus_bytes, cipher, key_obj); if (rc == CKR_OK) { memcpy(out_data, cipher, modulus_bytes); *out_data_len = modulus_bytes; } else { TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); } done: if (em_data) free(em_data); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV token_specific_rsa_oaep_decrypt(STDLL_TokData_t *tokdata, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE *hash, CK_ULONG hlen) { CK_RV rc; CK_BYTE *decr_data = NULL; OBJECT *key_obj = NULL; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_RSA_PKCS_OAEP_PARAMS_PTR oaepParms = NULL; if (!in_data || !out_data || !hash) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_FUNCTION_FAILED; } oaepParms = (CK_RSA_PKCS_OAEP_PARAMS_PTR) ctx->mech.pParameter; rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); return rc; } flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } else { *out_data_len = attr->ulValueLen; } decr_data = (CK_BYTE *) malloc(in_data_len); if (decr_data == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } rc = os_specific_rsa_decrypt(tokdata, in_data, in_data_len, decr_data, key_obj); if (rc != CKR_OK) goto done; /* pkcs1v2.2, section 7.1.2 Step 2: * EME-OAEP decoding. */ rc = decode_eme_oaep(tokdata, decr_data, in_data_len, out_data, out_data_len, oaepParms->mgf, hash, hlen); if (decr_data) free(decr_data); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV token_specific_rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *sig, CK_ULONG *sig_len) { CK_RV rc; CK_ULONG modbytes; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; OBJECT *key_obj = NULL; CK_BYTE *emdata = NULL; CK_RSA_PKCS_PSS_PARAMS *pssParms = NULL; UNUSED(sess); /* check the arguments */ if (!in_data || !sig) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } if (!ctx) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } pssParms = (CK_RSA_PKCS_PSS_PARAMS *) ctx->mech.pParameter; /* get the key */ rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); return rc; } flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } else { modbytes = attr->ulValueLen; } emdata = (CK_BYTE *) malloc(modbytes); if (emdata == NULL) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } rc = emsa_pss_encode(tokdata, pssParms, in_data, in_data_len, emdata, &modbytes); if (rc != CKR_OK) goto done; /* signing is a private key operation --> decrypt */ rc = os_specific_rsa_decrypt(tokdata, emdata, modbytes, sig, key_obj); if (rc == CKR_OK) *sig_len = modbytes; else TRACE_DEVEL("os_specific_rsa_decrypt failed\n"); done: if (emdata) free(emdata); object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV token_specific_rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess, SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG sig_len) { CK_RV rc; CK_ULONG modbytes; OBJECT *key_obj = NULL; CK_BBOOL flag; CK_ATTRIBUTE *attr = NULL; CK_BYTE out[MAX_RSA_KEYLEN]; CK_RSA_PKCS_PSS_PARAMS *pssParms = NULL; UNUSED(sess); /* check the arguments */ if (!in_data || !signature) { TRACE_ERROR("%s\n", ock_err(ERR_ARGUMENTS_BAD)); return CKR_ARGUMENTS_BAD; } if (!ctx) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } pssParms = (CK_RSA_PKCS_PSS_PARAMS *) ctx->mech.pParameter; /* get the key */ rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_DEVEL("object_mgr_find_in_map1 failed\n"); return rc; } /* verify is a public key operation ... encrypt */ rc = os_specific_rsa_encrypt(tokdata, signature, sig_len, out, key_obj); if (rc != CKR_OK) { TRACE_DEVEL("os_specific_rsa_encrypt failed\n"); goto done; } flag = template_attribute_find(key_obj->template, CKA_MODULUS, &attr); if (flag == FALSE) { TRACE_ERROR("Could not find CKA_MODULUS for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } else { modbytes = attr->ulValueLen; } /* call the pss verify scheme */ rc = emsa_pss_verify(tokdata, pssParms, in_data, in_data_len, out, modbytes); done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } #ifndef NOAES CK_RV token_specific_aes_key_gen(STDLL_TokData_t *tokdata, CK_BYTE **key, CK_ULONG *len, CK_ULONG keysize, CK_BBOOL *is_opaque) { *key = malloc(keysize); if (*key == NULL) return CKR_HOST_MEMORY; *len = keysize; *is_opaque = FALSE; return rng_generate(tokdata, *key, keysize); } CK_RV token_specific_aes_ecb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE encrypt) { int rc = CKR_OK; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); /* * checks for input and output data length and block sizes * are already being carried out in mech_aes.c * so we skip those */ // get the key value rc = template_attribute_find(key->template, CKA_VALUE, &attr); if (rc == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (encrypt) { rc = ica_aes_ecb(in_data, out_data, in_data_len, attr->pValue, attr->ulValueLen, ICA_ENCRYPT); } else { rc = ica_aes_ecb(in_data, out_data, in_data_len, attr->pValue, attr->ulValueLen, ICA_DECRYPT); } if (rc != 0) { (*out_data_len) = 0; rc = CKR_FUNCTION_FAILED; } else { (*out_data_len) = in_data_len; rc = CKR_OK; } return rc; } CK_RV token_specific_aes_cbc(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *init_v, CK_BYTE encrypt) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); /* * checks for input and output data length and block sizes * are already being carried out in mech_aes.c * so we skip those */ // get the key value if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (encrypt) { rc = ica_aes_cbc(in_data, out_data, in_data_len, attr->pValue, attr->ulValueLen, init_v, ICA_ENCRYPT); } else { rc = ica_aes_cbc(in_data, out_data, in_data_len, attr->pValue, attr->ulValueLen, init_v, ICA_DECRYPT); } if (rc != 0) { (*out_data_len) = 0; rc = CKR_FUNCTION_FAILED; } else { (*out_data_len) = in_data_len; rc = CKR_OK; } return rc; } CK_RV token_specific_aes_ctr(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key, CK_BYTE *counterblock, CK_ULONG counter_width, CK_BYTE encrypt) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); /* * checks for input and output data length and block sizes * are already being carried out in mech_aes.c * so we skip those */ /* in libica for AES-Counter Mode if uses one function for both encrypt and * decrypt, so they use variable direction to know if the data is to be * encrypted or decrypted * 0 -- Decrypt * 1 -- Encrypt */ // get the key value if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (encrypt) { rc = ica_aes_ctr(in_data, out_data, (unsigned int) in_data_len, attr->pValue, (unsigned int) attr->ulValueLen, counterblock, (unsigned int) counter_width, 1); } else { rc = ica_aes_ctr(in_data, out_data, (unsigned int) in_data_len, attr->pValue, (unsigned int) attr->ulValueLen, counterblock, (unsigned int) counter_width, 0); } if (rc != 0) { (*out_data_len) = 0; rc = CKR_FUNCTION_FAILED; } else { (*out_data_len) = in_data_len; rc = CKR_OK; } return rc; } CK_RV token_specific_aes_gcm_init(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx, CK_MECHANISM *mech, CK_OBJECT_HANDLE key, CK_BYTE encrypt) { CK_RV rc = CKR_OK; OBJECT *key_obj = NULL; CK_ATTRIBUTE *attr = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; AES_GCM_CONTEXT *context = NULL; CK_BYTE *icv, *icb, *ucb, *subkey; CK_ULONG icv_length; UNUSED(sess); /* find key object */ rc = object_mgr_find_in_map1(tokdata, key, &key_obj, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } /* get the key value */ rc = template_attribute_find(key_obj->template, CKA_VALUE, &attr); if (rc == FALSE) { TRACE_ERROR("Could not find CKA_KEY_VALUE for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } /* prepare initial counterblock */ aes_gcm_param = (CK_GCM_PARAMS *) mech->pParameter; context = (AES_GCM_CONTEXT *) ctx->context; context->ulAlen = aes_gcm_param->ulAADLen; icb = (CK_BYTE *) context->icb; ucb = (CK_BYTE *) context->ucb; subkey = (CK_BYTE *) context->subkey; icv = (CK_BYTE *) aes_gcm_param->pIv; icv_length = aes_gcm_param->ulIvLen; if (encrypt) { rc = ica_aes_gcm_initialize(icv, icv_length, attr->pValue, attr->ulValueLen, icb, ucb, subkey, 1); } else { rc = ica_aes_gcm_initialize(icv, icv_length, attr->pValue, attr->ulValueLen, icb, ucb, subkey, 0); } if (rc != 0) { TRACE_ERROR("ica_aes_gcm_initialize() failed.\n"); goto done; } done: object_put(tokdata, key_obj, TRUE); key_obj = NULL; return rc; } CK_RV token_specific_aes_gcm(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE encrypt) { CK_RV rc; OBJECT *key = NULL; CK_ATTRIBUTE *attr = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; CK_BYTE *counterblock; CK_ULONG counter_width; CK_BYTE *tag_data, *auth_data; CK_ULONG auth_data_len; CK_ULONG tag_data_len; UNUSED(sess); /* * Checks for input and output data length and block sizes are already * being carried out in mech_aes.c, so we skip those * * libica for AES-GCM Mode uses one function for both encrypt * and decrypt, so they use the variable 'direction' to know if * the data is to be encrypted or decrypted. * 0 -- Decrypt * 1 -- Encrypt */ aes_gcm_param = (CK_GCM_PARAMS *) ctx->mech.pParameter; counterblock = (CK_BYTE *) aes_gcm_param->pIv; counter_width = aes_gcm_param->ulIvLen; auth_data = (CK_BYTE *) aes_gcm_param->pAAD; auth_data_len = aes_gcm_param->ulAADLen; tag_data_len = (aes_gcm_param->ulTagBits + 7) / 8; /* find key object */ rc = object_mgr_find_in_map1(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } /* get key value */ if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } if (encrypt) { tag_data = out_data + in_data_len; rc = ica_aes_gcm(in_data, (unsigned int) in_data_len, out_data, counterblock, (unsigned int) counter_width, auth_data, (unsigned int) auth_data_len, tag_data, AES_BLOCK_SIZE, attr->pValue, (unsigned int) attr->ulValueLen, 1); if (rc == 0) { (*out_data_len) = in_data_len + tag_data_len; rc = CKR_OK; } } else { unsigned int len; tag_data = in_data + in_data_len - tag_data_len; len = in_data_len - tag_data_len; rc = ica_aes_gcm(out_data, (unsigned int) len, in_data, counterblock, (unsigned int) counter_width, auth_data, (unsigned int) auth_data_len, tag_data, (unsigned int) tag_data_len, attr->pValue, (unsigned int) attr->ulValueLen, 0); if (rc == 0) { (*out_data_len) = len; rc = CKR_OK; } } if (rc != 0) { TRACE_ERROR("ica_aes_gcm failed with rc = 0x%lx.\n", rc); (*out_data_len) = 0; rc = CKR_FUNCTION_FAILED; } done: object_put(tokdata, key, TRUE); key = NULL; return rc; } CK_RV token_specific_aes_gcm_update(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE encrypt) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; OBJECT *key = NULL; AES_GCM_CONTEXT *context = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; CK_ULONG total, tag_data_len, remain, auth_data_len; CK_ULONG out_len; CK_BYTE *auth_data, *tag_data; CK_BYTE *ucb, *subkey; CK_BYTE *buffer = NULL; UNUSED(tokdata); UNUSED(sess); context = (AES_GCM_CONTEXT *) ctx->context; total = (context->len + in_data_len); ucb = (CK_BYTE *) context->ucb; tag_data = context->hash; auth_data_len = context->ulAlen; subkey = (CK_BYTE *) context->subkey; aes_gcm_param = (CK_GCM_PARAMS *) ctx->mech.pParameter; tag_data_len = (aes_gcm_param->ulTagBits + 7) / 8; auth_data = (CK_BYTE *) aes_gcm_param->pAAD; /* if there isn't enough data to make a block, just save it */ if (encrypt) { remain = (total % AES_BLOCK_SIZE); if (total < AES_BLOCK_SIZE) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; *out_data_len = 0; return CKR_OK; } } else { /* decrypt */ remain = ((total - tag_data_len) % AES_BLOCK_SIZE) + tag_data_len; if (total < AES_BLOCK_SIZE + tag_data_len) { memcpy(context->data + context->len, in_data, in_data_len); context->len += in_data_len; *out_data_len = 0; return CKR_OK; } } /* At least we have 1 block */ /* find key object */ rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } /* get key value */ if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } out_len = total - remain; buffer = (CK_BYTE *) malloc(out_len); if (!buffer) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } if (encrypt) { /* copy all the leftover data from previous encryption first */ memcpy(buffer, context->data, context->len); memcpy(buffer + context->len, in_data, out_len - context->len); TRACE_DEVEL("Ciphertext length (%ld bytes).\n", in_data_len); rc = ica_aes_gcm_intermediate(buffer, (unsigned int) out_len, out_data, ucb, auth_data, (unsigned int) auth_data_len, tag_data, AES_BLOCK_SIZE, attr->pValue, (unsigned int) attr->ulValueLen, subkey, 1); /* save any remaining data */ if (remain != 0) memcpy(context->data, in_data + (in_data_len - remain), remain); context->len = remain; } else { /* decrypt */ /* copy all the leftover data from previous encryption first */ if (in_data_len >= tag_data_len) { /* case 1 */ /* copy complete context to buffer first */ memcpy(buffer, context->data, context->len); /* Append in_data to buffer */ memcpy(buffer + context->len, in_data, out_len - context->len); /* copy remaining data to context */ memcpy(context->data, in_data + out_len - context->len, remain); context->len = remain; } else { /* case 2 - partial data */ memcpy(buffer, context->data, AES_BLOCK_SIZE); memcpy(context->data, context->data + AES_BLOCK_SIZE, context->len - AES_BLOCK_SIZE); memcpy(context->data + context->len - AES_BLOCK_SIZE, in_data, in_data_len); context->len = context->len - AES_BLOCK_SIZE + in_data_len; } rc = ica_aes_gcm_intermediate(out_data, (unsigned int) out_len, buffer, ucb, auth_data, (unsigned int) auth_data_len, tag_data, (unsigned int) tag_data_len, attr->pValue, (unsigned int) attr->ulValueLen, subkey, 0); } if (rc != 0) { TRACE_ERROR("ica_aes_gcm_update failed with rc = 0x%lx.\n", rc); rc = CKR_FUNCTION_FAILED; goto done; } (*out_data_len) = out_len; context->ulClen += out_len; /* AAD only processed in first update seuence, * mark it empty for all subsequent calls */ context->ulAlen = 0; done: if (buffer) free(buffer); object_put(tokdata, key, TRUE); key = NULL; return rc; } CK_RV token_specific_aes_gcm_final(STDLL_TokData_t *tokdata, SESSION *sess, ENCR_DECR_CONTEXT *ctx, CK_BYTE *out_data, CK_ULONG *out_data_len, CK_BYTE encrypt) { CK_RV rc = CKR_OK; CK_ATTRIBUTE *attr = NULL; OBJECT *key = NULL; AES_GCM_CONTEXT *context = NULL; CK_GCM_PARAMS *aes_gcm_param = NULL; CK_BYTE *icb, *ucb; CK_BYTE *tag_data, *subkey, *auth_data, *final_tag_data; CK_ULONG auth_data_len, tag_data_len; CK_BYTE *buffer = NULL; UNUSED(tokdata); UNUSED(sess); /* find key object */ rc = object_mgr_find_in_map_nocache(tokdata, ctx->key, &key, READ_LOCK); if (rc != CKR_OK) { TRACE_ERROR("Failed to find specified object.\n"); return rc; } if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); rc = CKR_FUNCTION_FAILED; goto done; } context = (AES_GCM_CONTEXT *) ctx->context; ucb = (CK_BYTE *) context->ucb; icb = (CK_BYTE *) context->icb; tag_data = context->hash; subkey = (CK_BYTE *) context->subkey; aes_gcm_param = (CK_GCM_PARAMS *) ctx->mech.pParameter; auth_data = (CK_BYTE *) aes_gcm_param->pAAD; auth_data_len = aes_gcm_param->ulAADLen; tag_data_len = (aes_gcm_param->ulTagBits + 7) / 8; if (encrypt) { if (context->len != 0) { buffer = (CK_BYTE *) malloc(AES_BLOCK_SIZE); if (!buffer) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } memcpy(buffer, context->data, context->len); rc = ica_aes_gcm_intermediate(buffer, context->len, out_data, ucb, auth_data, context->ulAlen, tag_data, AES_BLOCK_SIZE, attr->pValue, (unsigned int) attr->ulValueLen, subkey, 1); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_intermediate() " "failed to encrypt\n"); rc = CKR_FUNCTION_FAILED; goto done; } context->ulClen += context->len; *out_data_len = context->len + tag_data_len; } else { *out_data_len = tag_data_len; } TRACE_DEVEL("GCM Final: context->len=%ld, tag_data_len=%ld, " "out_data_len=%ld\n", context->len, tag_data_len, *out_data_len); rc = ica_aes_gcm_last(icb, (unsigned int) auth_data_len, (unsigned int) context->ulClen, tag_data, NULL, 0, attr->pValue, (unsigned int) attr->ulValueLen, subkey, 1); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_final failed with rc = 0x%lx.\n", rc); rc = CKR_FUNCTION_FAILED; goto done; } memcpy(out_data + context->len, tag_data, tag_data_len); } else { /* decrypt */ if (context->len > tag_data_len) { buffer = (CK_BYTE *) malloc(AES_BLOCK_SIZE); if (!buffer) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); rc = CKR_HOST_MEMORY; goto done; } memcpy(buffer, context->data, context->len - tag_data_len); rc = ica_aes_gcm_intermediate(out_data, (unsigned int) context->len - tag_data_len, buffer, ucb, auth_data, (unsigned int) context->ulAlen, tag_data, AES_BLOCK_SIZE, attr->pValue, (unsigned int) attr->ulValueLen, subkey, 0); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_intermediate() " "failed to decrypt.\n"); rc = CKR_FUNCTION_FAILED; goto done; } (*out_data_len) = context->len - tag_data_len; context->ulClen += context->len - tag_data_len; } else if (context->len == tag_data_len) { /* remaining data are tag data */ *out_data_len = 0; } else { /* (context->len < tag_data_len) */ TRACE_ERROR("Incoming data are not consistent.\n"); rc = CKR_DATA_INVALID; goto done; } final_tag_data = context->data + context->len - tag_data_len; rc = ica_aes_gcm_last(icb, aes_gcm_param->ulAADLen, context->ulClen, tag_data, final_tag_data, tag_data_len, attr->pValue, (unsigned int) attr->ulValueLen, subkey, 0); if (rc != 0) { TRACE_ERROR("ica_aes_gcm_final failed with rc = 0x%lx.\n", rc); rc = CKR_FUNCTION_FAILED; } } done: if (buffer) free(buffer); object_put(tokdata, key, TRUE); key = NULL; return rc; } /** * In libica for AES-OFB Mode it uses one function for both encrypt and decrypt * The variable direction is used as an indicator either for encrypt or decrypt * 0 -- Decrypt * 1 -- Encrypt */ CK_RV token_specific_aes_ofb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key, CK_BYTE *init_v, uint_32 direction) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } rc = ica_aes_ofb(in_data, out_data, (unsigned long) in_data_len, attr->pValue, (unsigned int) attr->ulValueLen, init_v, direction); if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } return rc; } /** * In libica for AES-CFB Mode it uses one function for both encrypt and decrypt * The variable direction is used as an indicator either for encrypt or decrypt * 0 -- Decrypt * 1 -- Encrypt */ CK_RV token_specific_aes_cfb(STDLL_TokData_t *tokdata, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, OBJECT *key, CK_BYTE *init_v, uint_32 lcfb, uint_32 direction) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } rc = ica_aes_cfb(in_data, out_data, (unsigned long) in_data_len, attr->pValue, (unsigned int) attr->ulValueLen, init_v, lcfb, direction); if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } return rc; } CK_RV token_specific_aes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } rc = ica_aes_cmac_intermediate(message, (unsigned long) message_len, attr->pValue, (unsigned int) attr->ulValueLen, mac); if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } return rc; } CK_RV token_specific_aes_cmac(STDLL_TokData_t *tokdata, CK_BYTE *message, CK_ULONG message_len, OBJECT *key, CK_BYTE *mac, CK_BBOOL first, CK_BBOOL last, CK_VOID_PTR *ctx) { CK_RV rc; CK_ATTRIBUTE *attr = NULL; UNUSED(tokdata); UNUSED(ctx); if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) { TRACE_ERROR("Could not find CKA_VALUE for the key.\n"); return CKR_FUNCTION_FAILED; } if (first && last) { rc = ica_aes_cmac(message, (unsigned long) message_len, mac, AES_BLOCK_SIZE, attr->pValue, (unsigned int) attr->ulValueLen, ICA_ENCRYPT); } else if (!last) { rc = ica_aes_cmac_intermediate(message, (unsigned long) message_len, attr->pValue, (unsigned int) attr->ulValueLen, mac); } else { rc = ica_aes_cmac_last(message, (unsigned long) message_len, mac, AES_BLOCK_SIZE, attr->pValue, (unsigned int) attr->ulValueLen, mac, ICA_ENCRYPT); } if (rc != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; } return rc; } #endif typedef struct _REF_MECH_LIST_ELEMENT { CK_ULONG lica_idx; CK_MECHANISM_TYPE mech_type; CK_MECHANISM_INFO mech_info; } REF_MECH_LIST_ELEMENT; static const REF_MECH_LIST_ELEMENT ref_mech_list[] = { {92, CKM_RSA_PKCS_KEY_PAIR_GEN, {512, 4096, CKF_HW | CKF_GENERATE_KEY_PAIR} }, #if !(NODSA) // {1, CKM_DSA_KEY_PAIR_GEN, {512, 1024, CKF_HW|CKF_GENERATE_KEY_PAIR}}, #endif #if !(NOCDMF) // {4, CKM_CDMF_KEY_GEN, {0, 0, CKF_HW|CKF_GENERATE}}, #endif {80, CKM_DES_KEY_GEN, {8, 8, CKF_HW | CKF_GENERATE}}, {80, CKM_DES3_KEY_GEN, {24, 24, CKF_HW | CKF_GENERATE}}, {90, CKM_RSA_PKCS, {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER} }, #if !(NOX509) {90, CKM_RSA_X_509, {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_SIGN | CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER} }, #endif {90, CKM_RSA_PKCS_OAEP, {512, 4096, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {90, CKM_RSA_PKCS_PSS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {90, CKM_SHA1_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {90, CKM_SHA224_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {90, CKM_SHA256_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {90, CKM_SHA384_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {90, CKM_SHA512_RSA_PKCS_PSS, {512, 4096, CKF_SIGN | CKF_VERIFY}}, {190, CKM_SHA1_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {190, CKM_SHA224_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {190, CKM_SHA256_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {190, CKM_SHA384_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {190, CKM_SHA512_RSA_PKCS, {512, 4096, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {20, CKM_DES_ECB, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {21, CKM_DES_CBC, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {21, CKM_DES_CBC_PAD, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {41, CKM_DES3_ECB, {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {42, CKM_DES3_CBC, {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {42, CKM_DES3_CBC_PAD, {24, 24, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {49, CKM_DES3_MAC, {24, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {49, CKM_DES3_MAC_GENERAL, {24, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {49, CKM_DES3_CMAC, {16, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {49, CKM_DES3_CMAC_GENERAL, {16, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {24, CKM_DES_CFB8, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {44, CKM_DES_OFB64, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {45, CKM_DES_CFB64, {8, 8, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {01, CKM_SHA_1, {0, 0, CKF_HW | CKF_DIGEST}}, {01, CKM_SHA_1_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {01, CKM_SHA_1_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {03, CKM_SHA224, {0, 0, CKF_HW | CKF_DIGEST}}, {03, CKM_SHA224_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {03, CKM_SHA224_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {03, CKM_SHA256, {0, 0, CKF_HW | CKF_DIGEST}}, {03, CKM_SHA256_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {03, CKM_SHA256_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {04, CKM_SHA384, {0, 0, CKF_HW | CKF_DIGEST}}, {04, CKM_SHA384_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {04, CKM_SHA384_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {05, CKM_SHA512, {0, 0, CKF_HW | CKF_DIGEST}}, {05, CKM_SHA512_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {05, CKM_SHA512_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, #ifdef SHA512_224 {95, CKM_SHA512_224, {0, 0, CKF_HW|CKF_DIGEST}}, {95, CKM_SHA512_224_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {95, CKM_SHA512_224_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA512_256 {96, CKM_SHA512_256, {0, 0, CKF_HW|CKF_DIGEST}}, {96, CKM_SHA512_256_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {96, CKM_SHA512_256_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_224 {6, CKM_IBM_SHA3_224, {0, 0, CKF_HW|CKF_DIGEST}}, {6, CKM_IBM_SHA3_224_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_256 {7, CKM_IBM_SHA3_256, {0, 0, CKF_HW|CKF_DIGEST}}, {7, CKM_IBM_SHA3_256_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_384 {8, CKM_IBM_SHA3_384, {0, 0, CKF_HW|CKF_DIGEST}}, {8, CKM_IBM_SHA3_384_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, #endif #ifdef SHA3_512 {9, CKM_IBM_SHA3_512, {0, 0, CKF_HW|CKF_DIGEST}}, {9, CKM_IBM_SHA3_512_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, #endif #if !(NOMD5) {53, CKM_MD5, {0, 0, CKF_HW | CKF_DIGEST}}, {54, CKM_MD5_HMAC, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {55, CKM_MD5_HMAC_GENERAL, {0, 0, CKF_HW | CKF_SIGN | CKF_VERIFY}}, #endif #if !(NOAES) {80, CKM_AES_KEY_GEN, {16, 32, CKF_HW | CKF_GENERATE}}, {60, CKM_AES_ECB, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {61, CKM_AES_CBC, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {61, CKM_AES_CBC_PAD, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {63, CKM_AES_OFB, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {64, CKM_AES_CFB8, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {64, CKM_AES_CFB64, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {64, CKM_AES_CFB128, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {65, CKM_AES_CTR, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP} }, {70, CKM_AES_GCM, {16, 32, CKF_HW | CKF_ENCRYPT | CKF_DECRYPT}}, {68, CKM_AES_MAC, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {68, CKM_AES_MAC_GENERAL, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {68, CKM_AES_CMAC, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, {68, CKM_AES_CMAC_GENERAL, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}}, #endif {80, CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_HW | CKF_GENERATE}}, #ifndef NO_EC {85, CKM_ECDH1_DERIVE, {160, 521, CKF_HW | CKF_DERIVE | CKF_EC_NAMEDCURVE | CKF_EC_F_P} }, {86, CKM_ECDSA, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} }, {86, CKM_ECDSA_SHA1, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} }, {86, CKM_ECDSA_SHA224, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} }, {86, CKM_ECDSA_SHA256, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} }, {86, CKM_ECDSA_SHA384, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} }, {86, CKM_ECDSA_SHA512, {160, 521, CKF_HW | CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE | CKF_EC_F_P} }, {88, CKM_EC_KEY_PAIR_GEN, {160, 521, CKF_HW | CKF_GENERATE_KEY_PAIR | CKF_EC_NAMEDCURVE | CKF_EC_F_P} }, #endif }; static const CK_ULONG ref_mech_list_len = (sizeof(ref_mech_list) / sizeof(REF_MECH_LIST_ELEMENT)); CK_RV token_specific_get_mechanism_list(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { return ock_generic_get_mechanism_list(tokdata, pMechanismList, pulCount); } CK_RV token_specific_get_mechanism_info(STDLL_TokData_t *tokdata, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { return ock_generic_get_mechanism_info(tokdata, type, pInfo); } static CK_RV getRefListIdxfromId(CK_ULONG ica_idx, CK_ULONG_PTR pRefIdx) { unsigned int n; for (n = *pRefIdx; n < ref_mech_list_len; n++) { if (ica_idx == ref_mech_list[n].lica_idx) { *pRefIdx = n; return CKR_OK; } } return CKR_MECHANISM_INVALID; } static CK_RV getRefListIdxfromMech(CK_ULONG mech, CK_ULONG_PTR pRefIdx) { unsigned int n; for (n = *pRefIdx; n < ref_mech_list_len; n++) { if (mech == ref_mech_list[n].mech_type) { *pRefIdx = n; return CKR_OK; } } return CKR_MECHANISM_INVALID; } static CK_BBOOL isMechanismAvailable(STDLL_TokData_t *tokdata, CK_ULONG mechanism) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; unsigned int i; for (i = 0; i < ica_data->mech_list_len; i++) { if (ica_data->mech_list[i].mech_type == mechanism) return TRUE; } return FALSE; } static CK_RV addMechanismToList(STDLL_TokData_t *tokdata, CK_ULONG mechanism) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_ULONG ret; CK_ULONG refIdx = 0; if (ica_data->mech_list_len >= ICA_MAX_MECH_LIST_ENTRIES) { TRACE_ERROR("Not enough slots available to add mechanism\n"); return CKR_BUFFER_TOO_SMALL; } ret = getRefListIdxfromMech(mechanism, &refIdx); if (ret != CKR_OK) { return CKR_FUNCTION_FAILED; } ica_data->mech_list[ica_data->mech_list_len].mech_type = ref_mech_list[refIdx].mech_type; ica_data->mech_list[ica_data->mech_list_len].mech_info.flags = (ref_mech_list[refIdx].mech_info.flags & 0xfffffffe); ica_data->mech_list[ica_data->mech_list_len].mech_info.ulMinKeySize = ref_mech_list[refIdx].mech_info.ulMinKeySize; ica_data->mech_list[ica_data->mech_list_len].mech_info.ulMaxKeySize = ref_mech_list[refIdx].mech_info.ulMaxKeySize; ica_data->mech_list_len++; return CKR_OK; } /* * call libica to receive list of supported mechanisms * This method is called once per opencryptoki instance (application context) */ static CK_RV mech_list_ica_initialize(STDLL_TokData_t *tokdata) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_ULONG ret, rc = CKR_OK; unsigned int i, n; unsigned int ica_specific_mech_list_len; CK_ULONG tmp, ulActMechCtr, ulPreDefMechCtr, refIdx; ica_data->mech_list[0].mech_type = CKF_DIGEST; ica_data->mech_list[0].mech_info.flags = CKF_DIGEST; ica_data->mech_list[1].mech_type = CKM_MD5_HMAC; ica_data->mech_list[1].mech_info.flags = CKF_SIGN | CKF_VERIFY; ica_data->mech_list[2].mech_type = CKM_MD5_HMAC_GENERAL; ica_data->mech_list[2].mech_info.flags = CKF_SIGN | CKF_VERIFY; ica_data->mech_list_len = 3; rc = ica_get_functionlist(NULL, &ica_specific_mech_list_len); if (rc != CKR_OK) { TRACE_ERROR("ica_get_functionlist failed\n"); return CKR_FUNCTION_FAILED; } libica_func_list_element libica_func_list[ica_specific_mech_list_len]; rc = ica_get_functionlist(libica_func_list, &ica_specific_mech_list_len); if (rc != CKR_OK) { TRACE_ERROR("ica_get_functionlist failed\n"); return CKR_FUNCTION_FAILED; } /* * grab the mechanism of the corresponding ID returned by libICA * from the internal reference list put the mechanism ID and the * HW support indication into an internal ica_mech_list and get * additional flag information from the reference list */ ulPreDefMechCtr = ica_data->mech_list_len; for (i = 0; i < ica_specific_mech_list_len; i++) { if (libica_func_list[i].flags == 0) continue; // loop over libica supported list ulActMechCtr = (CK_ULONG)(-1); /* --- walk through the whole reflist and fetch all * matching mechanism's (if present) --- */ refIdx = 0; while ((ret = getRefListIdxfromId(libica_func_list[i].mech_mode_id, &refIdx)) == CKR_OK) { /* * Loop over the predefined mechanism list and check * if we have to overrule a software implemented * mechanism from token by libica HW supported * mechanism. */ for (n = 0; n < ulPreDefMechCtr; n++) { if (ica_data->mech_list[n].mech_type == ref_mech_list[refIdx].mech_type) { ulActMechCtr = n; break; } } if (ulActMechCtr == (CK_ULONG)(-1)) { /* add a new entry */ if (ica_data->mech_list_len >= ICA_MAX_MECH_LIST_ENTRIES) { TRACE_ERROR("Not enough slots available to add mechanism\n"); return CKR_BUFFER_TOO_SMALL; } ica_data->mech_list[ica_data->mech_list_len].mech_type = ref_mech_list[refIdx].mech_type; ica_data->mech_list[ica_data->mech_list_len].mech_info.flags = (libica_func_list[i].flags & 0x01) | (ref_mech_list[refIdx].mech_info.flags & 0xfffffffe); ica_data->mech_list[ica_data->mech_list_len].mech_info.ulMinKeySize = ref_mech_list[refIdx].mech_info.ulMinKeySize; ica_data->mech_list[ica_data->mech_list_len].mech_info.ulMaxKeySize = ref_mech_list[refIdx].mech_info.ulMaxKeySize; ica_data->mech_list_len++; } else { /* replace existing entry */ ica_data->mech_list[ulActMechCtr].mech_info.flags = (libica_func_list[i].flags & 0x01) | ica_data->mech_list[ulActMechCtr].mech_info.flags; } refIdx++; } } /* * check if special combined mechanisms are supported * if SHA1 and RSA is available -> insert CKM_SHA1_RSA_PKCS * if SHA256 and RSA is available -> insert CKM_SHA256_RSA_PKCS * if MD2 and RSA is available -> insert CKM_MD2_RSA_PKCS * if MD5 and RSA is available -> insert CKM_MD5_RSA_PKCS */ if (isMechanismAvailable(tokdata, CKM_SHA_1) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA1_RSA_PKCS); if (isMechanismAvailable(tokdata, CKM_SHA224) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA224_RSA_PKCS); if (isMechanismAvailable(tokdata, CKM_SHA256) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA256_RSA_PKCS); if (isMechanismAvailable(tokdata, CKM_SHA384) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA384_RSA_PKCS); if (isMechanismAvailable(tokdata, CKM_SHA512) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_SHA512_RSA_PKCS); if (isMechanismAvailable(tokdata, CKM_MD2) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_MD2_RSA_PKCS); if (isMechanismAvailable(tokdata, CKM_MD5) && isMechanismAvailable(tokdata, CKM_RSA_PKCS)) addMechanismToList(tokdata, CKM_MD5_RSA_PKCS); /* sort the mech_list_ica by mechanism ID's (bubble sort) */ for (i = 0; i < ica_data->mech_list_len; i++) { for (n = i; n < ica_data->mech_list_len; n++) { if (ica_data->mech_list[i].mech_type > ica_data->mech_list[n].mech_type) { tmp = ica_data->mech_list[i].mech_type; ica_data->mech_list[i].mech_type = ica_data->mech_list[n].mech_type; ica_data->mech_list[n].mech_type = tmp; tmp = ica_data->mech_list[i].mech_info.ulMinKeySize; ica_data->mech_list[i].mech_info.ulMinKeySize = ica_data->mech_list[n].mech_info.ulMinKeySize; ica_data->mech_list[n].mech_info.ulMinKeySize = tmp; tmp = ica_data->mech_list[i].mech_info.ulMaxKeySize; ica_data->mech_list[i].mech_info.ulMaxKeySize = ica_data->mech_list[n].mech_info.ulMaxKeySize; ica_data->mech_list[n].mech_info.ulMaxKeySize = tmp; tmp = ica_data->mech_list[i].mech_info.flags; ica_data->mech_list[i].mech_info.flags = ica_data->mech_list[n].mech_info.flags; ica_data->mech_list[n].mech_info.flags = tmp; } } } return rc; } CK_RV token_specific_generic_secret_key_gen(STDLL_TokData_t *tokdata, TEMPLATE *tmpl) { CK_ATTRIBUTE *attr = NULL; CK_RV rc = CKR_OK; CK_BYTE secret_key[MAX_GENERIC_KEY_SIZE]; CK_ULONG key_length = 0; CK_ULONG key_length_in_bits = 0; CK_ATTRIBUTE *value_attr = NULL; rc = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr); if (rc == FALSE) { TRACE_ERROR("CKA_VALUE_LEM missing in key template\n"); return CKR_TEMPLATE_INCOMPLETE; } key_length = *(CK_ULONG *) attr->pValue; //app specified key length in bytes key_length_in_bits = key_length * 8; /* After looking at fips cavs test vectors for HMAC ops, * it was decided that the key length should fall between * 80 and 2048 bits inclusive. */ if ((key_length_in_bits < 80) || (key_length_in_bits > 2048)) { TRACE_ERROR("Generic secret key size of %lu bits not within" " required range of 80-2048 bits\n", key_length_in_bits); return CKR_KEY_SIZE_RANGE; } /* libica does not have generic secret key generation, * so call token rng here. */ rc = rng_generate(tokdata, secret_key, key_length); if (rc != CKR_OK) { TRACE_DEVEL("Generic secret key generation failed.\n"); return rc; } rc = build_attribute(CKA_VALUE, secret_key, key_length, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute(CKA_VALUE) failed\n"); return rc; } rc = template_update_attribute(tmpl, value_attr); if (rc != CKR_OK) TRACE_DEVEL("template_update_attribute(CKA_VALUE) failed\n"); return rc; } #ifndef NO_EC static CK_RV build_update_attribute(TEMPLATE *tmpl, CK_ATTRIBUTE_TYPE type, CK_BYTE *data, CK_ULONG data_len) { CK_ATTRIBUTE *attr; CK_RV rv; if ((rv = build_attribute(type, data, data_len, &attr))) return rv; template_update_attribute(tmpl, attr); return CKR_OK; } static CK_RV is_equal(unsigned char *a, unsigned int a_length, unsigned char *b, unsigned int b_length) { if (a_length != b_length) return 0; if (memcmp(a, b, a_length) == 0) return 1; return 0; } static int nid_from_oid(CK_BYTE *oid, CK_ULONG oid_length) { /* Supported Elliptic Curves */ static const CK_BYTE brainpoolP160r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01 }; static const CK_BYTE brainpoolP192r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x03 }; static const CK_BYTE brainpoolP224r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x05 }; static const CK_BYTE brainpoolP256r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07 }; static const CK_BYTE brainpoolP320r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x09 }; static const CK_BYTE brainpoolP384r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B }; static const CK_BYTE brainpoolP512r1[] = { 0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D }; static const CK_BYTE prime192[] = { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01 }; static const CK_BYTE secp224[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x21 }; static const CK_BYTE prime256[] = { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }; static const CK_BYTE secp384[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22 }; static const CK_BYTE secp521[] = { 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23 }; if (is_equal (oid, oid_length, (unsigned char *) &prime192, sizeof(prime192))) return NID_X9_62_prime192v1; else if (is_equal(oid, oid_length, (unsigned char *) &secp224, sizeof(secp224))) return NID_secp224r1; else if (is_equal(oid, oid_length, (unsigned char *) &prime256, sizeof(prime256))) return NID_X9_62_prime256v1; else if (is_equal(oid, oid_length, (unsigned char *) &secp384, sizeof(secp384))) return NID_secp384r1; else if (is_equal(oid, oid_length, (unsigned char *) &secp521, sizeof(secp521))) return NID_secp521r1; else if (is_equal(oid, oid_length, (unsigned char *) &brainpoolP160r1, sizeof(brainpoolP160r1))) return NID_brainpoolP160r1; else if (is_equal(oid, oid_length, (unsigned char *) &brainpoolP192r1, sizeof(brainpoolP192r1))) return NID_brainpoolP192r1; else if (is_equal(oid, oid_length, (unsigned char *) &brainpoolP224r1, sizeof(brainpoolP224r1))) return NID_brainpoolP224r1; else if (is_equal(oid, oid_length, (unsigned char *) &brainpoolP256r1, sizeof(brainpoolP256r1))) return NID_brainpoolP256r1; else if (is_equal(oid, oid_length, (unsigned char *) &brainpoolP320r1, sizeof(brainpoolP320r1))) return NID_brainpoolP320r1; else if (is_equal(oid, oid_length, (unsigned char *) &brainpoolP384r1, sizeof(brainpoolP384r1))) return NID_brainpoolP384r1; else if (is_equal(oid, oid_length, (unsigned char *) &brainpoolP512r1, sizeof(brainpoolP512r1))) return NID_brainpoolP512r1; return -1; } CK_RV token_specific_ec_generate_keypair(STDLL_TokData_t *tokdata, TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr = NULL; ICA_EC_KEY *eckey; CK_BYTE q_array[1 + ICATOK_EC_MAX_Q_LEN]; CK_BYTE d_array[ICATOK_EC_MAX_D_LEN]; unsigned int privlen, q_len, d_len; CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len; int rc, nid; if (!ica_data->ica_ec_support_available) { TRACE_ERROR("ECC support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } if (!template_attribute_find(publ_tmpl, CKA_ECDSA_PARAMS, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } /* Determine curve nid */ nid = nid_from_oid(attr->pValue, attr->ulValueLen); if (nid < 0) { TRACE_ERROR("curve not supported by icatoken.\n"); return CKR_CURVE_NOT_SUPPORTED; } /* Create ICA_EC_KEY object */ eckey = p_ica_ec_key_new(nid, &privlen); if (!eckey) { TRACE_ERROR("ica_ec_key_new() failed.\n"); return CKR_FUNCTION_FAILED; } /* Generate key data for this key object */ rc = p_ica_ec_key_generate(ica_data->adapter_handle, eckey); if (rc != 0) { TRACE_ERROR("ica_ec_key_generate() failed with rc=%d.\n", rc); ret = CKR_FUNCTION_FAILED; goto end; } /* Return public key (X,Y) via CKA_EC_POINT as OCTET STRING */ rc = p_ica_ec_key_get_public_key(eckey, (unsigned char *)&q_array[1], &q_len); if (rc != 0) { TRACE_ERROR("ica_ec_key_get_public_key() failed with rc=%d.\n", rc); ret = CKR_FUNCTION_FAILED; goto end; } q_array[0] = POINT_CONVERSION_UNCOMPRESSED; q_len++; rc = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, q_array, q_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); goto end; } ret = build_update_attribute(publ_tmpl, CKA_EC_POINT, ecpoint, ecpoint_len); if (ret != 0) { TRACE_ERROR("build_update_attribute for (X,Y) failed rc=0x%lx\n", ret); goto end; } /* Return private key (D) via CKA_VALUE */ rc = p_ica_ec_key_get_private_key(eckey, (unsigned char *) &d_array, &d_len); if (rc != 0) { TRACE_ERROR("ica_ec_key_get_private_key() failed with rc=%d.\n", rc); ret = CKR_FUNCTION_FAILED; goto end; } ret = build_update_attribute(priv_tmpl, CKA_VALUE, d_array, d_len); if (ret != 0) { TRACE_ERROR("build_update_attribute for (D) failed, rc=0x%lx\n", ret); goto end; } /* Add CKA_ECDSA_PARAMS to private template also */ ret = build_update_attribute(priv_tmpl, CKA_ECDSA_PARAMS, attr->pValue, attr->ulValueLen); if (ret != 0) { TRACE_ERROR("build_update_attribute for CKA_ECDSA_PARAMS failed, " "rc=0x%lx\n", ret); goto end; } ret = CKR_OK; end: p_ica_ec_key_free(eckey); if (ecpoint != NULL) free(ecpoint); return ret; } CK_RV token_specific_ec_sign(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *out_data, CK_ULONG *out_data_len, OBJECT *key_obj) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr, *attr2; ICA_EC_KEY *eckey; unsigned int privlen; int rc, nid; UNUSED(sess); *out_data_len = 0; if (!ica_data->ica_ec_support_available) { TRACE_ERROR("ECC support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } /* Get CKA_ECDSA_PARAMS from template */ if (!template_attribute_find(key_obj->template, CKA_ECDSA_PARAMS, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } /* Determine curve nid */ nid = nid_from_oid(attr->pValue, attr->ulValueLen); if (nid < 0) { TRACE_ERROR("Cannot determine curve nid. \n"); return CKR_CURVE_NOT_SUPPORTED; } /* Create ICA_EC_KEY object */ eckey = p_ica_ec_key_new(nid, &privlen); if (!eckey) { TRACE_ERROR("ica_ec_key_new() failed for curve %i.\n", nid); return CKR_FUNCTION_FAILED; } /* Get private key from template via CKA_VALUE */ if (!template_attribute_find(key_obj->template, CKA_VALUE, &attr2)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); ret = CKR_TEMPLATE_INCOMPLETE; goto end; } /* Plausibility check */ if (privlen != attr2->ulValueLen) { TRACE_ERROR("Private key length for curve %i mismatch: length from " "ica_ec_key_new() = %i, length from attribute = %ld", nid, privlen, attr2->ulValueLen); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto end; } /* Initialize ICA_EC_KEY with private key (D) */ rc = p_ica_ec_key_init(NULL, NULL, attr2->pValue, eckey); if (rc != 0) { TRACE_ERROR("ica_ec_key_init() failed with rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } /* Create signature */ rc = p_ica_ecdsa_sign(ica_data->adapter_handle, eckey, (unsigned char *) in_data, (unsigned int) in_data_len, (unsigned char *) out_data, 2 * privlen); if (rc != 0) { TRACE_ERROR("ica_ecdsa_sign() failed with rc = %d. \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } *out_data_len = 2 * privlen; ret = CKR_OK; end: p_ica_ec_key_free(eckey); return ret; } /** * decompress the given compressed public key. Sets x from given pub_key, * re-calculates y from format byte, x and nid. * * @return 0 on success */ static CK_RV decompress_pubkey(unsigned int nid, const unsigned char *pub_key, CK_ULONG pub_len, unsigned int priv_len, unsigned char *x, unsigned char *y) { BN_CTX *ctx = BN_CTX_new(); BIGNUM *bn_x = BN_bin2bn((unsigned char *) &(pub_key[1]), priv_len, NULL); BIGNUM *bn_y = BN_new(); EC_GROUP *group = NULL; EC_POINT *point = NULL; int y_bit = (pub_key[0] == POINT_CONVERSION_COMPRESSED ? 0 : 1); CK_RV ret = CKR_OK; UNUSED(pub_len); group = EC_GROUP_new_by_curve_name(nid); if (!group) { TRACE_ERROR("Curve %d is not supported by openssl. Cannot decompress " "public key\n", nid); ret = CKR_CURVE_NOT_SUPPORTED; goto end; } point = EC_POINT_new(group); if (!point) { ret = CKR_FUNCTION_FAILED; goto end; } if (!EC_POINT_set_compressed_coordinates(group, point, bn_x, y_bit, ctx)) { ret = CKR_FUNCTION_FAILED; goto end; } if (!EC_POINT_is_on_curve(group, point, ctx)) { ret = CKR_FUNCTION_FAILED; goto end; } if (!EC_POINT_get_affine_coordinates(group, point, bn_x, bn_y, ctx)) { ret = CKR_FUNCTION_FAILED; goto end; } memcpy(x, &(pub_key[1]), priv_len); BN_bn2bin(bn_y, y); end: if (ctx) BN_CTX_free(ctx); if (point) EC_POINT_free(point); if (group) EC_GROUP_free(group); if (bn_x) BN_free(bn_x); if (bn_y) BN_free(bn_y); return ret; } /** * returns the (X,Y) coordinates of the given EC public key. * For a compressed key, Y is calculated from X and an indication * if Y is even or odd. * * Refer to X9.62, section 4.3.6, "point to octet-string conversion". * * @return 0 on success */ static CK_RV set_pubkey_coordinates(unsigned int nid, const unsigned char *pub_key, CK_ULONG pub_len, unsigned int priv_len, unsigned char *x, unsigned char *y) { int i, n; /* Check if key has no format byte: [X || Y] */ if (pub_len == 2 * priv_len) { memcpy(x, pub_key, priv_len); memcpy(y, pub_key + priv_len, priv_len); return CKR_OK; } /* Check if key is compressed: [0x0n || X] * 0x0n: 0x02: Y is even * 0x03: Y is odd */ if (pub_len == priv_len + 1 && (pub_key[0] == POINT_CONVERSION_COMPRESSED || pub_key[0] == POINT_CONVERSION_COMPRESSED + 1)) { return decompress_pubkey(nid, pub_key, pub_len, priv_len, x, y); } /* Check if key is uncompressed or hybrid: [0x0n || X || Y] * 0x0n: 0x04 : uncompressed * 0c06 : hybrid, Y is even * 0x07 : hybrid, Y is odd */ if (pub_len == 2 * priv_len + 1 && (pub_key[0] == POINT_CONVERSION_UNCOMPRESSED || pub_key[0] == POINT_CONVERSION_HYBRID || pub_key[0] == POINT_CONVERSION_HYBRID + 1)) { memcpy(x, pub_key + 1, priv_len); memcpy(y, pub_key + 1 + priv_len, priv_len); return CKR_OK; } /* Add leading null bytes to pub_key X, if necessary. In this * case there is no format byte */ if (pub_len < 2 * priv_len) { n = 2 * priv_len - pub_len; for (i = 0; i < n; i++) x[i] = 0x00; memcpy(x + i, pub_key, priv_len - n); memcpy(y, pub_key + priv_len - n, priv_len); return CKR_OK; } memset(x, 0, priv_len); memset(y, 0, priv_len); return CKR_FUNCTION_FAILED; } CK_RV token_specific_ec_verify(STDLL_TokData_t *tokdata, SESSION *sess, CK_BYTE *in_data, CK_ULONG in_data_len, CK_BYTE *signature, CK_ULONG signature_len, OBJECT *key_obj) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV ret = CKR_OK; CK_ATTRIBUTE *attr, *attr2; ICA_EC_KEY *eckey; unsigned int privlen; unsigned char x_array[ICATOK_EC_MAX_D_LEN]; unsigned char y_array[ICATOK_EC_MAX_D_LEN]; int rc, nid; CK_BYTE *ecpoint; CK_ULONG ecpoint_len, field_len; UNUSED(sess); if (!ica_data->ica_ec_support_available) { TRACE_ERROR("ECC support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } /* Get CKA_ECDSA_PARAMS from template */ if (!template_attribute_find(key_obj->template, CKA_ECDSA_PARAMS, &attr)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); return CKR_TEMPLATE_INCOMPLETE; } /* Create ICA_EC_KEY object */ nid = nid_from_oid(attr->pValue, attr->ulValueLen); if (nid < 0) { TRACE_ERROR("Cannot determine curve nid. \n"); return CKR_CURVE_NOT_SUPPORTED; } eckey = p_ica_ec_key_new(nid, &privlen); if (!eckey) { TRACE_ERROR("ica_ec_key_new() failed for curve %i. \n", nid); return CKR_FUNCTION_FAILED; } /* Get public key (X,Y) from template via CKA_EC_POINT */ if (!template_attribute_find(key_obj->template, CKA_EC_POINT, &attr2)) { TRACE_ERROR("%s\n", ock_err(ERR_TEMPLATE_INCOMPLETE)); ret = CKR_TEMPLATE_INCOMPLETE; goto end; } /* CKA_EC_POINT contains the EC point as OCTET STRING */ ret = ber_decode_OCTET_STRING(attr2->pValue, &ecpoint, &ecpoint_len, &field_len); if (ret != CKR_OK || field_len != attr2->ulValueLen) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); ret = CKR_ATTRIBUTE_VALUE_INVALID; goto end; } /* Signature length ok? */ if (signature_len != 2 * privlen) { TRACE_ERROR("Supplied signature length mismatch: " "supplied length = %ld, length from libica = %i\n", signature_len, 2 * privlen); ret = CKR_SIGNATURE_LEN_RANGE; goto end; } /* Provide (X,Y), decompress key if necessary */ ret = set_pubkey_coordinates(nid, ecpoint, ecpoint_len, privlen, x_array, y_array); if (ret != 0) { TRACE_ERROR("Cannot determine public key coordinates from " "given public key\n"); goto end; } /* Initialize ICA_EC_KEY with public key (Q) */ rc = p_ica_ec_key_init(x_array, y_array, NULL, eckey); if (rc != 0) { TRACE_ERROR("ica_ec_key_init() for public key failed " "with rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } /* Verify signature */ rc = p_ica_ecdsa_verify(ica_data->adapter_handle, eckey, (unsigned char *) in_data, (unsigned int) in_data_len, (unsigned char *) signature, signature_len); switch (rc) { case 0: ret = CKR_OK; break; case EFAULT: TRACE_ERROR("ica_ecdsa_verify() returned invalid signature, " "rc = %d. \n", rc); ret = CKR_SIGNATURE_INVALID; break; default: TRACE_ERROR("ica_ecdsa_verify() returned internal error, " "rc = %d. \n", rc); ret = CKR_FUNCTION_FAILED; break; } end: p_ica_ec_key_free(eckey); return ret; } CK_RV token_specific_ecdh_pkcs_derive(STDLL_TokData_t *tokdata, CK_BYTE *priv_bytes, CK_ULONG priv_length, CK_BYTE *pub_bytes, CK_ULONG pub_length, CK_BYTE *secret_value, CK_ULONG *secret_value_len, CK_BYTE *oid, CK_ULONG oid_length) { ica_private_data_t *ica_data = (ica_private_data_t *)tokdata->private_data; CK_RV ret = CKR_OK; ICA_EC_KEY *pubkey = NULL, *privkey = NULL; unsigned int n, privlen, i; unsigned char d_array[ICATOK_EC_MAX_D_LEN]; unsigned char x_array[ICATOK_EC_MAX_D_LEN]; unsigned char y_array[ICATOK_EC_MAX_D_LEN]; int rc, nid; CK_BYTE *ecpoint; CK_ULONG ecpoint_len, field_len; UNUSED(tokdata); *secret_value_len = 0; if (!ica_data->ica_ec_support_available) { TRACE_ERROR("ECC support is not available in Libica\n"); return CKR_FUNCTION_NOT_SUPPORTED; } /* Get nid from oid */ nid = nid_from_oid(oid, oid_length); if (nid < 0) { TRACE_ERROR("curve not supported by icatoken.\n"); return CKR_CURVE_NOT_SUPPORTED; } /* Create ICA_EC_KEY object with public key */ pubkey = p_ica_ec_key_new(nid, &privlen); if (!pubkey) { TRACE_ERROR("ica_ec_key_new() for curve %i failed.\n", nid); return CKR_FUNCTION_FAILED; } /* As per PKCS#11, a token MUST be able to accept this value encoded * as a raw octet string (as per section A.5.2 of [ANSI X9.62]). * A token MAY, in addition, support accepting this value as a * DER-encoded ECPoint (as per section E.6 of [ANSI X9.62]) i.e. * the same as a CKA_EC_POINT encoding. */ ret = ber_decode_OCTET_STRING(pub_bytes, &ecpoint, &ecpoint_len, &field_len); if (ret != CKR_OK || field_len != pub_length || ecpoint_len > pub_length - 2) { /* no valid BER OCTET STRING encoding, assume raw octet string */ ecpoint = pub_bytes; ecpoint_len = pub_length; } /* Provide (X,Y), decompress key if necessary */ ret = set_pubkey_coordinates(nid, ecpoint, ecpoint_len, privlen, x_array, y_array); if (ret != 0) { TRACE_ERROR("Cannot determine public key coordinates\n"); goto end; } /* Format (D) as char array with leading nulls if necessary */ n = privlen - priv_length; for (i = 0; i < n; i++) d_array[i] = 0x00; memcpy(&(d_array[n]), priv_bytes, priv_length); /* Initialize ICA_EC_KEY with public key (X,Y) */ rc = p_ica_ec_key_init(x_array, y_array, NULL, pubkey); if (rc != 0) { TRACE_ERROR("ica_ec_key_init() for public key failed with " "rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } /* Create ICA_EC_KEY object with private key */ privkey = p_ica_ec_key_new(nid, &privlen); if (!privkey) { TRACE_ERROR("ica_ec_key_new() for curve %i failed. \n", nid); ret = CKR_FUNCTION_FAILED; goto end; } /* Initialize ICA_EC_KEY with private key (D) */ rc = p_ica_ec_key_init(NULL, NULL, d_array, privkey); if (rc != 0) { TRACE_ERROR("ica_ec_key_init() for private key failed with " "rc = %d \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } /* Calculate shared secret z */ rc = p_ica_ecdh_derive_secret(ica_data->adapter_handle, privkey, pubkey, secret_value, privlen); if (rc != 0) { TRACE_ERROR("ica_ecdh_derive_secret() failed with rc = %d. \n", rc); ret = CKR_FUNCTION_FAILED; goto end; } *secret_value_len = privlen; ret = CKR_OK; end: p_ica_ec_key_free(privkey); p_ica_ec_key_free(pubkey); return ret; } #endif