/*
* 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
*/
/***************************************************************************
Change Log
==========
4/25/03 Kapil Sood (kapil@corrent.com)
Added DH key pair generation and DH shared key derivation
functions.
****************************************************************************/
#include <pthread.h>
#include <string.h> // for memcmp() et al
#include <stdlib.h>
#include <unistd.h>
#include <openssl/opensslv.h>
#if OPENSSL_VERSION_NUMBER < 0x10101000L
#define NO_EC 1
#endif
#include "pkcs11types.h"
#include "defs.h"
#include "host_defs.h"
#include "h_extern.h"
#include "errno.h"
#include "tok_specific.h"
#include "tok_struct.h"
#include "trace.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <endian.h>
#include <openssl/des.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/dh.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>
#include <openssl/cmac.h>
#include <openssl/ec.h>
/*
* In order to make opencryptoki compatible with
* OpenSSL 1.1 API Changes and backward compatible
* we need to check for its version
*/
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#define OLDER_OPENSSL
#endif
#define MAX_GENERIC_KEY_SIZE 256
const char manuf[] = "IBM";
const char model[] = "Soft";
const char descr[] = "IBM Soft token";
const char label[] = "softtok";
static const MECH_LIST_ELEMENT soft_mech_list[] = {
{CKM_RSA_PKCS_KEY_PAIR_GEN, {512, 4096, CKF_GENERATE_KEY_PAIR}},
#if !(NODSA)
{CKM_DSA_KEY_PAIR_GEN, {512, 1024, CKF_GENERATE_KEY_PAIR}},
#endif
{CKM_DES_KEY_GEN, {8, 8, CKF_GENERATE}},
{CKM_DES3_KEY_GEN, {24, 24, CKF_GENERATE}},
#if !(NOCDMF)
{CKM_CDMF_KEY_GEN, {0, 0, CKF_GENERATE}},
#endif
{CKM_RSA_PKCS,
{512, 4096, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_SIGN |
CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER}},
{CKM_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA1_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA224_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN|CKF_VERIFY}},
{CKM_SHA256_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA384_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA512_RSA_PKCS_PSS, {1024, 4096, CKF_SIGN | CKF_VERIFY}},
#if !(NOX509)
{CKM_RSA_X_509,
{512, 4096, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP | CKF_SIGN |
CKF_VERIFY | CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER}},
#endif
{CKM_RSA_PKCS_OAEP,
{1024, 4096, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
#if !(NOMD2)
{CKM_MD2_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}},
#endif
#if !(NOMD5)
{CKM_MD5_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}},
#endif
#if !(NOSHA1)
{CKM_SHA1_RSA_PKCS, {512, 4096, CKF_SIGN | CKF_VERIFY}},
#endif
#if !(NODSA)
{CKM_DSA, {512, 1024, CKF_SIGN | CKF_VERIFY}},
#endif
/* Begin code contributed by Corrent corp. */
#if !(NODH)
{CKM_DH_PKCS_DERIVE, {512, 2048, CKF_DERIVE}},
{CKM_DH_PKCS_KEY_PAIR_GEN, {512, 2048, CKF_GENERATE_KEY_PAIR}},
#endif
/* End code contributed by Corrent corp. */
{CKM_DES_ECB, {8, 8, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
{CKM_DES_CBC, {8, 8, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
{CKM_DES_CBC_PAD,
{8, 8, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
#if !(NOCDMF)
{CKM_CDMF_ECB, {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
{CKM_CDMF_CBC, {0, 0, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
#endif
{CKM_DES3_ECB, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
{CKM_DES3_CBC, {24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
{CKM_DES3_CBC_PAD,
{24, 24, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
{CKM_DES3_MAC, {16, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}},
{CKM_DES3_MAC_GENERAL, {16, 24, CKF_HW | CKF_SIGN | CKF_VERIFY}},
{CKM_DES3_CMAC, {16, 24, CKF_SIGN | CKF_VERIFY}},
{CKM_DES3_CMAC_GENERAL, {16, 24, CKF_SIGN | CKF_VERIFY}},
#if !(NOSHA1)
{CKM_SHA_1, {0, 0, CKF_DIGEST}},
{CKM_SHA_1_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA_1_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}},
#endif
{CKM_SHA224, {0, 0, CKF_DIGEST}},
{CKM_SHA224_HMAC, {0, 0, CKF_SIGN|CKF_VERIFY}},
{CKM_SHA224_HMAC_GENERAL, {0, 0, CKF_SIGN|CKF_VERIFY}},
{CKM_SHA256, {0, 0, CKF_DIGEST}},
{CKM_SHA256_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA256_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA384, {0, 0, CKF_DIGEST}},
{CKM_SHA384_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA384_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA512, {0, 0, CKF_DIGEST}},
{CKM_SHA512_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA512_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}},
#ifdef NID_sha512_224WithRSAEncryption
{CKM_SHA512_224, {0, 0, CKF_DIGEST}},
{CKM_SHA512_224_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA512_224_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}},
#endif
#ifdef NID_sha512_256WithRSAEncryption
{CKM_SHA512_256, {0, 0, CKF_DIGEST}},
{CKM_SHA512_256_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_SHA512_256_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}},
#endif
#ifdef NID_sha3_224
{CKM_IBM_SHA3_224, {0, 0, CKF_DIGEST}},
{CKM_IBM_SHA3_224_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
#endif
#ifdef NID_sha3_256
{CKM_IBM_SHA3_256, {0, 0, CKF_DIGEST}},
{CKM_IBM_SHA3_256_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
#endif
#ifdef NID_sha3_384
{CKM_IBM_SHA3_384, {0, 0, CKF_DIGEST}},
{CKM_IBM_SHA3_384_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
#endif
#ifdef NID_sha3_512
{CKM_IBM_SHA3_512, {0, 0, CKF_DIGEST}},
{CKM_IBM_SHA3_512_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
#endif
#if !(NOMD2)
{CKM_MD2, {0, 0, CKF_DIGEST}},
{CKM_MD2_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_MD2_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}},
#endif
#if !(NOMD5)
{CKM_MD5, {0, 0, CKF_DIGEST}},
{CKM_MD5_HMAC, {0, 0, CKF_SIGN | CKF_VERIFY}},
{CKM_MD5_HMAC_GENERAL, {0, 0, CKF_SIGN | CKF_VERIFY}},
#endif
{CKM_SSL3_PRE_MASTER_KEY_GEN, {48, 48, CKF_GENERATE}},
{CKM_SSL3_MASTER_KEY_DERIVE, {48, 48, CKF_DERIVE}},
{CKM_SSL3_KEY_AND_MAC_DERIVE, {48, 48, CKF_DERIVE}},
{CKM_SSL3_MD5_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}},
{CKM_SSL3_SHA1_MAC, {384, 384, CKF_SIGN | CKF_VERIFY}},
#if !(NOAES)
{CKM_AES_KEY_GEN, {16, 32, CKF_GENERATE}},
{CKM_AES_ECB, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
{CKM_AES_CBC, {16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
{CKM_AES_CBC_PAD,
{16, 32, CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP}},
{CKM_AES_MAC, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}},
{CKM_AES_MAC_GENERAL, {16, 32, CKF_HW | CKF_SIGN | CKF_VERIFY}},
{CKM_AES_CMAC, {16, 32, CKF_SIGN | CKF_VERIFY}},
{CKM_AES_CMAC_GENERAL, {16, 32, CKF_SIGN | CKF_VERIFY}},
#endif
{CKM_GENERIC_SECRET_KEY_GEN, {80, 2048, CKF_GENERATE}},
#if !(NO_EC)
{CKM_EC_KEY_PAIR_GEN, {160, 521, CKF_GENERATE_KEY_PAIR |
CKF_EC_NAMEDCURVE | CKF_EC_F_P}},
{CKM_ECDSA, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE |
CKF_EC_F_P}},
{CKM_ECDSA_SHA1, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE |
CKF_EC_F_P}},
{CKM_ECDSA_SHA224, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE |
CKF_EC_F_P}},
{CKM_ECDSA_SHA256, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE |
CKF_EC_F_P}},
{CKM_ECDSA_SHA384, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE |
CKF_EC_F_P}},
{CKM_ECDSA_SHA512, {160, 521, CKF_SIGN | CKF_VERIFY | CKF_EC_NAMEDCURVE |
CKF_EC_F_P}},
{CKM_ECDH1_DERIVE, {160, 521, CKF_DERIVE | CKF_EC_NAMEDCURVE | CKF_EC_F_P}},
#endif
};
static const CK_ULONG soft_mech_list_len =
(sizeof(soft_mech_list) / sizeof(MECH_LIST_ELEMENT));
CK_RV token_specific_init(STDLL_TokData_t *tokdata, CK_SLOT_ID SlotNumber,
char *conf_name)
{
UNUSED(conf_name);
tokdata->mech_list = (MECH_LIST_ELEMENT *)soft_mech_list;
tokdata->mech_list_len = soft_mech_list_len;
TRACE_INFO("soft %s slot=%lu running\n", __func__, SlotNumber);
return CKR_OK;
}
CK_RV token_specific_final(STDLL_TokData_t *tokdata,
CK_BBOOL token_specific_final)
{
UNUSED(tokdata);
UNUSED(token_specific_final);
TRACE_INFO("soft %s running\n", __func__);
return CKR_OK;
}
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);
} else {
do {
rng_generate(tokdata, *des_key, keysize);;
} 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)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
CK_ULONG rc;
DES_key_schedule des_key2;
const_DES_cblock key_val_SSL, in_key_data;
DES_cblock out_key_data;
unsigned int i, j;
CK_ATTRIBUTE *attr = NULL;
UNUSED(tokdata);
// 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;
}
// Create the key schedule
memcpy(&key_val_SSL, attr->pValue, 8);
DES_set_key_unchecked(&key_val_SSL, &des_key2);
// the des decrypt will only fail if the data length is not evenly divisible
// by 8
if (in_data_len % DES_BLOCK_SIZE) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
// Both the encrypt and the decrypt are done 8 bytes at a time
if (encrypt) {
for (i = 0; i < in_data_len; i = i + 8) {
memcpy(in_key_data, in_data + i, 8);
DES_ecb_encrypt(&in_key_data, &out_key_data, &des_key2,
DES_ENCRYPT);
memcpy(out_data + i, out_key_data, 8);
}
*out_data_len = in_data_len;
rc = CKR_OK;
} else {
for (j = 0; j < in_data_len; j = j + 8) {
memcpy(in_key_data, in_data + j, 8);
DES_ecb_encrypt(&in_key_data, &out_key_data, &des_key2,
DES_DECRYPT);
memcpy(out_data + j, out_key_data, 8);
}
*out_data_len = in_data_len;
rc = CKR_OK;
}
return rc;
#else
const EVP_CIPHER *cipher = EVP_des_ecb();
EVP_CIPHER_CTX *ctx = NULL;
CK_ATTRIBUTE *attr = NULL;
unsigned char dkey[DES_KEY_SIZE];
CK_ULONG rc;
int outlen;
UNUSED(tokdata);
// get the key value
if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) {
TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n");
return CKR_FUNCTION_FAILED;
}
if (in_data_len % DES_BLOCK_SIZE || in_data_len > INT_MAX) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
memcpy(dkey, attr->pValue, sizeof(dkey));
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = ERR_HOST_MEMORY;
goto done;
}
if (EVP_CipherInit_ex(ctx, cipher,
NULL, dkey, NULL, encrypt ? 1 : 0) != 1
|| EVP_CIPHER_CTX_set_padding(ctx, 0) != 1
|| EVP_CipherUpdate(ctx, out_data, &outlen, in_data, in_data_len) != 1
|| EVP_CipherFinal_ex(ctx, out_data, &outlen) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR));
rc = ERR_GENERAL_ERROR;
goto done;
}
*out_data_len = in_data_len;
rc = CKR_OK;
done:
OPENSSL_cleanse(dkey, sizeof(dkey));
EVP_CIPHER_CTX_free(ctx);
return rc;
#endif
}
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)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
CK_ULONG rc;
CK_ATTRIBUTE *attr = NULL;
DES_cblock ivec;
DES_key_schedule des_key2;
const_DES_cblock key_val_SSL;
UNUSED(tokdata);
// 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;
}
// Create the key schedule
memcpy(&key_val_SSL, attr->pValue, 8);
DES_set_key_unchecked(&key_val_SSL, &des_key2);
memcpy(&ivec, init_v, 8);
// the des decrypt will only fail if the data length is not evenly divisible
// by 8
if (in_data_len % DES_BLOCK_SIZE) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
if (encrypt) {
DES_ncbc_encrypt(in_data, out_data, in_data_len, &des_key2, &ivec,
DES_ENCRYPT);
*out_data_len = in_data_len;
rc = CKR_OK;
} else {
DES_ncbc_encrypt(in_data, out_data, in_data_len, &des_key2, &ivec,
DES_DECRYPT);
*out_data_len = in_data_len;
rc = CKR_OK;
}
return rc;
#else
const EVP_CIPHER *cipher = EVP_des_cbc();
EVP_CIPHER_CTX *ctx = NULL;
CK_ATTRIBUTE *attr = NULL;
unsigned char dkey[DES_KEY_SIZE];
CK_ULONG rc;
int outlen;
UNUSED(tokdata);
// get the key value
if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) {
TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n");
return CKR_FUNCTION_FAILED;
}
if (in_data_len % DES_BLOCK_SIZE || in_data_len > INT_MAX) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
memcpy(dkey, attr->pValue, sizeof(dkey));
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = ERR_HOST_MEMORY;
goto done;
}
if (EVP_CipherInit_ex(ctx, cipher,
NULL, dkey, init_v, encrypt ? 1 : 0) != 1
|| EVP_CIPHER_CTX_set_padding(ctx, 0) != 1
|| EVP_CipherUpdate(ctx, out_data, &outlen, in_data, in_data_len) != 1
|| EVP_CipherFinal_ex(ctx, out_data, &outlen) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR));
rc = ERR_GENERAL_ERROR;
goto done;
}
*out_data_len = in_data_len;
rc = CKR_OK;
done:
OPENSSL_cleanse(dkey, sizeof(dkey));
EVP_CIPHER_CTX_free(ctx);
return rc;
#endif
}
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)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE key_value[3 * DES_KEY_SIZE];
CK_KEY_TYPE keytype;
unsigned int k, j;
DES_key_schedule des_key1;
DES_key_schedule des_key2;
DES_key_schedule des_key3;
const_DES_cblock key_SSL1, key_SSL2, key_SSL3, in_key_data;
DES_cblock out_key_data;
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);
}
// The key as passed is a 24 byte long string containing three des keys
// pick them apart and create the 3 corresponding key schedules
memcpy(&key_SSL1, key_value, 8);
memcpy(&key_SSL2, key_value + 8, 8);
memcpy(&key_SSL3, key_value + 16, 8);
DES_set_key_unchecked(&key_SSL1, &des_key1);
DES_set_key_unchecked(&key_SSL2, &des_key2);
DES_set_key_unchecked(&key_SSL3, &des_key3);
// the des decrypt will only fail if the data length is not evenly divisible
// by 8
if (in_data_len % DES_BLOCK_SIZE) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
// the encrypt and decrypt are done 8 bytes at a time
if (encrypt) {
for (k = 0; k < in_data_len; k = k + 8) {
memcpy(in_key_data, in_data + k, 8);
DES_ecb3_encrypt((const_DES_cblock *) & in_key_data,
(DES_cblock *) & out_key_data,
&des_key1, &des_key2, &des_key3, DES_ENCRYPT);
memcpy(out_data + k, out_key_data, 8);
}
*out_data_len = in_data_len;
rc = CKR_OK;
} else {
for (j = 0; j < in_data_len; j = j + 8) {
memcpy(in_key_data, in_data + j, 8);
DES_ecb3_encrypt((const_DES_cblock *) & in_key_data,
(DES_cblock *) & out_key_data,
&des_key1, &des_key2, &des_key3, DES_DECRYPT);
memcpy(out_data + j, out_key_data, 8);
}
*out_data_len = in_data_len;
rc = CKR_OK;
}
return rc;
#else
const EVP_CIPHER *cipher = EVP_des_ede3_ecb();
EVP_CIPHER_CTX *ctx = NULL;
CK_ATTRIBUTE *attr = NULL;
unsigned char dkey[3 * DES_KEY_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG rc;
int outlen;
UNUSED(tokdata);
// get the key type
rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr);
if (rc == FALSE) {
TRACE_ERROR("template_attribute_find(CKA_KEY_TYPE) failed.\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("template_attribute_find(CKA_VALUE) failed.\n");
return CKR_FUNCTION_FAILED;
}
if (in_data_len % DES_BLOCK_SIZE || in_data_len > INT_MAX) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
if (keytype == CKK_DES2) {
memcpy(dkey, attr->pValue, 2 * DES_KEY_SIZE);
memcpy(dkey + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE);
} else {
memcpy(dkey, attr->pValue, 3 * DES_KEY_SIZE);
}
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = ERR_HOST_MEMORY;
goto done;
}
if (EVP_CipherInit_ex(ctx, cipher,
NULL, dkey, NULL, encrypt ? 1 : 0) != 1
|| EVP_CIPHER_CTX_set_padding(ctx, 0) != 1
|| EVP_CipherUpdate(ctx, out_data, &outlen, in_data, in_data_len) != 1
|| EVP_CipherFinal_ex(ctx, out_data, &outlen) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR));
rc = ERR_GENERAL_ERROR;
goto done;
}
*out_data_len = in_data_len;
rc = CKR_OK;
done:
OPENSSL_cleanse(dkey, sizeof(dkey));
EVP_CIPHER_CTX_free(ctx);
return rc;
#endif
}
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)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
CK_ATTRIBUTE *attr = NULL;
CK_RV rc = CKR_OK;
CK_BYTE key_value[3 * DES_KEY_SIZE];
CK_KEY_TYPE keytype;
DES_key_schedule des_key1;
DES_key_schedule des_key2;
DES_key_schedule des_key3;
const_DES_cblock key_SSL1, key_SSL2, key_SSL3;
DES_cblock ivec;
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);
}
// The key as passed in is a 24 byte string containing 3 keys
// pick it apart and create the key schedules
memcpy(&key_SSL1, key_value, 8);
memcpy(&key_SSL2, key_value + 8, 8);
memcpy(&key_SSL3, key_value + 16, 8);
DES_set_key_unchecked(&key_SSL1, &des_key1);
DES_set_key_unchecked(&key_SSL2, &des_key2);
DES_set_key_unchecked(&key_SSL3, &des_key3);
memcpy(ivec, init_v, sizeof(ivec));
// the des decrypt will only fail if the data length is not evenly divisible
// by 8
if (in_data_len % DES_BLOCK_SIZE) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
// Encrypt or decrypt the data
if (encrypt) {
DES_ede3_cbc_encrypt(in_data,
out_data,
in_data_len,
&des_key1,
&des_key2, &des_key3, &ivec, DES_ENCRYPT);
*out_data_len = in_data_len;
rc = CKR_OK;
} else {
DES_ede3_cbc_encrypt(in_data,
out_data,
in_data_len,
&des_key1,
&des_key2, &des_key3, &ivec, DES_DECRYPT);
*out_data_len = in_data_len;
rc = CKR_OK;
}
return rc;
#else
const EVP_CIPHER *cipher = EVP_des_ede3_cbc();
EVP_CIPHER_CTX *ctx = NULL;
CK_ATTRIBUTE *attr = NULL;
unsigned char dkey[3 * DES_KEY_SIZE];
CK_KEY_TYPE keytype;
CK_ULONG rc;
int outlen;
UNUSED(tokdata);
// get the key type
rc = template_attribute_find(key->template, CKA_KEY_TYPE, &attr);
if (rc == FALSE) {
TRACE_ERROR("template_attribute_find(CKA_KEY_TYPE) failed.\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("template_attribute_find(CKA_VALUE) failed.\n");
return CKR_FUNCTION_FAILED;
}
if (keytype == CKK_DES2) {
memcpy(dkey, attr->pValue, 2 * DES_KEY_SIZE);
memcpy(dkey + (2 * DES_KEY_SIZE), attr->pValue, DES_KEY_SIZE);
} else {
memcpy(dkey, attr->pValue, 3 * DES_KEY_SIZE);
}
if (in_data_len % DES_BLOCK_SIZE || in_data_len > INT_MAX) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = ERR_HOST_MEMORY;
goto done;
}
if (EVP_CipherInit_ex(ctx, cipher,
NULL, dkey, init_v, encrypt ? 1 : 0) != 1
|| EVP_CIPHER_CTX_set_padding(ctx, 0) != 1
|| EVP_CipherUpdate(ctx, out_data, &outlen, in_data, in_data_len) != 1
|| EVP_CipherFinal_ex(ctx, out_data, &outlen) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR));
rc = ERR_GENERAL_ERROR;
goto done;
}
*out_data_len = in_data_len;
rc = CKR_OK;
done:
OPENSSL_cleanse(dkey, sizeof(dkey));
EVP_CIPHER_CTX_free(ctx);
return rc;
#endif
}
CK_RV token_specific_tdes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message,
CK_ULONG message_len, OBJECT *key, CK_BYTE *mac)
{
CK_BYTE *out_buf;
CK_ULONG out_len;
CK_RV rc;
out_buf = malloc(message_len);
if (out_buf == NULL) {
TRACE_ERROR("Malloc failed.\n");
return CKR_HOST_MEMORY;
}
rc = token_specific_tdes_cbc(tokdata, message, message_len, out_buf,
&out_len, key, mac, 1);
if (rc == CKR_OK && out_len >= DES_BLOCK_SIZE)
memcpy(mac, out_buf + out_len - DES_BLOCK_SIZE, DES_BLOCK_SIZE);
free(out_buf);
return rc;
}
// convert from the local PKCS11 template representation to
// the underlying requirement
// returns the pointer to the local key representation
static void *rsa_convert_public_key(OBJECT *key_obj)
{
CK_BBOOL rc;
CK_ATTRIBUTE *modulus = NULL;
CK_ATTRIBUTE *pub_exp = NULL;
RSA *rsa;
BIGNUM *bn_mod, *bn_exp;
rc = template_attribute_find(key_obj->template, CKA_MODULUS, &modulus);
rc &=
template_attribute_find(key_obj->template, CKA_PUBLIC_EXPONENT,
&pub_exp);
if (rc == FALSE) {
return NULL;
}
// Create an RSA key struct to return
rsa = RSA_new();
if (rsa == NULL)
return NULL;
// Create and init BIGNUM structs to stick in the RSA struct
bn_mod = BN_new();
bn_exp = BN_new();
if (bn_exp == NULL || bn_mod == NULL) {
if (bn_mod)
free(bn_mod);
if (bn_exp)
free(bn_exp);
RSA_free(rsa);
return NULL;
}
// Convert from strings to BIGNUMs and stick them in the RSA struct
BN_bin2bn((unsigned char *) modulus->pValue, modulus->ulValueLen, bn_mod);
BN_bin2bn((unsigned char *) pub_exp->pValue, pub_exp->ulValueLen, bn_exp);
#ifdef OLDER_OPENSSL
rsa->n = bn_mod;
rsa->e = bn_exp;
#else
RSA_set0_key(rsa, bn_mod, bn_exp, NULL);
#endif
return (void *) rsa;
}
static void *rsa_convert_private_key(OBJECT *key_obj)
{
CK_ATTRIBUTE *modulus = NULL;
CK_ATTRIBUTE *pub_exp = NULL;
CK_ATTRIBUTE *priv_exp = NULL;
CK_ATTRIBUTE *prime1 = NULL;
CK_ATTRIBUTE *prime2 = NULL;
CK_ATTRIBUTE *exp1 = NULL;
CK_ATTRIBUTE *exp2 = NULL;
CK_ATTRIBUTE *coeff = NULL;
CK_BBOOL rc;
RSA *rsa;
RSA_METHOD *meth;
BIGNUM *bn_mod, *bn_pub_exp, *bn_priv_exp, *bn_p1, *bn_p2, *bn_e1, *bn_e2,
*bn_cf;
rc = template_attribute_find(key_obj->template, CKA_MODULUS, &modulus);
rc &=
template_attribute_find(key_obj->template, CKA_PUBLIC_EXPONENT,
&pub_exp);
rc &=
template_attribute_find(key_obj->template, CKA_PRIVATE_EXPONENT,
&priv_exp);
rc &= template_attribute_find(key_obj->template, CKA_PRIME_1, &prime1);
rc &= template_attribute_find(key_obj->template, CKA_PRIME_2, &prime2);
rc &= template_attribute_find(key_obj->template, CKA_EXPONENT_1, &exp1);
rc &= template_attribute_find(key_obj->template, CKA_EXPONENT_2, &exp2);
rc &= template_attribute_find(key_obj->template, CKA_COEFFICIENT, &coeff);
if (!prime2 && !modulus) {
return NULL;
}
// Create and init all the RSA and BIGNUM structs we need.
rsa = RSA_new();
if (rsa == NULL)
return NULL;
/*
* Depending if an engine is loaded on OpenSSL and define its own
* RSA_METHOD, we can end up having an infinite loop as the SOFT
* Token doesn't implement RSA and, instead, calls OpenSSL for it.
* So to avoid it we set RSA methods to the default rsa methods.
*/
#ifdef OLDER_OPENSSL
if (rsa->engine) {
meth = (RSA_METHOD *) rsa->meth;
const RSA_METHOD *meth2 = RSA_PKCS1_SSLeay();
meth->rsa_pub_enc = meth2->rsa_pub_enc;
meth->rsa_pub_dec = meth2->rsa_pub_dec;
meth->rsa_priv_enc = meth2->rsa_priv_enc;
meth->rsa_priv_dec = meth2->rsa_priv_dec;
meth->rsa_mod_exp = meth2->rsa_mod_exp;
meth->bn_mod_exp = meth2->bn_mod_exp;
#else
/*
* XXX I dont see a better way than to ignore this warning for now.
* Note that the GCC pragma also works for clang.
*/
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
ENGINE *e = RSA_get0_engine(rsa);
if (e) {
meth = (RSA_METHOD *) RSA_get_method(rsa);
const RSA_METHOD *meth2 = RSA_PKCS1_OpenSSL();
RSA_meth_set_pub_enc(meth, RSA_meth_get_pub_enc(meth2));
RSA_meth_set_pub_dec(meth, RSA_meth_get_pub_dec(meth2));
RSA_meth_set_priv_enc(meth, RSA_meth_get_priv_enc(meth2));
RSA_meth_set_priv_dec(meth, RSA_meth_get_priv_dec(meth2));
RSA_meth_set_mod_exp(meth, RSA_meth_get_mod_exp(meth2));
RSA_meth_set_bn_mod_exp(meth, RSA_meth_get_bn_mod_exp(meth2));
# pragma GCC diagnostic pop
#endif
}
bn_mod = BN_new();
bn_pub_exp = BN_new();
bn_priv_exp = BN_new();
bn_p1 = BN_new();
bn_p2 = BN_new();
bn_e1 = BN_new();
bn_e2 = BN_new();
bn_cf = BN_new();
if ((bn_cf == NULL) || (bn_e2 == NULL) || (bn_e1 == NULL) ||
(bn_p2 == NULL) || (bn_p1 == NULL) || (bn_priv_exp == NULL) ||
(bn_pub_exp == NULL) || (bn_mod == NULL)) {
if (rsa)
RSA_free(rsa);
if (bn_mod)
BN_free(bn_mod);
if (bn_pub_exp)
BN_free(bn_pub_exp);
if (bn_priv_exp)
BN_free(bn_priv_exp);
if (bn_p1)
BN_free(bn_p1);
if (bn_p2)
BN_free(bn_p2);
if (bn_e1)
BN_free(bn_e1);
if (bn_e2)
BN_free(bn_e2);
if (bn_cf)
BN_free(bn_cf);
return NULL;
}
// CRT key?
if (prime1) {
if (!prime2 || !exp1 || !exp2 || !coeff) {
return NULL;
}
// Even though this is CRT key, OpenSSL requires the
// modulus and exponents filled in or encrypt and decrypt will
// not work
BN_bin2bn((unsigned char *) modulus->pValue, modulus->ulValueLen,
bn_mod);
BN_bin2bn((unsigned char *) pub_exp->pValue, pub_exp->ulValueLen,
bn_pub_exp);
BN_bin2bn((unsigned char *) priv_exp->pValue, priv_exp->ulValueLen,
bn_priv_exp);
BN_bin2bn((unsigned char *) prime1->pValue, prime1->ulValueLen, bn_p1);
BN_bin2bn((unsigned char *) prime2->pValue, prime2->ulValueLen, bn_p2);
BN_bin2bn((unsigned char *) exp1->pValue, exp1->ulValueLen, bn_e1);
BN_bin2bn((unsigned char *) exp2->pValue, exp2->ulValueLen, bn_e2);
BN_bin2bn((unsigned char *) coeff->pValue, coeff->ulValueLen, bn_cf);
#ifdef OLDER_OPENSSL
rsa->n = bn_mod;
rsa->d = bn_priv_exp;
rsa->p = bn_p1;
rsa->q = bn_p2;
rsa->dmp1 = bn_e1;
rsa->dmq1 = bn_e2;
rsa->iqmp = bn_cf;
#else
RSA_set0_key(rsa, bn_mod, bn_pub_exp, bn_priv_exp);
RSA_set0_factors(rsa, bn_p1, bn_p2);
RSA_set0_crt_params(rsa, bn_e1, bn_e2, bn_cf);
#endif
return rsa;
} else { // must be a non-CRT key
if (!priv_exp) {
return NULL;
}
BN_bin2bn((unsigned char *) modulus->pValue, modulus->ulValueLen,
bn_mod);
BN_bin2bn((unsigned char *) pub_exp->pValue, pub_exp->ulValueLen,
bn_pub_exp);
BN_bin2bn((unsigned char *) priv_exp->pValue, priv_exp->ulValueLen,
bn_priv_exp);
#ifdef OLDER_OPENSSL
rsa->n = bn_mod;
rsa->d = bn_priv_exp;
#else
RSA_set0_key(rsa, bn_mod, bn_pub_exp, bn_priv_exp);
#endif
}
return (void *) rsa;
}
static CK_RV os_specific_rsa_keygen(TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl)
{
CK_ATTRIBUTE *publ_exp = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_ULONG mod_bits;
CK_BBOOL flag;
CK_RV rc;
CK_ULONG BNLength;
RSA *rsa = NULL;
const BIGNUM *bignum = NULL;
CK_BYTE *ssl_ptr = NULL;
BIGNUM *e = NULL;
#ifndef OLDER_OPENSSL
EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *ctx = NULL;
#endif
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;
// we don't support less than 1024 bit keys in the sw
if (mod_bits < 512 || mod_bits > 4096) {
TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE));
return CKR_KEY_SIZE_RANGE;
}
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;
}
if (publ_exp->ulValueLen > sizeof(CK_ULONG)) {
TRACE_ERROR("%s\n", ock_err(ERR_ATTRIBUTE_VALUE_INVALID));
return CKR_ATTRIBUTE_VALUE_INVALID;
}
e = BN_new();
if (e == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
BN_bin2bn(publ_exp->pValue, publ_exp->ulValueLen, e);
#ifdef OLDER_OPENSSL
rsa = RSA_new();
if (rsa == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
if (!RSA_generate_key_ex(rsa, mod_bits, e, NULL)) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
bignum = rsa->n;
#else
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
if (EVP_PKEY_keygen_init(ctx) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (mod_bits > INT_MAX
|| EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, mod_bits) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx, e) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (EVP_PKEY_keygen(ctx, &pkey) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
if ((rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
RSA_get0_key(rsa, &bignum, NULL, NULL);
#endif
BNLength = BN_num_bytes(bignum);
ssl_ptr = malloc(BNLength);
if (ssl_ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
BNLength = BN_bn2bin(bignum, ssl_ptr);
rc = build_attribute(CKA_MODULUS, ssl_ptr, BNLength, &attr); // in bytes
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(publ_tmpl, attr);
free(ssl_ptr);
ssl_ptr = NULL;
// Public Exponent
#ifdef OLDER_OPENSSL
bignum = rsa->e;
#else
RSA_get0_key(rsa, NULL, &bignum, NULL);
#endif
BNLength = BN_num_bytes(bignum);
ssl_ptr = malloc(BNLength);
if (ssl_ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
BNLength = BN_bn2bin(bignum, ssl_ptr);
// in bytes
rc = build_attribute(CKA_PUBLIC_EXPONENT, ssl_ptr, BNLength, &attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(publ_tmpl, attr);
/* add public exponent to the private template. Its already an attribute in
* the private template at this point, we're just making its value correct
*/
rc = build_attribute(CKA_PUBLIC_EXPONENT, ssl_ptr, BNLength, &attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(priv_tmpl, attr);
free(ssl_ptr);
ssl_ptr = NULL;
// 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 done;
}
template_update_attribute(publ_tmpl, attr);
//
// now, do the private key
//
// Cheat here and put the whole original key into the CKA_VALUE... remember
// to force the system to not return this for RSA keys..
// Add the modulus to the private key information
#ifdef OLDER_OPENSSL
bignum = rsa->n;
#else
RSA_get0_key(rsa, &bignum, NULL, NULL);
#endif
BNLength = BN_num_bytes(bignum);
ssl_ptr = malloc(BNLength);
if (ssl_ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
BNLength = BN_bn2bin(bignum, ssl_ptr);
rc = build_attribute(CKA_MODULUS, ssl_ptr, BNLength, &attr); // in bytes
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(priv_tmpl, attr);
free(ssl_ptr);
ssl_ptr = NULL;
// Private Exponent
#ifdef OLDER_OPENSSL
bignum = rsa->d;
#else
RSA_get0_key(rsa, NULL, NULL, &bignum);
#endif
BNLength = BN_num_bytes(bignum);
ssl_ptr = malloc(BNLength);
if (ssl_ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
BNLength = BN_bn2bin(bignum, ssl_ptr);
rc = build_attribute(CKA_PRIVATE_EXPONENT, ssl_ptr, BNLength, &attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(priv_tmpl, attr);
OPENSSL_cleanse(ssl_ptr, BNLength);
free(ssl_ptr);
ssl_ptr = NULL;
// prime #1: p
//
#ifdef OLDER_OPENSSL
bignum = rsa->p;
#else
RSA_get0_factors(rsa, &bignum, NULL);
#endif
BNLength = BN_num_bytes(bignum);
ssl_ptr = malloc(BNLength);
if (ssl_ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
BNLength = BN_bn2bin(bignum, ssl_ptr);
rc = build_attribute(CKA_PRIME_1, ssl_ptr, BNLength, &attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(priv_tmpl, attr);
OPENSSL_cleanse(ssl_ptr, BNLength);
free(ssl_ptr);
ssl_ptr = NULL;
// prime #2: q
//
#ifdef OLDER_OPENSSL
bignum = rsa->q;
#else
RSA_get0_factors(rsa, NULL, &bignum);
#endif
BNLength = BN_num_bytes(bignum);
ssl_ptr = malloc(BNLength);
if (ssl_ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
BNLength = BN_bn2bin(bignum, ssl_ptr);
rc = build_attribute(CKA_PRIME_2, ssl_ptr, BNLength, &attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(priv_tmpl, attr);
OPENSSL_cleanse(ssl_ptr, BNLength);
free(ssl_ptr);
ssl_ptr = NULL;
// exponent 1: d mod(p-1)
//
#ifdef OLDER_OPENSSL
bignum = rsa->dmp1;
#else
RSA_get0_crt_params(rsa, &bignum, NULL, NULL);
#endif
BNLength = BN_num_bytes(bignum);
ssl_ptr = malloc(BNLength);
if (ssl_ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
BNLength = BN_bn2bin(bignum, ssl_ptr);
rc = build_attribute(CKA_EXPONENT_1, ssl_ptr, BNLength, &attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(priv_tmpl, attr);
OPENSSL_cleanse(ssl_ptr, BNLength);
free(ssl_ptr);
ssl_ptr = NULL;
// exponent 2: d mod(q-1)
//
#ifdef OLDER_OPENSSL
bignum = rsa->dmq1;
#else
RSA_get0_crt_params(rsa, NULL, &bignum, NULL);
#endif
BNLength = BN_num_bytes(bignum);
ssl_ptr = malloc(BNLength);
if (ssl_ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
BNLength = BN_bn2bin(bignum, ssl_ptr);
rc = build_attribute(CKA_EXPONENT_2, ssl_ptr, BNLength, &attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(priv_tmpl, attr);
OPENSSL_cleanse(ssl_ptr, BNLength);
free(ssl_ptr);
ssl_ptr = NULL;
// CRT coefficient: q_inverse mod(p)
//
#ifdef OLDER_OPENSSL
bignum = rsa->iqmp;
#else
RSA_get0_crt_params(rsa, NULL, NULL, &bignum);
#endif
BNLength = BN_num_bytes(bignum);
ssl_ptr = malloc(BNLength);
if (ssl_ptr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
BNLength = BN_bn2bin(bignum, ssl_ptr);
rc = build_attribute(CKA_COEFFICIENT, ssl_ptr, BNLength, &attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(priv_tmpl, attr);
OPENSSL_cleanse(ssl_ptr, BNLength);
free(ssl_ptr);
ssl_ptr = NULL;
flag = TRUE;
rc = build_attribute(CKA_LOCAL, &flag, sizeof(CK_BBOOL), &attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
goto done;
}
template_update_attribute(priv_tmpl, attr);
done:
#ifdef OLDER_OPENSSL
if (e != NULL)
BN_free(e);
if (rsa != NULL)
RSA_free(rsa);
if (ssl_ptr != NULL) {
OPENSSL_cleanse(ssl_ptr, BNLength);
free(ssl_ptr);
}
#else
if (ssl_ptr != NULL) {
OPENSSL_cleanse(ssl_ptr, BNLength);
free(ssl_ptr);
}
if (pkey != NULL)
EVP_PKEY_free(pkey);
if (ctx != NULL)
EVP_PKEY_CTX_free(ctx);
#endif
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(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(CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data, OBJECT *key_obj)
{
#ifdef OLDER_OPENSSL
CK_RV rc;
RSA *rsa;
int size;
// Convert the local representation to an RSA representation
rsa = (RSA *) rsa_convert_public_key(key_obj);
if (rsa == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
return rc;
}
// Do an RSA public encryption
size =
RSA_public_encrypt(in_data_len, in_data, out_data, rsa, RSA_NO_PADDING);
if (size == -1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_ARGUMENTS_BAD;
goto done;
}
rc = CKR_OK;
done:
RSA_free(rsa);
return rc;
#else
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
RSA *rsa = NULL;
CK_RV rc;
size_t outlen = in_data_len;
rsa = (RSA *)rsa_convert_public_key(key_obj);
if (rsa == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
return rc;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
if (EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
rsa = NULL; /* freed together with pkey */
ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
if (EVP_PKEY_encrypt_init(ctx) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (EVP_PKEY_encrypt(ctx, out_data, &outlen,
in_data, in_data_len) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
rc = CKR_OK;
done:
if (rsa != NULL)
RSA_free(rsa);
if (pkey != NULL)
EVP_PKEY_free(pkey);
if (ctx != NULL)
EVP_PKEY_CTX_free(ctx);
return rc;
#endif
}
static CK_RV os_specific_rsa_decrypt(CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data, OBJECT *key_obj)
{
#ifdef OLDER_OPENSSL
CK_RV rc;
RSA *rsa;
int size;
// Convert the local key representation to an RSA key representaion
rsa = (RSA *) rsa_convert_private_key(key_obj);
if (rsa == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
return rc;
}
// Do the private decryption
size =
RSA_private_decrypt(in_data_len, in_data, out_data, rsa,
RSA_NO_PADDING);
if (size == -1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
rc = CKR_OK;
done:
RSA_free(rsa);
return rc;
#else
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
RSA *rsa = NULL;
size_t outlen = in_data_len;
CK_RV rc;
rsa = (RSA *)rsa_convert_private_key(key_obj);
if (rsa == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
return rc;
}
pkey = EVP_PKEY_new();
if (pkey == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
if (EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
rsa = NULL; /* freed together with pkey */
ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
if (EVP_PKEY_decrypt_init(ctx) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (EVP_PKEY_decrypt(ctx, out_data, &outlen,
in_data, in_data_len) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rc = CKR_FUNCTION_FAILED;
goto done;
}
rc = CKR_OK;
done:
if (rsa != NULL)
RSA_free(rsa);
if (pkey != NULL)
EVP_PKEY_free(pkey);
if (ctx != NULL)
EVP_PKEY_CTX_free(ctx);
return rc;
#endif
}
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_ULONG modulus_bytes;
CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN];
CK_ATTRIBUTE *attr = NULL;
/* format the data */
if (!template_attribute_find(key_obj->template, CKA_MODULUS, &attr)) {
TRACE_ERROR("Could not find CKA_MODULUS for the key.\n");
return CKR_FUNCTION_FAILED;
}
modulus_bytes = attr->ulValueLen;
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");
goto done;
}
// Do an RSA public encryption
rc = os_specific_rsa_encrypt(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");
}
done:
OPENSSL_cleanse(clear, sizeof(clear));
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_RV rc;
CK_BYTE out[MAX_RSA_KEYLEN];
CK_ULONG modulus_bytes;
UNUSED(tokdata);
modulus_bytes = in_data_len;
rc = os_specific_rsa_decrypt(in_data, modulus_bytes, out, key_obj);
if (rc != CKR_OK) {
TRACE_DEVEL("os_specific_rsa_decrypt failed\n");
goto done;
}
rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_2);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_parse_block failed\n");
goto done;
}
/*
* For PKCS #1 v1.5 padding, out_data_len must be less than
* modulus_bytes - 11.
*/
if (*out_data_len > (modulus_bytes - 11)) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE));
rc = CKR_ENCRYPTED_DATA_LEN_RANGE;
}
done:
OPENSSL_cleanse(out, sizeof(out));
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_BYTE data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN];
CK_ULONG modulus_bytes;
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
UNUSED(tokdata);
UNUSED(sess);
/* format the data */
if (!template_attribute_find(key_obj->template, CKA_MODULUS, &attr)) {
TRACE_ERROR("Could not find CKA_MODULUS for the key.\n");
return CKR_FUNCTION_FAILED;
}
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(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_ATTRIBUTE *attr = NULL;
CK_BYTE out[MAX_RSA_KEYLEN], out_data[MAX_RSA_KEYLEN];
CK_ULONG modulus_bytes, out_data_len;
CK_BBOOL flag;
CK_RV rc;
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;
}
// verifying is a public key operation --> encrypt
//
rc = os_specific_rsa_encrypt(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.
*/
if (rc == CKR_ARGUMENTS_BAD) {
TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID));
rc = CKR_SIGNATURE_INVALID;
} else {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
}
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_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 rc;
}
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_ATTRIBUTE *attr = NULL;
CK_BYTE out[MAX_RSA_KEYLEN];
CK_ULONG modulus_bytes;
CK_BBOOL flag;
CK_RV rc;
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;
}
// verifying is a public key operation --> encrypt
//
rc = os_specific_rsa_encrypt(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_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
}
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(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(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;
}
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_ATTRIBUTE *attr = NULL;
CK_BYTE clear[MAX_RSA_KEYLEN], cipher[MAX_RSA_KEYLEN];
CK_ULONG modulus_bytes;
CK_BBOOL flag;
CK_RV rc;
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");
rc = CKR_FUNCTION_FAILED;
goto done;
}
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(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");
}
done:
OPENSSL_cleanse(clear, sizeof(clear));
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_ATTRIBUTE *attr = NULL;
CK_BYTE out[MAX_RSA_KEYLEN];
CK_ULONG modulus_bytes;
CK_BBOOL flag;
CK_RV rc;
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");
rc = CKR_FUNCTION_FAILED;
goto done;
}
modulus_bytes = attr->ulValueLen;
rc = os_specific_rsa_decrypt(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");
}
done:
OPENSSL_cleanse(out, sizeof(out));
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_ATTRIBUTE *attr = NULL;
CK_BYTE data[MAX_RSA_KEYLEN], sig[MAX_RSA_KEYLEN];
CK_ULONG modulus_bytes;
CK_BBOOL flag;
CK_RV rc;
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(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_ATTRIBUTE *attr = NULL;
CK_BYTE out[MAX_RSA_KEYLEN];
CK_ULONG modulus_bytes;
CK_BBOOL flag;
CK_RV rc;
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(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_ATTRIBUTE *attr = NULL;
CK_BYTE out[MAX_RSA_KEYLEN];
CK_ULONG modulus_bytes;
CK_BBOOL flag;
CK_RV rc;
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(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;
}
modulus_bytes = attr->ulValueLen;
/* pkcs1v2.2, section 7.1.1 Step 2:
* EME-OAEP encoding.
*/
em_data = (CK_BYTE *) malloc(modulus_bytes * sizeof(CK_BYTE));
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(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) {
OPENSSL_cleanse(em_data, modulus_bytes * sizeof(CK_BYTE));
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("%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 error;
}
*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 error;
}
rc = os_specific_rsa_decrypt(in_data, in_data_len, decr_data, key_obj);
if (rc != CKR_OK)
goto error;
/* 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);
error:
if (decr_data) {
OPENSSL_cleanse(decr_data, in_data_len);
free(decr_data);
}
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)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
AES_KEY ssl_aes_key;
unsigned int i;
CK_ATTRIBUTE *attr = NULL;
/* There's a previous check that in_data_len % AES_BLOCK_SIZE == 0,
* so this is fine */
CK_ULONG loops = (CK_ULONG) (in_data_len / AES_BLOCK_SIZE);
UNUSED(tokdata);
memset(&ssl_aes_key, 0, sizeof(AES_KEY));
// get 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;
}
// AES_ecb_encrypt encrypts only a single block, so we have to break up the
// input data here
if (encrypt) {
AES_set_encrypt_key((unsigned char *) attr->pValue,
(attr->ulValueLen * 8), &ssl_aes_key);
for (i = 0; i < loops; i++) {
AES_ecb_encrypt((unsigned char *) in_data + (i * AES_BLOCK_SIZE),
(unsigned char *) out_data + (i * AES_BLOCK_SIZE),
&ssl_aes_key, AES_ENCRYPT);
}
} else {
AES_set_decrypt_key((unsigned char *) attr->pValue,
(attr->ulValueLen * 8), &ssl_aes_key);
for (i = 0; i < loops; i++) {
AES_ecb_encrypt((unsigned char *) in_data + (i * AES_BLOCK_SIZE),
(unsigned char *) out_data + (i * AES_BLOCK_SIZE),
&ssl_aes_key, AES_DECRYPT);
}
}
*out_data_len = in_data_len;
return CKR_OK;
#else
CK_RV rc;
int outlen;
unsigned char akey[32];
const EVP_CIPHER *cipher = NULL;
EVP_CIPHER_CTX *ctx = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_ULONG keylen;
UNUSED(tokdata);
// get the key value
if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) {
TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n");
return CKR_FUNCTION_FAILED;
}
keylen = attr->ulValueLen;
if (keylen == 128 / 8)
cipher = EVP_aes_128_ecb();
else if (keylen == 192 / 8)
cipher = EVP_aes_192_ecb();
else if (keylen == 256 / 8)
cipher = EVP_aes_256_ecb();
memcpy(akey, attr->pValue, keylen);
if (in_data_len % AES_BLOCK_SIZE || in_data_len > INT_MAX) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
rc = CKR_DATA_LEN_RANGE;
goto done;
}
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = ERR_HOST_MEMORY;
goto done;
}
if (EVP_CipherInit_ex(ctx, cipher,
NULL, akey, NULL, encrypt ? 1 : 0) != 1
|| EVP_CIPHER_CTX_set_padding(ctx, 0) != 1
|| EVP_CipherUpdate(ctx, out_data, &outlen, in_data, in_data_len) != 1
|| EVP_CipherFinal_ex(ctx, out_data, &outlen) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR));
rc = ERR_GENERAL_ERROR;
goto done;
}
*out_data_len = in_data_len;
rc = CKR_OK;
done:
OPENSSL_cleanse(akey, sizeof(akey));
EVP_CIPHER_CTX_free(ctx);
return rc;
#endif
}
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)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
AES_KEY ssl_aes_key;
CK_ATTRIBUTE *attr = NULL;
UNUSED(tokdata);
memset(&ssl_aes_key, 0, sizeof(AES_KEY));
// get 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;
}
// AES_cbc_encrypt chunks the data into AES_BLOCK_SIZE blocks, unlike
// AES_ecb_encrypt, so no looping required.
if (encrypt) {
AES_set_encrypt_key((unsigned char *) attr->pValue,
(attr->ulValueLen * 8), &ssl_aes_key);
AES_cbc_encrypt((unsigned char *) in_data, (unsigned char *) out_data,
in_data_len, &ssl_aes_key, init_v, AES_ENCRYPT);
} else {
AES_set_decrypt_key((unsigned char *) attr->pValue,
(attr->ulValueLen * 8), &ssl_aes_key);
AES_cbc_encrypt((unsigned char *) in_data, (unsigned char *) out_data,
in_data_len, &ssl_aes_key, init_v, AES_DECRYPT);
}
*out_data_len = in_data_len;
return CKR_OK;
#else
CK_RV rc;
int outlen;
unsigned char akey[32];
const EVP_CIPHER *cipher = NULL;
EVP_CIPHER_CTX *ctx = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_ULONG keylen;
UNUSED(tokdata);
// get the key value
if (template_attribute_find(key->template, CKA_VALUE, &attr) == FALSE) {
TRACE_ERROR("template_attribute_find(CKA_VALUE) failed.\n");
return CKR_FUNCTION_FAILED;
}
keylen = attr->ulValueLen;
if (keylen == 128 / 8)
cipher = EVP_aes_128_cbc();
else if (keylen == 192 / 8)
cipher = EVP_aes_192_cbc();
else if (keylen == 256 / 8)
cipher = EVP_aes_256_cbc();
memcpy(akey, attr->pValue, keylen);
if (in_data_len % AES_BLOCK_SIZE || in_data_len > INT_MAX) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
rc = CKR_DATA_LEN_RANGE;
goto done;
}
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = ERR_HOST_MEMORY;
goto done;
}
if (EVP_CipherInit_ex(ctx, cipher,
NULL, akey, init_v, encrypt ? 1 : 0) != 1
|| EVP_CIPHER_CTX_set_padding(ctx, 0) != 1
|| EVP_CipherUpdate(ctx, out_data, &outlen, in_data, in_data_len) != 1
|| EVP_CipherFinal_ex(ctx, out_data, &outlen) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_GENERAL_ERROR));
rc = ERR_GENERAL_ERROR;
goto done;
}
*out_data_len = in_data_len;
rc = CKR_OK;
done:
OPENSSL_cleanse(akey, sizeof(akey));
EVP_CIPHER_CTX_free(ctx);
return rc;
#endif
}
CK_RV token_specific_aes_mac(STDLL_TokData_t *tokdata, CK_BYTE *message,
CK_ULONG message_len, OBJECT *key, CK_BYTE *mac)
{
CK_BYTE *out_buf;
CK_ULONG out_len;
CK_RV rc;
out_buf = malloc(message_len);
if (out_buf == NULL) {
TRACE_ERROR("Malloc failed.\n");
return CKR_HOST_MEMORY;
}
rc = token_specific_aes_cbc(tokdata, message, message_len, out_buf,
&out_len, key, mac, 1);
if (rc == CKR_OK && out_len >= AES_BLOCK_SIZE)
memcpy(mac, out_buf + out_len - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
free(out_buf);
return rc;
}
#endif
/* Begin code contributed by Corrent corp. */
#ifndef NODH
// This computes DH shared secret, where:
// Output: z is computed shared secret
// Input: y is other party's public key
// x is private key
// p is prime
// All length's are in number of bytes. All data comes in as Big Endian.
CK_RV token_specific_dh_pkcs_derive(STDLL_TokData_t *tokdata,
CK_BYTE *z,
CK_ULONG *z_len,
CK_BYTE *y,
CK_ULONG y_len,
CK_BYTE *x,
CK_ULONG x_len, CK_BYTE *p, CK_ULONG p_len)
{
CK_RV rc;
BIGNUM *bn_z, *bn_y, *bn_x, *bn_p;
BN_CTX *ctx;
UNUSED(tokdata);
// Create and Init the BIGNUM structures.
bn_y = BN_new();
bn_x = BN_new();
bn_p = BN_new();
bn_z = BN_new();
if (bn_z == NULL || bn_p == NULL || bn_x == NULL || bn_y == NULL) {
if (bn_y)
BN_free(bn_y);
if (bn_x)
BN_free(bn_x);
if (bn_p)
BN_free(bn_p);
if (bn_z)
BN_free(bn_z);
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
// Initialize context
ctx = BN_CTX_new();
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
return CKR_FUNCTION_FAILED;
}
// Add data into these new BN structures
BN_bin2bn((unsigned char *) y, y_len, bn_y);
BN_bin2bn((unsigned char *) x, x_len, bn_x);
BN_bin2bn((unsigned char *) p, p_len, bn_p);
rc = BN_mod_exp(bn_z, bn_y, bn_x, bn_p, ctx);
if (rc == 0) {
BN_free(bn_z);
BN_free(bn_y);
BN_free(bn_x);
BN_free(bn_p);
BN_CTX_free(ctx);
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
return CKR_FUNCTION_FAILED;
}
*z_len = BN_num_bytes(bn_z);
BN_bn2bin(bn_z, z);
BN_free(bn_z);
BN_free(bn_y);
BN_free(bn_x);
BN_free(bn_p);
BN_CTX_free(ctx);
return CKR_OK;
} /* end token_specific_dh_pkcs_derive() */
// This computes DH key pair, where:
// Output: priv_tmpl is generated private key
// pub_tmpl is computed public key
// Input: pub_tmpl is public key (prime and generator)
// All length's are in number of bytes. All data comes in as Big Endian.
CK_RV token_specific_dh_pkcs_key_pair_gen(STDLL_TokData_t *tokdata,
TEMPLATE *publ_tmpl,
TEMPLATE *priv_tmpl)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
CK_BBOOL rc;
CK_ATTRIBUTE *prime_attr = NULL;
CK_ATTRIBUTE *base_attr = NULL;
CK_ATTRIBUTE *temp_attr = NULL;
CK_ATTRIBUTE *value_bits_attr = NULL;
CK_BYTE *temp_byte;
CK_ULONG temp_bn_len;
DH *dh;
BIGNUM *bn_p;
BIGNUM *bn_g;
const BIGNUM *temp_bn;
UNUSED(tokdata);
rc = template_attribute_find(publ_tmpl, CKA_PRIME, &prime_attr);
rc &= template_attribute_find(publ_tmpl, CKA_BASE, &base_attr);
if (rc == FALSE) {
TRACE_ERROR("Could not find CKA_PRIME or CKA_BASE for the key\n");
return CKR_FUNCTION_FAILED;
}
if ((prime_attr->ulValueLen > 256) || (prime_attr->ulValueLen < 64)) {
TRACE_ERROR("CKA_PRIME attribute value is invalid.\n");
return CKR_ATTRIBUTE_VALUE_INVALID;
}
dh = DH_new();
if (dh == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
return CKR_FUNCTION_FAILED;
}
// Create and init BIGNUM structs to stick in the DH struct
bn_p = BN_new();
bn_g = BN_new();
if (bn_g == NULL || bn_p == NULL) {
if (bn_g)
BN_free(bn_g);
if (bn_p)
BN_free(bn_p);
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
// Convert from strings to BIGNUMs and stick them in the DH struct
BN_bin2bn((unsigned char *) prime_attr->pValue, prime_attr->ulValueLen,
bn_p);
BN_bin2bn((unsigned char *) base_attr->pValue, base_attr->ulValueLen, bn_g);
dh->p = bn_p;
dh->g = bn_g;
// Generate the DH Key
if (!DH_generate_key(dh)) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
DH_free(dh);
return CKR_FUNCTION_FAILED;
}
// Extract the public and private key components from the DH struct,
// and insert them in the publ_tmpl and priv_tmpl
//
// pub_key
//
//temp_bn = BN_new();
temp_bn = dh->pub_key;
temp_bn_len = BN_num_bytes(temp_bn);
temp_byte = malloc(temp_bn_len);
temp_bn_len = BN_bn2bin(temp_bn, temp_byte);
// in bytes
rc = build_attribute(CKA_VALUE, temp_byte, temp_bn_len, &temp_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
DH_free(dh);
free(temp_byte);
return CKR_FUNCTION_FAILED;
}
template_update_attribute(publ_tmpl, temp_attr);
free(temp_byte);
//
// priv_key
//
//temp_bn = BN_new();
temp_bn = dh->priv_key;
temp_bn_len = BN_num_bytes(temp_bn);
temp_byte = malloc(temp_bn_len);
temp_bn_len = BN_bn2bin(temp_bn, temp_byte);
// in bytes
rc = build_attribute(CKA_VALUE, temp_byte, temp_bn_len, &temp_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
DH_free(dh);
free(temp_byte);
return CKR_FUNCTION_FAILED;
}
template_update_attribute(priv_tmpl, temp_attr);
free(temp_byte);
// Update CKA_VALUE_BITS attribute in the private key
value_bits_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG));
value_bits_attr->type = CKA_VALUE_BITS;
value_bits_attr->ulValueLen = sizeof(CK_ULONG);
value_bits_attr->pValue =
(CK_BYTE *) value_bits_attr + sizeof(CK_ATTRIBUTE);
*(CK_ULONG *) value_bits_attr->pValue = 8 * temp_bn_len;
template_update_attribute(priv_tmpl, value_bits_attr);
// Add prime and base to the private key template
rc = build_attribute(CKA_PRIME,
(unsigned char *) prime_attr->pValue,
prime_attr->ulValueLen, &temp_attr); // in bytes
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
DH_free(dh);
return CKR_FUNCTION_FAILED;
}
template_update_attribute(priv_tmpl, temp_attr);
rc = build_attribute(CKA_BASE,
(unsigned char *) base_attr->pValue,
base_attr->ulValueLen, &temp_attr); // in bytes
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
DH_free(dh);
return CKR_FUNCTION_FAILED;
}
template_update_attribute(priv_tmpl, temp_attr);
// Cleanup DH key
DH_free(dh);
return CKR_OK;
#else
CK_RV rv;
CK_BBOOL rc;
CK_ATTRIBUTE *prime_attr = NULL;
CK_ATTRIBUTE *base_attr = NULL;
CK_ATTRIBUTE *temp_attr = NULL;
CK_ATTRIBUTE *value_bits_attr = NULL;
CK_BYTE *temp_byte = NULL, *temp_byte2 = NULL;
CK_ULONG temp_bn_len;
DH *dh = NULL;
BIGNUM *bn_p = NULL;
BIGNUM *bn_g = NULL;
const BIGNUM *temp_bn = NULL;
EVP_PKEY *params = NULL, *pkey = NULL;
EVP_PKEY_CTX *ctx = NULL;
UNUSED(tokdata);
rc = template_attribute_find(publ_tmpl, CKA_PRIME, &prime_attr);
rc &= template_attribute_find(publ_tmpl, CKA_BASE, &base_attr);
if (rc == FALSE) {
TRACE_ERROR("Could not find CKA_PRIME or CKA_BASE for the key\n");
rv = CKR_FUNCTION_FAILED;
goto done;
}
if ((prime_attr->ulValueLen > 256) || (prime_attr->ulValueLen < 64)) {
TRACE_ERROR("CKA_PRIME attribute value is invalid.\n");
rv = CKR_ATTRIBUTE_VALUE_INVALID;
goto done;
}
dh = DH_new();
if (dh == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rv = CKR_FUNCTION_FAILED;
goto done;
}
// Create and init BIGNUM structs to stick in the DH struct
bn_p = BN_new();
bn_g = BN_new();
if (bn_g == NULL || bn_p == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rv = CKR_HOST_MEMORY;
goto done;
}
// Convert from strings to BIGNUMs and stick them in the DH struct
BN_bin2bn((unsigned char *) prime_attr->pValue, prime_attr->ulValueLen,
bn_p);
BN_bin2bn((unsigned char *) base_attr->pValue, base_attr->ulValueLen, bn_g);
DH_set0_pqg(dh, bn_p, NULL, bn_g);
/* bn_p and bn_q freed together with dh */
bn_p = NULL;
bn_g = NULL;
params = EVP_PKEY_new();
if (params == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rv = CKR_HOST_MEMORY;
goto done;
}
if (EVP_PKEY_assign_DH(params, dh) != 1) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rv = CKR_FUNCTION_FAILED;
goto done;
}
dh = NULL; /* freed together with params */
ctx = EVP_PKEY_CTX_new(params, NULL);
if (ctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rv = CKR_HOST_MEMORY;
goto done;
}
if (EVP_PKEY_keygen_init(ctx) != 1
|| EVP_PKEY_keygen(ctx, &pkey) != 1
/* dh is freed together with pkey */
|| (dh = EVP_PKEY_get0_DH(pkey)) == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rv = CKR_FUNCTION_FAILED;
goto done;
}
// Extract the public and private key components from the DH struct,
// and insert them in the publ_tmpl and priv_tmpl
//
// pub_key
//
DH_get0_key(dh, &temp_bn, NULL);
temp_bn_len = BN_num_bytes(temp_bn);
temp_byte = malloc(temp_bn_len);
temp_bn_len = BN_bn2bin(temp_bn, temp_byte);
// in bytes
rc = build_attribute(CKA_VALUE, temp_byte, temp_bn_len, &temp_attr);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
rv = CKR_FUNCTION_FAILED;
goto done;
}
template_update_attribute(publ_tmpl, temp_attr);
//
// priv_key
//
DH_get0_key(dh, NULL, &temp_bn);
temp_bn_len = BN_num_bytes(temp_bn);
temp_byte2 = malloc(temp_bn_len);
temp_bn_len = BN_bn2bin(temp_bn, temp_byte2);
// in bytes
rc = build_attribute(CKA_VALUE, temp_byte2, temp_bn_len, &temp_attr);
OPENSSL_cleanse(temp_byte2, temp_bn_len);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
rv = CKR_FUNCTION_FAILED;
goto done;
}
template_update_attribute(priv_tmpl, temp_attr);
// Update CKA_VALUE_BITS attribute in the private key
value_bits_attr =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) + sizeof(CK_ULONG));
if (value_bits_attr == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rv = CKR_HOST_MEMORY;
goto done;
}
value_bits_attr->type = CKA_VALUE_BITS;
value_bits_attr->ulValueLen = sizeof(CK_ULONG);
value_bits_attr->pValue =
(CK_BYTE *) value_bits_attr + sizeof(CK_ATTRIBUTE);
*(CK_ULONG *) value_bits_attr->pValue = 8 * temp_bn_len;
template_update_attribute(priv_tmpl, value_bits_attr);
// Add prime and base to the private key template
rc = build_attribute(CKA_PRIME,
(unsigned char *) prime_attr->pValue,
prime_attr->ulValueLen, &temp_attr); // in bytes
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
rv = CKR_FUNCTION_FAILED;
goto done;
}
template_update_attribute(priv_tmpl, temp_attr);
rc = build_attribute(CKA_BASE,
(unsigned char *) base_attr->pValue,
base_attr->ulValueLen, &temp_attr); // in bytes
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute failed\n");
rv = CKR_FUNCTION_FAILED;
goto done;
}
template_update_attribute(priv_tmpl, temp_attr);
rv = CKR_OK;
done:
if (bn_g != NULL)
BN_free(bn_g);
if (bn_p != NULL)
BN_free(bn_p);
if (pkey != NULL)
EVP_PKEY_free(pkey);
if (ctx != NULL)
EVP_PKEY_CTX_free(ctx);
free(temp_byte);
free(temp_byte2);
return rv;
#endif
} /* end token_specific_dh_key_pair_gen() */
#endif
/* End code contributed by Corrent corp. */
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);
}
CK_RV token_specific_sha_init(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx,
CK_MECHANISM *mech)
{
const EVP_MD *md = NULL;
UNUSED(tokdata);
ctx->context_len = 1; /* Dummy length, size of EVP_MD_CTX is unknown */
#if OPENSSL_VERSION_NUMBER < 0x10101000L
ctx->context = (CK_BYTE *)EVP_MD_CTX_create();
#else
ctx->context = (CK_BYTE *)EVP_MD_CTX_new();
#endif
if (ctx->context == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
switch (mech->mechanism) {
case CKM_SHA_1:
md = EVP_sha1();
break;
case CKM_SHA224:
md = EVP_sha224();
break;
case CKM_SHA256:
md = EVP_sha256();
break;
case CKM_SHA384:
md = EVP_sha384();
break;
case CKM_SHA512:
md = EVP_sha512();
break;
#ifdef NID_sha512_224WithRSAEncryption
case CKM_SHA512_224:
md = EVP_sha512_224();
break;
#endif
#ifdef NID_sha512_256WithRSAEncryption
case CKM_SHA512_256:
md = EVP_sha512_256();
break;
#endif
#ifdef NID_sha3_224
case CKM_IBM_SHA3_224:
md = EVP_sha3_224();
break;
#endif
#ifdef NID_sha3_256
case CKM_IBM_SHA3_256:
md = EVP_sha3_256();
break;
#endif
#ifdef NID_sha3_384
case CKM_IBM_SHA3_384:
md = EVP_sha3_384();
break;
#endif
#ifdef NID_sha3_512
case CKM_IBM_SHA3_512:
md = EVP_sha3_512();
break;
#endif
default:
break;
}
if (md == NULL ||
!EVP_DigestInit_ex((EVP_MD_CTX *)ctx->context, md, NULL)) {
#if OPENSSL_VERSION_NUMBER < 0x10101000L
EVP_MD_CTX_destroy((EVP_MD_CTX *)ctx->context);
#else
EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context);
#endif
ctx->context = NULL;
ctx->context_len = 0;
return CKR_FUNCTION_FAILED;
}
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)
{
unsigned int len;
CK_RV rc = CKR_OK;
UNUSED(tokdata);
if (!ctx || !ctx->context)
return CKR_OPERATION_NOT_INITIALIZED;
if (!in_data || !out_data)
return CKR_ARGUMENTS_BAD;
if (*out_data_len < (CK_ULONG)EVP_MD_CTX_size((EVP_MD_CTX *)ctx->context))
return CKR_BUFFER_TOO_SMALL;
if (!EVP_DigestUpdate((EVP_MD_CTX *)ctx->context, in_data, in_data_len) ||
!EVP_DigestFinal((EVP_MD_CTX *)ctx->context, out_data, &len)) {
rc = CKR_FUNCTION_FAILED;
goto out;
}
*out_data_len = len;
out:
#if OPENSSL_VERSION_NUMBER < 0x10101000L
EVP_MD_CTX_destroy((EVP_MD_CTX *)ctx->context);
#else
EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context);
#endif
ctx->context = NULL;
ctx->context_len = 0;
return rc;
}
CK_RV token_specific_sha_update(STDLL_TokData_t *tokdata, DIGEST_CONTEXT *ctx,
CK_BYTE *in_data, CK_ULONG in_data_len)
{
UNUSED(tokdata);
if (!ctx || !ctx->context)
return CKR_OPERATION_NOT_INITIALIZED;
if (!in_data)
return CKR_ARGUMENTS_BAD;
if (!EVP_DigestUpdate((EVP_MD_CTX *)ctx->context, in_data, in_data_len)) {
#if OPENSSL_VERSION_NUMBER < 0x10101000L
EVP_MD_CTX_destroy((EVP_MD_CTX *)ctx->context);
#else
EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context);
#endif
ctx->context = NULL;
ctx->context_len = 0;
return CKR_FUNCTION_FAILED;
}
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)
{
unsigned int len;
CK_RV rc = CKR_OK;
UNUSED(tokdata);
if (!ctx || !ctx->context)
return CKR_OPERATION_NOT_INITIALIZED;
if (!out_data)
return CKR_ARGUMENTS_BAD;
if (*out_data_len < (CK_ULONG)EVP_MD_CTX_size((EVP_MD_CTX *)ctx->context))
return CKR_BUFFER_TOO_SMALL;
if (!EVP_DigestFinal((EVP_MD_CTX *)ctx->context, out_data, &len)) {
rc = CKR_FUNCTION_FAILED;
goto out;
}
*out_data_len = len;
out:
#if OPENSSL_VERSION_NUMBER < 0x10101000L
EVP_MD_CTX_destroy((EVP_MD_CTX *)ctx->context);
#else
EVP_MD_CTX_free((EVP_MD_CTX *)ctx->context);
#endif
ctx->context = NULL;
ctx->context_len = 0;
return rc;
}
static CK_RV softtok_hmac_init(STDLL_TokData_t *tokdata,
SIGN_VERIFY_CONTEXT *ctx, CK_MECHANISM_PTR mech,
CK_OBJECT_HANDLE Hkey)
{
int rc;
OBJECT *key = NULL;
CK_ATTRIBUTE *attr = NULL;
EVP_MD_CTX *mdctx = NULL;
EVP_PKEY *pkey = NULL;
rc = object_mgr_find_in_map1(tokdata, Hkey, &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;
}
pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, attr->pValue,
attr->ulValueLen);
if (pkey == NULL) {
TRACE_ERROR("EVP_PKEY_new_mac_key() failed.\n");
rc = CKR_FUNCTION_FAILED;
goto done;
}
mdctx = EVP_MD_CTX_create();
if (mdctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
switch (mech->mechanism) {
case CKM_SHA_1_HMAC_GENERAL:
case CKM_SHA_1_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha1(), NULL, pkey);
break;
case CKM_SHA224_HMAC_GENERAL:
case CKM_SHA224_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha224(), NULL, pkey);
break;
case CKM_SHA256_HMAC_GENERAL:
case CKM_SHA256_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, pkey);
break;
case CKM_SHA384_HMAC_GENERAL:
case CKM_SHA384_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha384(), NULL, pkey);
break;
case CKM_SHA512_HMAC_GENERAL:
case CKM_SHA512_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha512(), NULL, pkey);
break;
#ifdef NID_sha512_224WithRSAEncryption
case CKM_SHA512_224_HMAC_GENERAL:
case CKM_SHA512_224_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha512_224(), NULL, pkey);
break;
#endif
#ifdef NID_sha512_256WithRSAEncryption
case CKM_SHA512_256_HMAC_GENERAL:
case CKM_SHA512_256_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha512_256(), NULL, pkey);
break;
#endif
#ifdef NID_sha3_224
case CKM_IBM_SHA3_224_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha3_224(), NULL, pkey);
break;
#endif
#ifdef NID_sha3_256
case CKM_IBM_SHA3_256_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha3_256(), NULL, pkey);
break;
#endif
#ifdef NID_sha3_384
case CKM_IBM_SHA3_384_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha3_384(), NULL, pkey);
break;
#endif
#ifdef NID_sha3_512
case CKM_IBM_SHA3_512_HMAC:
rc = EVP_DigestSignInit(mdctx, NULL, EVP_sha3_512(), NULL, pkey);
break;
#endif
default:
EVP_MD_CTX_destroy(mdctx);
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
if (rc != 1) {
EVP_MD_CTX_destroy(mdctx);
ctx->context = NULL;
TRACE_ERROR("EVP_DigestSignInit failed.\n");
rc = CKR_FUNCTION_FAILED;
goto done;
} else {
ctx->context = (CK_BYTE *) mdctx;
}
rc = CKR_OK;
done:
if (pkey != NULL)
EVP_PKEY_free(pkey);
object_put(tokdata, key, TRUE);
key = NULL;
return rc;
}
CK_RV token_specific_hmac_sign_init(STDLL_TokData_t *tokdata, SESSION *sess,
CK_MECHANISM *mech, CK_OBJECT_HANDLE Hkey)
{
return softtok_hmac_init(tokdata, &sess->sign_ctx, mech, Hkey);
}
CK_RV token_specific_hmac_verify_init(STDLL_TokData_t *tokdata, SESSION *sess,
CK_MECHANISM *mech,
CK_OBJECT_HANDLE Hkey)
{
return softtok_hmac_init(tokdata, &sess->verify_ctx, mech, Hkey);
}
static CK_RV softtok_hmac(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data,
CK_ULONG in_data_len, CK_BYTE *signature,
CK_ULONG *sig_len, CK_BBOOL sign)
{
int rc;
size_t mac_len, len;
unsigned char mac[MAX_SHA_HASH_SIZE];
EVP_MD_CTX *mdctx = NULL;
CK_RV rv = CKR_OK;
CK_BBOOL general = FALSE;
if (!ctx || !ctx->context) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
if (sign && !sig_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
switch (ctx->mech.mechanism) {
case CKM_SHA_1_HMAC_GENERAL:
general = TRUE;
/* fallthrough */
case CKM_SHA_1_HMAC:
mac_len = SHA1_HASH_SIZE;
break;
case CKM_SHA224_HMAC_GENERAL:
#ifdef NID_sha512_224WithRSAEncryption
case CKM_SHA512_224_HMAC_GENERAL:
#endif
general = TRUE;
/* fallthrough */
case CKM_SHA224_HMAC:
#ifdef NID_sha512_224WithRSAEncryption
case CKM_SHA512_224_HMAC:
#endif
mac_len = SHA224_HASH_SIZE;
break;
case CKM_SHA256_HMAC_GENERAL:
#ifdef NID_sha512_256WithRSAEncryption
case CKM_SHA512_256_HMAC_GENERAL:
#endif
general = TRUE;
/* fallthrough */
case CKM_SHA256_HMAC:
#ifdef NID_sha512_256WithRSAEncryption
case CKM_SHA512_256_HMAC:
#endif
mac_len = SHA256_HASH_SIZE;
break;
case CKM_SHA384_HMAC_GENERAL:
general = TRUE;
/* fallthrough */
case CKM_SHA384_HMAC:
mac_len = SHA384_HASH_SIZE;
break;
case CKM_SHA512_HMAC_GENERAL:
general = TRUE;
/* fallthrough */
case CKM_SHA512_HMAC:
mac_len = SHA512_HASH_SIZE;
break;
#ifdef NID_sha3_224
case CKM_IBM_SHA3_224_HMAC:
mac_len = SHA3_224_HASH_SIZE;
break;
#endif
#ifdef NID_sha3_256
case CKM_IBM_SHA3_256_HMAC:
mac_len = SHA3_256_HASH_SIZE;
break;
#endif
#ifdef NID_sha3_384
case CKM_IBM_SHA3_384_HMAC:
mac_len = SHA3_384_HASH_SIZE;
break;
#endif
#ifdef NID_sha3_512
case CKM_IBM_SHA3_512_HMAC:
mac_len = SHA3_512_HASH_SIZE;
break;
#endif
default:
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
return CKR_MECHANISM_INVALID;
}
mdctx = (EVP_MD_CTX *) ctx->context;
rc = EVP_DigestSignUpdate(mdctx, in_data, in_data_len);
if (rc != 1) {
TRACE_ERROR("EVP_DigestSignUpdate failed.\n");
rv = CKR_FUNCTION_FAILED;
goto done;
}
rc = EVP_DigestSignFinal(mdctx, mac, &mac_len);
if (rc != 1) {
TRACE_ERROR("EVP_DigestSignFinal failed.\n");
rv = CKR_FUNCTION_FAILED;
goto done;
}
if (sign) {
if (general)
*sig_len = *(CK_ULONG *) ctx->mech.pParameter;
else
*sig_len = mac_len;
memcpy(signature, mac, *sig_len);
} else {
if (general)
len = *(CK_ULONG *) ctx->mech.pParameter;
else
len = mac_len;
if (CRYPTO_memcmp(signature, mac, len) != 0) {
TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID));
rv = CKR_SIGNATURE_INVALID;
}
}
done:
EVP_MD_CTX_destroy(mdctx);
ctx->context = NULL;
return rv;
}
CK_RV token_specific_hmac_sign(STDLL_TokData_t *tokdata, SESSION *sess,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG *sig_len)
{
UNUSED(tokdata);
return softtok_hmac(&sess->sign_ctx, in_data, in_data_len, signature,
sig_len, TRUE);
}
CK_RV token_specific_hmac_verify(STDLL_TokData_t *tokdata, SESSION *sess,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG sig_len)
{
UNUSED(tokdata);
return softtok_hmac(&sess->verify_ctx, in_data, in_data_len, signature,
&sig_len, FALSE);
}
static CK_RV softtok_hmac_update(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data,
CK_ULONG in_data_len, CK_BBOOL sign)
{
int rc;
EVP_MD_CTX *mdctx = NULL;
CK_RV rv = CKR_OK;
UNUSED(sign);
if (!ctx || !ctx->context)
return CKR_OPERATION_NOT_INITIALIZED;
mdctx = (EVP_MD_CTX *) ctx->context;
rc = EVP_DigestSignUpdate(mdctx, in_data, in_data_len);
if (rc != 1) {
TRACE_ERROR("EVP_DigestSignUpdate failed.\n");
rv = CKR_FUNCTION_FAILED;
} else {
ctx->context = (CK_BYTE *) mdctx;
return CKR_OK;
}
EVP_MD_CTX_destroy(mdctx);
ctx->context = NULL;
return rv;
}
CK_RV token_specific_hmac_sign_update(STDLL_TokData_t *tokdata, SESSION *sess,
CK_BYTE *in_data, CK_ULONG in_data_len)
{
UNUSED(tokdata);
return softtok_hmac_update(&sess->sign_ctx, in_data, in_data_len, TRUE);
}
CK_RV token_specific_hmac_verify_update(STDLL_TokData_t *tokdata,
SESSION *sess, CK_BYTE *in_data,
CK_ULONG in_data_len)
{
UNUSED(tokdata);
return softtok_hmac_update(&sess->verify_ctx, in_data, in_data_len, FALSE);
}
static CK_RV softtok_hmac_final(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *signature,
CK_ULONG *sig_len, CK_BBOOL sign)
{
int rc;
size_t mac_len, len;
unsigned char mac[MAX_SHA_HASH_SIZE];
EVP_MD_CTX *mdctx = NULL;
CK_RV rv = CKR_OK;
CK_BBOOL general = FALSE;
if (!ctx || !ctx->context)
return CKR_OPERATION_NOT_INITIALIZED;
if (sign && !sig_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
switch (ctx->mech.mechanism) {
case CKM_SHA_1_HMAC_GENERAL:
general = TRUE;
/* fallthrough */
case CKM_SHA_1_HMAC:
mac_len = SHA1_HASH_SIZE;
break;
case CKM_SHA224_HMAC_GENERAL:
general = TRUE;
/* fallthrough */
case CKM_SHA224_HMAC:
mac_len = SHA224_HASH_SIZE;
break;
case CKM_SHA256_HMAC_GENERAL:
general = TRUE;
/* fallthrough */
case CKM_SHA256_HMAC:
mac_len = SHA256_HASH_SIZE;
break;
case CKM_SHA384_HMAC_GENERAL:
general = TRUE;
/* fallthrough */
case CKM_SHA384_HMAC:
mac_len = SHA384_HASH_SIZE;
break;
case CKM_SHA512_HMAC_GENERAL:
general = TRUE;
/* fallthrough */
case CKM_SHA512_HMAC:
mac_len = SHA512_HASH_SIZE;
break;
#ifdef NID_sha3_224
case CKM_IBM_SHA3_224_HMAC:
mac_len = SHA3_224_HASH_SIZE;
break;
#endif
#ifdef NID_sha3_256
case CKM_IBM_SHA3_256_HMAC:
mac_len = SHA3_256_HASH_SIZE;
break;
#endif
#ifdef NID_sha3_384
case CKM_IBM_SHA3_384_HMAC:
mac_len = SHA3_384_HASH_SIZE;
break;
#endif
#ifdef NID_sha3_512
case CKM_IBM_SHA3_512_HMAC:
mac_len = SHA3_512_HASH_SIZE;
break;
#endif
default:
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
return CKR_MECHANISM_INVALID;
}
if (signature == NULL) {
if (sign) {
if (general)
*sig_len = *(CK_ULONG *) ctx->mech.pParameter;
else
*sig_len = (CK_ULONG) mac_len;
}
return CKR_OK;
}
mdctx = (EVP_MD_CTX *) ctx->context;
rc = EVP_DigestSignFinal(mdctx, mac, &mac_len);
if (rc != 1) {
TRACE_ERROR("EVP_DigestSignFinal failed.\n");
rv = CKR_FUNCTION_FAILED;
goto done;
}
if (sign) {
if (general)
*sig_len = *(CK_ULONG *) ctx->mech.pParameter;
else
*sig_len = mac_len;
memcpy(signature, mac, *sig_len);
} else {
if (general)
len = *(CK_ULONG *) ctx->mech.pParameter;
else
len = mac_len;
if (CRYPTO_memcmp(signature, mac, len) != 0) {
TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID));
rv = CKR_SIGNATURE_INVALID;
}
}
done:
EVP_MD_CTX_destroy(mdctx);
ctx->context = NULL;
return rv;
}
CK_RV token_specific_hmac_sign_final(STDLL_TokData_t *tokdata, SESSION *sess,
CK_BYTE *signature, CK_ULONG *sig_len)
{
UNUSED(tokdata);
return softtok_hmac_final(&sess->sign_ctx, signature, sig_len, TRUE);
}
CK_RV token_specific_hmac_verify_final(STDLL_TokData_t *tokdata,
SESSION *sess, CK_BYTE *signature,
CK_ULONG sig_len)
{
UNUSED(tokdata);
return softtok_hmac_final(&sess->verify_ctx, signature, &sig_len, FALSE);
}
CK_RV token_specific_generic_secret_key_gen(STDLL_TokData_t *tokdata,
TEMPLATE *tmpl)
{
CK_ATTRIBUTE *attr = NULL;
CK_ATTRIBUTE *gkey = 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;
rc = template_attribute_find(tmpl, CKA_VALUE_LEN, &attr);
if (rc == FALSE) {
TRACE_ERROR("CKA_VALUE_LEN missing in (HMAC) key template\n");
return CKR_TEMPLATE_INCOMPLETE;
}
//app specified key length in bytes
key_length = *(CK_ULONG *) attr->pValue;
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. openssl does not explicitly
* specify limits to key sizes for secret keys
*/
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;
}
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, &gkey);
if (rc != CKR_OK) {
TRACE_DEVEL("build_attribute(CKA_VALUE) failed\n");
return rc;
}
rc = template_update_attribute(tmpl, gkey);
if (rc != CKR_OK)
TRACE_DEVEL("template_update_attribute(CKA_VALUE) failed.\n");
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)
{
#if OPENSSL_VERSION_NUMBER < 0x10101000L
int rc;
CK_RV rv = CKR_OK;
CK_ATTRIBUTE *attr = NULL;
CK_KEY_TYPE keytype;
CMAC_CTX *cmac_ctx;
const EVP_CIPHER *cipher;
size_t maclen;
UNUSED(tokdata);
if (first) {
// 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;
}
switch (keytype) {
case CKK_DES2:
cipher = EVP_des_ede_cbc();
break;
case CKK_DES3:
cipher = EVP_des_ede3_cbc();
break;
default:
TRACE_ERROR("Invalid key type: %lu\n", keytype);
return CKR_KEY_TYPE_INCONSISTENT;
}
if (cipher == NULL) {
TRACE_ERROR("Failed to allocate cipher\n");
return CKR_HOST_MEMORY;
}
cmac_ctx = CMAC_CTX_new();
if (cmac_ctx == NULL) {
TRACE_ERROR("Failed to allocate CMAC context\n");
return CKR_HOST_MEMORY;
}
rc = CMAC_Init(cmac_ctx, attr->pValue, attr->ulValueLen, cipher, NULL);
if (rc != 1) {
TRACE_ERROR("CMAC_Init failed\n");
CMAC_CTX_free(cmac_ctx);
return CKR_FUNCTION_FAILED;
}
*ctx = cmac_ctx;
}
cmac_ctx = (CMAC_CTX *)*ctx;
rc = CMAC_Update(cmac_ctx, message, message_len);
if (rc != 1) {
TRACE_ERROR("CMAC_Update failed\n");
rv = CKR_FUNCTION_FAILED;
}
if (last) {
maclen = AES_BLOCK_SIZE;
rc = CMAC_Final(cmac_ctx, mac, &maclen);
if (rc != 1) {
TRACE_ERROR("CMAC_Final failed\n");
rv = CKR_FUNCTION_FAILED;
}
}
if (last || (first && rv != CKR_OK)) {
CMAC_CTX_free(cmac_ctx);
*ctx = NULL;
}
return rv;
#else
int rc;
size_t maclen;
CK_RV rv = CKR_OK;
CK_ATTRIBUTE *attr = NULL;
CK_KEY_TYPE keytype;
const EVP_CIPHER *cipher;
struct cmac_ctx {
EVP_MD_CTX *mctx;
EVP_PKEY_CTX *pctx;
EVP_PKEY *pkey;
};
struct cmac_ctx *cmac = NULL;
UNUSED(tokdata);
if (first) {
// 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");
rv = CKR_FUNCTION_FAILED;
goto err;
}
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");
rv = CKR_FUNCTION_FAILED;
goto err;
}
switch (keytype) {
case CKK_DES2:
cipher = EVP_des_ede_cbc();
break;
case CKK_DES3:
cipher = EVP_des_ede3_cbc();
break;
default:
TRACE_ERROR("Invalid key type: %lu\n", keytype);
rv = CKR_KEY_TYPE_INCONSISTENT;
goto err;
}
cmac = calloc(1, sizeof(*cmac));
if (cmac == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rv = ERR_HOST_MEMORY;
goto err;
}
cmac->mctx = EVP_MD_CTX_new();
if (cmac->mctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rv = ERR_HOST_MEMORY;
goto err;
}
cmac->pkey = EVP_PKEY_new_CMAC_key(NULL,
attr->pValue, attr->ulValueLen,
cipher);
if (cmac->pkey == NULL) {
TRACE_ERROR("EVP_DigestSignInit failed\n");
rv = CKR_FUNCTION_FAILED;
goto err;
}
if (EVP_DigestSignInit(cmac->mctx, &cmac->pctx,
NULL, NULL, cmac->pkey) != 1) {
TRACE_ERROR("EVP_DigestSignInit failed\n");
rv = CKR_FUNCTION_FAILED;
goto err;
}
*ctx = cmac;
}
cmac = (struct cmac_ctx *)*ctx;
if (cmac == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rv = CKR_FUNCTION_FAILED;
goto err;
}
rc = EVP_DigestSignUpdate(cmac->mctx, message, message_len);
if (rc != 1 || message_len > INT_MAX) {
TRACE_ERROR("EVP_DigestSignUpdate failed\n");
rv = CKR_FUNCTION_FAILED;
goto err;
}
if (last) {
maclen = AES_BLOCK_SIZE;
rc = EVP_DigestSignFinal(cmac->mctx, mac, &maclen);
if (rc != 1) {
TRACE_ERROR("EVP_DigestSignFinal failed\n");
rv = CKR_FUNCTION_FAILED;
goto err;
}
EVP_MD_CTX_free(cmac->mctx); /* frees pctx */
EVP_PKEY_free(cmac->pkey);
free(cmac);
*ctx = NULL;
}
return CKR_OK;
err:
if (cmac != NULL) {
if (cmac->mctx != NULL)
EVP_MD_CTX_free(cmac->mctx); /* frees pctx */
if (cmac->pkey != NULL)
EVP_PKEY_free(cmac->pkey);
free(cmac);
}
*ctx = NULL;
return rv;
#endif
}
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)
{
#if OPENSSL_VERSION_NUMBER < 0x10101000L
int rc;
CK_RV rv = CKR_OK;
CK_ATTRIBUTE *attr = NULL;
CMAC_CTX *cmac_ctx;
const EVP_CIPHER *cipher;
size_t maclen;
UNUSED(tokdata);
if (first) {
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;
}
switch (attr->ulValueLen * 8) {
case 128:
cipher = EVP_aes_128_cbc();
break;
case 192:
cipher = EVP_aes_192_cbc();
break;
case 256:
cipher = EVP_aes_256_cbc();
break;
default:
TRACE_ERROR("Invalid key size: %lu\n", attr->ulValueLen);
return CKR_KEY_TYPE_INCONSISTENT;
}
if (cipher == NULL) {
TRACE_ERROR("Failed to allocate cipher\n");
return CKR_HOST_MEMORY;
}
cmac_ctx = CMAC_CTX_new();
if (cmac_ctx == NULL) {
TRACE_ERROR("Failed to allocate CMAC context\n");
return CKR_HOST_MEMORY;
}
rc = CMAC_Init(cmac_ctx, attr->pValue, attr->ulValueLen, cipher, NULL);
if (rc != 1) {
TRACE_ERROR("CMAC_Init failed\n");
CMAC_CTX_free(cmac_ctx);
return CKR_FUNCTION_FAILED;
}
*ctx = cmac_ctx;
}
cmac_ctx = (CMAC_CTX *)*ctx;
rc = CMAC_Update(cmac_ctx, message, message_len);
if (rc != 1) {
TRACE_ERROR("CMAC_Update failed\n");
rv = CKR_FUNCTION_FAILED;
}
if (last) {
maclen = AES_BLOCK_SIZE;
rc = CMAC_Final(cmac_ctx, mac, &maclen);
if (rc != 1) {
TRACE_ERROR("CMAC_Final failed\n");
rv = CKR_FUNCTION_FAILED;
}
}
if (last || (first && rv != CKR_OK)) {
CMAC_CTX_free(cmac_ctx);
*ctx = NULL;
}
return rv;
#else
int rc;
size_t maclen;
CK_RV rv = CKR_OK;
CK_ATTRIBUTE *attr = NULL;
const EVP_CIPHER *cipher;
struct cmac_ctx {
EVP_MD_CTX *mctx;
EVP_PKEY_CTX *pctx;
EVP_PKEY *pkey;
};
struct cmac_ctx *cmac = NULL;
UNUSED(tokdata);
if (first) {
// 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");
rv = CKR_FUNCTION_FAILED;
goto err;
}
switch (attr->ulValueLen * 8) {
case 128:
cipher = EVP_aes_128_cbc();
break;
case 192:
cipher = EVP_aes_192_cbc();
break;
case 256:
cipher = EVP_aes_256_cbc();
break;
default:
TRACE_ERROR("Invalid key size: %lu\n", attr->ulValueLen);
return CKR_KEY_TYPE_INCONSISTENT;
}
cmac = calloc(1, sizeof(*cmac));
if (cmac == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rv = ERR_HOST_MEMORY;
goto err;
}
cmac->mctx = EVP_MD_CTX_new();
if (cmac->mctx == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rv = ERR_HOST_MEMORY;
goto err;
}
cmac->pkey = EVP_PKEY_new_CMAC_key(NULL,
attr->pValue, attr->ulValueLen,
cipher);
if (cmac->pkey == NULL) {
TRACE_ERROR("EVP_DigestSignInit failed\n");
rv = CKR_FUNCTION_FAILED;
goto err;
}
if (EVP_DigestSignInit(cmac->mctx, &cmac->pctx,
NULL, NULL, cmac->pkey) != 1) {
TRACE_ERROR("EVP_DigestSignInit failed\n");
rv = CKR_FUNCTION_FAILED;
goto err;
}
*ctx = cmac;
}
cmac = (struct cmac_ctx *)*ctx;
if (cmac == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED));
rv = CKR_FUNCTION_FAILED;
goto err;
}
rc = EVP_DigestSignUpdate(cmac->mctx, message, message_len);
if (rc != 1 || message_len > INT_MAX) {
TRACE_ERROR("EVP_DigestSignUpdate failed\n");
rv = CKR_FUNCTION_FAILED;
goto err;
}
if (last) {
maclen = AES_BLOCK_SIZE;
rc = EVP_DigestSignFinal(cmac->mctx, mac, &maclen);
if (rc != 1) {
TRACE_ERROR("EVP_DigestSignFinal failed\n");
rv = CKR_FUNCTION_FAILED;
goto err;
}
EVP_MD_CTX_free(cmac->mctx); /* frees pctx */
EVP_PKEY_free(cmac->pkey);
free(cmac);
*ctx = NULL;
}
return CKR_OK;
err:
if (cmac != NULL) {
if (cmac->mctx != NULL)
EVP_MD_CTX_free(cmac->mctx); /* frees pctx */
if (cmac->pkey != NULL)
EVP_PKEY_free(cmac->pkey);
free(cmac);
}
*ctx = NULL;
return rv;
#endif
}
#ifndef NO_EC
static CK_RV make_ec_key_from_params(const CK_BYTE *params, CK_ULONG params_len,
EC_KEY **key)
{
const unsigned char *oid;
ASN1_OBJECT *obj = NULL;
EC_KEY *ec_key = NULL;
int nid;
CK_RV rc = CKR_OK;
oid = params;
obj = d2i_ASN1_OBJECT(NULL, &oid, params_len);
if (obj == NULL) {
TRACE_ERROR("curve not supported by OpenSSL.\n");
rc = CKR_CURVE_NOT_SUPPORTED;
goto out;
}
nid = OBJ_obj2nid(obj);
if (nid == NID_undef) {
TRACE_ERROR("curve not supported by OpenSSL.\n");
rc = CKR_CURVE_NOT_SUPPORTED;
goto out;
}
ec_key = EC_KEY_new_by_curve_name(nid);
if (ec_key == NULL) {
TRACE_ERROR("curve not supported by OpenSSL.\n");
rc = CKR_CURVE_NOT_SUPPORTED;
goto out;
}
out:
if (obj != NULL)
ASN1_OBJECT_free(obj);
if (rc != CKR_OK) {
if (ec_key != NULL)
EC_KEY_free(ec_key);
return rc;
}
*key = ec_key;
return CKR_OK;
}
static CK_RV fill_ec_key_from_pubkey(EC_KEY *ec_key, const CK_BYTE *data,
CK_ULONG data_len)
{
CK_BYTE *ecpoint = NULL;
CK_ULONG ecpoint_len, field_len, privlen, padlen;
CK_BYTE form, *temp = NULL;
CK_RV rc;
/* CKA_EC_POINT contains the EC point as OCTET STRING */
rc = ber_decode_OCTET_STRING((CK_BYTE *)data, &ecpoint, &ecpoint_len,
&field_len);
if (rc != CKR_OK || field_len != data_len) {
TRACE_DEVEL("ber_decode_OCTET_STRING failed\n");
rc = CKR_ATTRIBUTE_VALUE_INVALID;
goto out;
}
/* Check for public key without format byte */
privlen = (EC_GROUP_order_bits(EC_KEY_get0_group(ec_key)) + 7) / 8;
form = ecpoint[0] & ~0x01;
if (ecpoint_len <= 2 * privlen &&
form != POINT_CONVERSION_COMPRESSED &&
form != POINT_CONVERSION_UNCOMPRESSED &&
form != POINT_CONVERSION_HYBRID) {
temp = malloc(1 + 2 * privlen);
if (temp == NULL) {
rc = CKR_HOST_MEMORY;
goto out;
}
padlen = 2 * privlen - ecpoint_len;
temp[0] = POINT_CONVERSION_UNCOMPRESSED;
memset(temp + 1, 0, padlen);
memcpy(temp + 1 + padlen, ecpoint, ecpoint_len);
ecpoint = temp;
ecpoint_len = 1 + 2 * privlen;
}
if (!EC_KEY_oct2key(ec_key, ecpoint, ecpoint_len, NULL)) {
TRACE_ERROR("EC_KEY_oct2key failed\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
out:
if (temp != NULL)
free(temp);
return rc;
}
static CK_RV fill_ec_key_from_privkey(EC_KEY *ec_key, const CK_BYTE *data,
CK_ULONG data_len)
{
EC_POINT *point = NULL;
CK_RV rc = CKR_OK;
if (!EC_KEY_oct2priv(ec_key, data, data_len)) {
TRACE_ERROR("EC_KEY_oct2priv failed\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
point = EC_POINT_new(EC_KEY_get0_group(ec_key));
if (point == NULL) {
TRACE_ERROR("EC_POINT_new failed\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
if (!EC_POINT_mul(EC_KEY_get0_group(ec_key), point,
EC_KEY_get0_private_key(ec_key), NULL, NULL, NULL)) {
TRACE_ERROR("EC_POINT_mul failed\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
if (!EC_KEY_set_public_key(ec_key, point)) {
TRACE_ERROR("EC_KEY_set_public_key failed\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
out:
if (point != NULL)
EC_POINT_free(point);
return rc;
}
static CK_RV make_ec_key_from_template(TEMPLATE *template, EC_KEY **key)
{
CK_ATTRIBUTE *attr = NULL;
CK_OBJECT_CLASS keyclass;
EC_KEY *ec_key = NULL;
CK_RV rc;
rc = template_attribute_find(template, CKA_CLASS, &attr);
if (rc == FALSE) {
TRACE_ERROR("Could not find CKA_CLASS in the template\n");
rc = CKR_TEMPLATE_INCOMPLETE;
goto out;
}
keyclass = *(CK_OBJECT_CLASS *) attr->pValue;
if (!template_attribute_find(template, CKA_ECDSA_PARAMS, &attr)) {
TRACE_ERROR("Could not find CKA_ECDSA_PARAMS in the template\n");
rc = CKR_TEMPLATE_INCOMPLETE;
goto out;
}
rc = make_ec_key_from_params(attr->pValue, attr->ulValueLen, &ec_key);
if (rc != CKR_OK)
goto out;
switch (keyclass) {
case CKO_PUBLIC_KEY:
rc = template_attribute_find(template, CKA_EC_POINT, &attr);
if (rc == FALSE) {
TRACE_ERROR("Could not find CKA_EC_POINT in the template\n");
rc = CKR_TEMPLATE_INCOMPLETE;
goto out;
}
rc = fill_ec_key_from_pubkey(ec_key, attr->pValue, attr->ulValueLen);
if (rc != CKR_OK) {
TRACE_DEVEL("fill_ec_key_from_pubkey failed\n");
goto out;
}
break;
case CKO_PRIVATE_KEY:
rc = template_attribute_find(template, CKA_VALUE, &attr);
if (rc == FALSE) {
TRACE_ERROR("Could not find CKA_VALUE in the template\n");
rc = CKR_TEMPLATE_INCOMPLETE;
goto out;
}
rc = fill_ec_key_from_privkey(ec_key, attr->pValue, attr->ulValueLen);
if (rc != CKR_OK) {
TRACE_DEVEL("fill_ec_key_from_privkey failed\n");
goto out;
}
break;
default:
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto out;
}
rc = CKR_OK;
out:
if (rc != CKR_OK) {
if (ec_key != NULL)
EC_KEY_free(ec_key);
return rc;
}
*key = ec_key;
return CKR_OK;
}
CK_RV token_specific_ec_generate_keypair(STDLL_TokData_t *tokdata,
TEMPLATE *publ_tmpl,
TEMPLATE *priv_tmpl)
{
CK_ATTRIBUTE *attr = NULL, *ec_point_attr, *value_attr, *parms_attr;
EC_KEY *ec_key = NULL;
BN_CTX *ctx = NULL;
CK_BYTE *ecpoint = NULL, *enc_ecpoint = NULL, *d = NULL;
CK_ULONG ecpoint_len, enc_ecpoint_len, d_len;
CK_RV rc;
UNUSED(tokdata);
if (!template_attribute_find(publ_tmpl, CKA_ECDSA_PARAMS, &attr)) {
TRACE_ERROR("Could not find CKA_ECDSA_PARAMS in the template\n");
rc = CKR_TEMPLATE_INCOMPLETE;
goto out;
}
rc = make_ec_key_from_params(attr->pValue, attr->ulValueLen, &ec_key);
if (rc != CKR_OK)
goto out;
if (!EC_KEY_generate_key(ec_key)) {
TRACE_ERROR("Failed to generate an EC key.\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
ctx = BN_CTX_new();
if (ctx == NULL) {
rc = CKR_HOST_MEMORY;
goto out;
}
ecpoint_len = EC_KEY_key2buf(ec_key, POINT_CONVERSION_UNCOMPRESSED,
&ecpoint, ctx);
if (ecpoint_len == 0) {
TRACE_ERROR("Failed to get the EC Point compressed.\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
rc = ber_encode_OCTET_STRING(FALSE, &enc_ecpoint, &enc_ecpoint_len,
ecpoint, ecpoint_len);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_OCTET_STRING failed\n");
goto out;
}
rc = build_attribute(CKA_EC_POINT, enc_ecpoint, enc_ecpoint_len,
&ec_point_attr);
if (rc != CKR_OK) {
TRACE_ERROR("build_attribute for CKA_EC_POINT failed rc=0x%lx\n", rc);
goto out;
}
template_update_attribute(publ_tmpl, ec_point_attr);
d_len = EC_KEY_priv2buf(ec_key, &d);
if (d_len == 0) {
TRACE_ERROR("Failed to get the EC private key.\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
rc = build_attribute(CKA_VALUE, d, d_len, &value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("build_attribute for CKA_VALUE failed, rc=0x%lx\n", rc);
goto out;
}
template_update_attribute(priv_tmpl, value_attr);
/* Add CKA_ECDSA_PARAMS to private template also */
rc = build_attribute(CKA_ECDSA_PARAMS, attr->pValue, attr->ulValueLen,
&parms_attr);
if (rc != CKR_OK) {
TRACE_ERROR("build_attribute for CKA_ECDSA_PARAMS failed, rc=0x%lx\n",
rc);
goto out;
}
template_update_attribute(priv_tmpl, parms_attr);
rc = CKR_OK;
out:
if (ctx)
BN_CTX_free(ctx);
if (ec_key != NULL)
EC_KEY_free(ec_key);
if (ecpoint != NULL)
OPENSSL_free(ecpoint);
if (enc_ecpoint != NULL)
free(enc_ecpoint);
if (d != NULL)
OPENSSL_free(d);
return rc;
}
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)
{
EC_KEY *ec_key;
ECDSA_SIG *sig;
const BIGNUM *r, *s;
CK_ULONG privlen, n;
CK_RV rc = CKR_OK;
UNUSED(tokdata);
UNUSED(sess);
*out_data_len = 0;
rc = make_ec_key_from_template(key_obj->template, &ec_key);
if (rc != CKR_OK)
return rc;
sig = ECDSA_do_sign(in_data, in_data_len, ec_key);
if (sig == NULL) {
TRACE_ERROR("ECDSA_do_sign failed\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
ECDSA_SIG_get0(sig, &r, &s);
privlen = (EC_GROUP_order_bits(EC_KEY_get0_group(ec_key)) + 7) / 8;
/* Insert leading 0x00's if r or s shorter than privlen */
n = privlen - BN_num_bytes(r);
memset(out_data, 0x00, n);
BN_bn2bin(r, &out_data[n]);
n = privlen - BN_num_bytes(s);
memset(out_data + privlen, 0x00, n);
BN_bn2bin(s, &out_data[privlen + n]);
*out_data_len = 2 * privlen;
out:
if (sig != NULL)
ECDSA_SIG_free(sig);
if (ec_key != NULL)
EC_KEY_free(ec_key);
return rc;
}
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)
{
EC_KEY *ec_key;
CK_ULONG privlen;
ECDSA_SIG *sig = NULL;
BIGNUM *r = NULL, *s = NULL;
CK_RV rc = CKR_OK;
UNUSED(tokdata);
UNUSED(sess);
rc = make_ec_key_from_template(key_obj->template, &ec_key);
if (rc != CKR_OK)
return rc;
privlen = (EC_GROUP_order_bits(EC_KEY_get0_group(ec_key)) + 7) / 8;
if (signature_len < 2 * privlen) {
TRACE_ERROR("Signature is too short\n");
rc = CKR_SIGNATURE_LEN_RANGE;
goto out;
}
sig = ECDSA_SIG_new();
if (sig == NULL) {
rc = CKR_HOST_MEMORY;
goto out;
}
r = BN_bin2bn(signature, privlen, NULL);
s = BN_bin2bn(signature + privlen, privlen, NULL);
if (r == NULL || s == NULL) {
TRACE_ERROR("BN_bin2bn failed\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
if (!ECDSA_SIG_set0(sig, r, s)) {
TRACE_ERROR("ECDSA_SIG_set0 failed\n");
rc = CKR_FUNCTION_FAILED;
goto out;
}
rc = ECDSA_do_verify(in_data, in_data_len, sig, ec_key);
switch (rc) {
case 0:
rc = CKR_SIGNATURE_INVALID;
break;
case 1:
rc = CKR_OK;
break;
default:
rc = CKR_FUNCTION_FAILED;
break;
}
out:
if (sig != NULL)
ECDSA_SIG_free(sig);
if (ec_key != NULL)
EC_KEY_free(ec_key);
return rc;
}
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)
{
EC_KEY *ec_pub = NULL, *ec_priv = NULL;
CK_ULONG privlen;
int secret_len;
CK_RV rc;
UNUSED(tokdata);
rc = make_ec_key_from_params(oid, oid_length, &ec_priv);
if (rc != CKR_OK) {
TRACE_DEVEL("make_ec_key_from_params failed\n");
goto out;
}
rc = fill_ec_key_from_privkey(ec_priv, priv_bytes, priv_length);
if (rc != CKR_OK) {
TRACE_DEVEL("fill_ec_key_from_privkey failed\n");
goto out;
}
rc = make_ec_key_from_params(oid, oid_length, &ec_pub);
if (rc != CKR_OK) {
TRACE_DEVEL("make_ec_key_from_params failed\n");
goto out;
}
rc = fill_ec_key_from_pubkey(ec_pub, pub_bytes, pub_length);
if (rc != CKR_OK) {
TRACE_DEVEL("fill_ec_key_from_privkey failed\n");
goto out;
}
privlen = (EC_GROUP_order_bits(EC_KEY_get0_group(ec_priv)) + 7) / 8;
secret_len = ECDH_compute_key(secret_value, privlen,
EC_KEY_get0_public_key(ec_pub), ec_priv,
NULL);
if (secret_len <= 0) {
TRACE_DEVEL("ECDH_compute_key failed\n");
rc = CKR_FUNCTION_FAILED;
*secret_value_len = 0;
goto out;
}
*secret_value_len = secret_len;
out:
if (ec_priv != NULL)
EC_KEY_free(ec_priv);
if (ec_pub != NULL)
EC_KEY_free(ec_pub);
return rc;
}
#endif
CK_RV token_specific_object_add(STDLL_TokData_t * tokdata, SESSION * sess,
OBJECT * obj)
{
CK_ATTRIBUTE *attr = NULL;
CK_KEY_TYPE keytype;
#ifndef NO_EC
EC_KEY *ec_key = NULL;
CK_RV rc;
#endif
UNUSED(tokdata);
UNUSED(sess);
if (template_attribute_find(obj->template, CKA_KEY_TYPE, &attr) == FALSE)
return CKR_OK;
keytype = *(CK_KEY_TYPE *)attr->pValue;
switch (keytype) {
#ifndef NO_EC
case CKK_EC:
/* Check if OpenSSL supports the curve */
rc = make_ec_key_from_template(obj->template, &ec_key);
if (ec_key != NULL)
EC_KEY_free(ec_key);
return rc;
#endif
default:
return CKR_OK;;
}
}