/*
* 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
==========
****************************************************************************/
/* Declaration of secure_getenv requires _GNU_SOURCE */
#define _GNU_SOURCE
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <regex.h>
#include <dirent.h>
#include <libgen.h>
#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 "stdll.h"
#include "attributes.h"
#include "trace.h"
#include "ock_syslog.h"
#include "ec_defs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <asm/zcrypt.h>
#include <syslog.h>
#include <dlfcn.h>
#include <lber.h>
#include <grp.h>
#include <sys/time.h>
#include <time.h>
#ifdef DEBUG
#include <ctype.h>
#endif
#include <ica_api.h>
#include <openssl/crypto.h>
#include "ep11.h"
#include "ep11_func.h"
#include "ep11_specific.h"
#define EP11SHAREDLIB_NAME "OCK_EP11_LIBRARY"
#define EP11SHAREDLIB_V3 "libep11.so.3"
#define EP11SHAREDLIB_V2 "libep11.so.2"
#define EP11SHAREDLIB_V1 "libep11.so.1"
#define EP11SHAREDLIB "libep11.so"
#define ICASHAREDLIB "libica.so.3"
CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata,
CK_MECHANISM_TYPE_PTR mlist,
CK_ULONG_PTR count);
CK_RV ep11tok_get_mechanism_info(STDLL_TokData_t * tokdata,
CK_MECHANISM_TYPE type,
CK_MECHANISM_INFO_PTR pInfo);
CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata,
CK_MECHANISM_TYPE type);
CK_RV ep11tok_is_mechanism_supported_ex(STDLL_TokData_t *tokdata,
CK_MECHANISM_PTR mech);
static m_GenerateRandom_t dll_m_GenerateRandom;
static m_SeedRandom_t dll_m_SeedRandom;
static m_Digest_t dll_m_Digest;
static m_DigestInit_t dll_m_DigestInit;
static m_DigestUpdate_t dll_m_DigestUpdate;
static m_DigestKey_t dll_m_DigestKey;
static m_DigestFinal_t dll_m_DigestFinal;
static m_DigestSingle_t dll_m_DigestSingle;
static m_Encrypt_t dll_m_Encrypt;
static m_EncryptInit_t dll_m_EncryptInit;
static m_EncryptUpdate_t dll_m_EncryptUpdate;
static m_EncryptFinal_t dll_m_EncryptFinal;
static m_EncryptSingle_t dll_m_EncryptSingle;
static m_Decrypt_t dll_m_Decrypt;
static m_DecryptInit_t dll_m_DecryptInit;
static m_DecryptUpdate_t dll_m_DecryptUpdate;
static m_DecryptFinal_t dll_m_DecryptFinal;
static m_DecryptSingle_t dll_m_DecryptSingle;
static m_ReencryptSingle_t dll_m_ReencryptSingle;
static m_GenerateKey_t dll_m_GenerateKey;
static m_GenerateKeyPair_t dll_m_GenerateKeyPair;
static m_Sign_t dll_m_Sign;
static m_SignInit_t dll_m_SignInit;
static m_SignUpdate_t dll_m_SignUpdate;
static m_SignFinal_t dll_m_SignFinal;
static m_SignSingle_t dll_m_SignSingle;
static m_Verify_t dll_m_Verify;
static m_VerifyInit_t dll_m_VerifyInit;
static m_VerifyUpdate_t dll_m_VerifyUpdate;
static m_VerifyFinal_t dll_m_VerifyFinal;
static m_VerifySingle_t dll_m_VerifySingle;
static m_WrapKey_t dll_m_WrapKey;
static m_UnwrapKey_t dll_m_UnwrapKey;
static m_DeriveKey_t dll_m_DeriveKey;
static m_GetMechanismList_t dll_m_GetMechanismList;
static m_GetMechanismInfo_t dll_m_GetMechanismInfo;
static m_GetAttributeValue_t dll_m_GetAttributeValue;
static m_SetAttributeValue_t dll_m_SetAttributeValue;
static m_Login_t dll_m_Login;
static m_Logout_t dll_m_Logout;
static m_admin_t dll_m_admin;
static m_add_backend_t dll_m_add_backend;
static m_init_t dll_m_init;
static m_shutdown_t dll_m_shutdown;
static m_add_module_t dll_m_add_module;
static m_rm_module_t dll_m_rm_module;
static xcpa_queryblock_t dll_xcpa_queryblock;
static xcpa_internal_rv_t dll_xcpa_internal_rv;
static m_get_xcp_info_t dll_m_get_xcp_info;
#ifdef DEBUG
/* a simple function for dumping out a memory area */
static inline void hexdump(void *buf, size_t buflen)
{
/* 1 2 3 4 5 6
0123456789012345678901234567890123456789012345678901234567890123456789
xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx ................
*/
size_t i, j;
char line[68];
for (i = 0; i < buflen; i += 16) {
for (j = 0; j < 16; j++) {
if (i + j < buflen) {
unsigned char b = ((unsigned char *) buf)[i + j];
sprintf(line + j * 3, "%02hhx ", b);
line[51 + j] = (isalnum(b) ? b : '.');
} else {
sprintf(line + j * 3, " ");
line[51 + j] = ' ';
}
}
line[47] = line[48] = line[49] = line[50] = ' ';
line[67] = '\0';
TRACE_DEBUG("%s\n", line);
}
}
#define TRACE_DEBUG_DUMP(_buf, _buflen) hexdump(_buf, _buflen)
#endif /* DEBUG */
const char manuf[] = "IBM";
const char model[] = "EP11";
const char descr[] = "IBM EP11 token";
const char label[] = "ep11tok";
/* largest blobsize ever seen is about 5k (for 4096 mod bits RSA keys) */
#define MAX_BLOBSIZE 8192
#define MAX_CSUMSIZE 64
#define MAX_DIGEST_STATE_BYTES 1024
#define MAX_CRYPT_STATE_BYTES 8192
#define MAX_SIGN_STATE_BYTES 8192
#define MAX_APQN 256
/* wrap_key is used for importing keys */
static const char wrap_key_name[] = "EP11_wrapkey";
typedef struct cp_mech_config {
CK_MECHANISM_TYPE mech; // the mechanism ID
struct cp_mech_config *next; // next mechanism, or NULL
} cp_mech_config_t;
typedef struct cp_config {
unsigned long int cp; // control point number
cp_mech_config_t *mech; // list of mechanisms affected by this CP
struct cp_config *next; // next control point, or NULL
} cp_config_t;
typedef struct {
SESSION *session;
CK_BYTE session_id[SHA256_HASH_SIZE];
CK_BYTE vhsm_pin[XCP_MAX_PINBYTES];
CK_BYTE flags;
CK_BYTE session_pin_blob[XCP_PINBLOB_BYTES];
CK_OBJECT_HANDLE session_object;
CK_BYTE vhsm_pin_blob[XCP_PINBLOB_BYTES];
CK_OBJECT_HANDLE vhsm_object;
} ep11_session_t;
#define EP11_SESS_PINBLOB_VALID 0x01
#define EP11_VHSM_PINBLOB_VALID 0x02
#define EP11_VHSMPIN_VALID 0x10
#define EP11_STRICT_MODE 0x40
#define EP11_VHSM_MODE 0x80
#define DEFAULT_EP11_PIN " "
#define CKH_IBM_EP11_SESSION CKH_VENDOR_DEFINED + 1
#define CKH_IBM_EP11_VHSMPIN CKH_VENDOR_DEFINED + 2
#define PUBLIC_SESSION_ID_LENGTH 16
#define MAX_RETRY_COUNT 100
#define RETRY_START do { \
int retry_count; \
for(retry_count = 0; \
retry_count < MAX_RETRY_COUNT; \
retry_count ++) {
#define RETRY_END(rc, tokdata, session) if ((rc) != CKR_SESSION_CLOSED) \
break; \
(rc) = ep11tok_relogin_session( \
tokdata, session); \
if ((rc) != CKR_OK) \
break; \
} \
} while (0);
#define CKF_EP11_HELPER_SESSION 0x80000000
static CK_BOOL ep11_is_session_object(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len);
static CK_RV ep11tok_relogin_session(STDLL_TokData_t * tokdata, SESSION * session);
static void ep11_get_pin_blob(ep11_session_t * ep11_session, CK_BOOL is_session_obj,
CK_BYTE ** pin_blob, CK_ULONG * pin_blob_len);
static CK_RV ep11_open_helper_session(STDLL_TokData_t * tokdata, SESSION * sess,
CK_SESSION_HANDLE_PTR phSession);
static CK_RV ep11_close_helper_session(STDLL_TokData_t * tokdata,
ST_SESSION_HANDLE * sSession);
static void free_cp_config(cp_config_t * cp);
#ifdef DEBUG
static const char *ep11_get_cp(unsigned int cp);
#endif
static CK_ULONG ep11_get_cp_by_name(const char *name);
static CK_RV check_cps_for_mechanism(cp_config_t * cp_config,
CK_MECHANISM_TYPE mech,
unsigned char *cp, size_t cp_len,
size_t max_cp_index);
static CK_RV get_control_points(STDLL_TokData_t * tokdata,
unsigned char *cp, size_t * cp_len,
size_t *max_cp_index);
typedef struct ep11_card_version {
struct ep11_card_version *next;
CK_ULONG card_type;
CK_VERSION firmware_version;
CK_ULONG firmware_API_version;
} ep11_card_version_t;
static CK_RV ep11tok_get_ep11_library_version(CK_VERSION *lib_version);
static CK_RV ep11tok_get_ep11_version(STDLL_TokData_t *tokdata);
static void free_card_versions(ep11_card_version_t *card_version);
static int check_card_version(STDLL_TokData_t *tokdata, CK_ULONG card_type,
const CK_VERSION *ep11_lib_version,
const CK_VERSION *firmware_version,
const CK_ULONG *firmware_API_version);
static int compare_ck_version(const CK_VERSION *v1, const CK_VERSION *v2);
typedef struct {
const CK_VERSION *min_lib_version;
const CK_VERSION *min_firmware_version;
const CK_ULONG *min_firmware_API_version;
CK_ULONG card_type;
} version_req_t;
static int check_required_versions(STDLL_TokData_t *tokdata,
const version_req_t req[],
CK_ULONG num_req);
/* EP11 Firmware levels that contain the HMAC min/max keysize fix */
static const CK_VERSION cex4p_hmac_fix = { .major = 4, .minor = 20 };
static const CK_VERSION cex5p_hmac_fix = { .major = 6, .minor = 3 };
static const CK_VERSION cex6p_hmac_fix = { .major = 6, .minor = 9 };
static const version_req_t hmac_req_versions[] = {
{ .card_type = 4, .min_firmware_version = &cex4p_hmac_fix },
{ .card_type = 5, .min_firmware_version = &cex5p_hmac_fix },
{ .card_type = 6, .min_firmware_version = &cex6p_hmac_fix }
};
#define NUM_HMAC_REQ (sizeof(hmac_req_versions) / sizeof(version_req_t))
static const CK_VERSION cex7p_ibm_sha3_support = { .major = 7, .minor = 11 };
static const version_req_t ibm_sha3_req_versions[] = {
{ .card_type = 7, .min_firmware_version = &cex7p_ibm_sha3_support }
};
#define NUM_IBM_SHA3_REQ (sizeof(ibm_sha3_req_versions) / sizeof(version_req_t))
static const CK_VERSION cex7p_cmac_support = { .major = 7, .minor = 11 };
static const version_req_t cmac_req_versions[] = {
{ .card_type = 7, .min_firmware_version = &cex7p_cmac_support }
};
#define NUM_CMAC_REQ (sizeof(cmac_req_versions) / sizeof(version_req_t))
static const CK_VERSION cex7p_oaep_sha2_support = { .major = 7, .minor = 13 };
static const version_req_t oaep_sha2_req_versions[] = {
{ .card_type = 7, .min_firmware_version = &cex7p_oaep_sha2_support }
};
#define NUM_OAEP_SHA2_REQ (sizeof(oaep_sha2_req_versions) / sizeof(version_req_t))
static const CK_VERSION cex7p_edwards_support = { .major = 7, .minor = 15 };
static const version_req_t edwards_req_versions[] = {
{ .card_type = 7, .min_firmware_version = &cex7p_edwards_support }
};
#define NUM_EDWARDS_REQ (sizeof(edwards_req_versions) / sizeof(version_req_t))
static const CK_VERSION ibm_cex7p_dilithium_support = { .major = 7, .minor = 15 };
static const version_req_t ibm_dilithium_req_versions[] = {
{ .card_type = 7, .min_firmware_version = &ibm_cex7p_dilithium_support }
};
#define NUM_DILITHIUM_REQ (sizeof(ibm_dilithium_req_versions) / sizeof(version_req_t))
static const CK_VERSION ibm_cex6p_reencrypt_single_support =
{ .major = 6, .minor = 15 };
static const CK_VERSION ibm_cex7p_reencrypt_single_support =
{ .major = 7, .minor = 21 };
static const version_req_t reencrypt_single_req_versions[] = {
{ .card_type = 6, .min_firmware_version =
&ibm_cex6p_reencrypt_single_support },
{ .card_type = 7, .min_firmware_version =
&ibm_cex7p_reencrypt_single_support }
};
#define NUM_REENCRYPT_SINGLE_REQ (sizeof(reencrypt_single_req_versions) / \
sizeof(version_req_t))
/* Definitions for loading libica dynamically */
typedef unsigned int (*ica_sha1_t)(unsigned int message_part,
unsigned int input_length,
unsigned char *input_data,
sha_context_t *sha_context,
unsigned char *output_data);
typedef unsigned int (*ica_sha224_t)(unsigned int message_part,
unsigned int input_length,
unsigned char *input_data,
sha256_context_t *sha_context,
unsigned char *output_data);
typedef unsigned int (*ica_sha256_t)(unsigned int message_part,
unsigned int input_length,
unsigned char *input_data,
sha256_context_t *sha_context,
unsigned char *output_data);
typedef unsigned int (*ica_sha384_t)(unsigned int message_part,
unsigned int input_length,
unsigned char *input_data,
sha512_context_t *sha_context,
unsigned char *output_data);
typedef unsigned int (*ica_sha512_t)(unsigned int message_part,
unsigned int input_length,
unsigned char *input_data,
sha512_context_t *sha_context,
unsigned char *output_data);
typedef unsigned int (*ica_sha512_224_t)(unsigned int message_part,
unsigned int input_length,
unsigned char *input_data,
sha512_context_t *sha_context,
unsigned char *output_data);
typedef unsigned int (*ica_sha512_256_t)(unsigned int message_part,
unsigned int input_length,
unsigned char *input_data,
sha512_context_t *sha_context,
unsigned char *output_data);
#ifdef SHA3_224
typedef unsigned int (*ica_sha3_224_t)(unsigned int message_part,
unsigned int input_length,
unsigned char *input_data,
sha3_224_context_t *sha3_224_context,
unsigned char *output_data);
typedef unsigned int (*ica_sha3_256_t)(unsigned int message_part,
unsigned int input_length,
unsigned char *input_data,
sha3_256_context_t *sha3_256_context,
unsigned char *output_data);
typedef unsigned int (*ica_sha3_384_t)(unsigned int message_part,
uint64_t input_length,
unsigned char *input_data,
sha3_384_context_t *sha3_384_context,
unsigned char *output_data);
typedef unsigned int (*ica_sha3_512_t)(unsigned int message_part,
uint64_t input_length,
unsigned char *input_data,
sha3_512_context_t *sha3_512_context,
unsigned char *output_data);
#endif
typedef struct {
CK_BYTE buffer[MAX_SHA_BLOCK_SIZE];
CK_ULONG block_size;
CK_ULONG offset;
CK_BBOOL first;
union {
sha_context_t sha1;
sha256_context_t sha256;
sha512_context_t sha512;
#ifdef SHA3_224
sha3_224_context_t sha3_224;
sha3_256_context_t sha3_256;
sha3_384_context_t sha3_384;
sha3_512_context_t sha3_512;
#endif
} ctx;
} libica_sha_context_t;
typedef struct {
void *library;
ica_sha1_t ica_sha1;
ica_sha224_t ica_sha224;
ica_sha256_t ica_sha256;
ica_sha384_t ica_sha384;
ica_sha512_t ica_sha512;
ica_sha512_224_t ica_sha512_224;
ica_sha512_256_t ica_sha512_256;
#ifdef SHA3_224
ica_sha3_224_t ica_sha3_224;
ica_sha3_256_t ica_sha3_256;
ica_sha3_384_t ica_sha3_384;
ica_sha3_512_t ica_sha3_512;
#endif
} libica_t;
/* target list of adapters/domains, specified in a config file by user,
tells the device driver which adapter/domain pairs should be used,
they must have the same master key */
typedef struct {
short format;
short length;
short apqns[2 * MAX_APQN];
} __attribute__ ((packed)) ep11_target_t;
/* EP11 token private data */
typedef struct {
target_t target;
ep11_target_t target_list;
CK_BYTE raw2key_wrap_blob[MAX_BLOBSIZE];
size_t raw2key_wrap_blob_l;
int cka_sensitive_default_true;
char cp_filter_config_filename[PATH_MAX];
cp_config_t *cp_config;
unsigned char control_points[XCP_CP_BYTES];
size_t control_points_len;
size_t max_control_point_index;
int strict_mode;
int vhsm_mode;
int optimize_single_ops;
int digest_libica;
char digest_libica_path[PATH_MAX];
libica_t libica;
CK_VERSION ep11_lib_version;
ep11_card_version_t *card_versions;
CK_ULONG used_firmware_API_version;
CK_CHAR serialNumber[16];
} ep11_private_data_t;
static CK_RV ep11tok_setup_target(STDLL_TokData_t *tokdata);
static CK_RV get_ep11_target_for_apqn(uint_32 adapter, uint_32 domain,
target_t *target);
static void free_ep11_target_for_apqn(target_t target);
/* defined in the makefile, ep11 library can run standalone (without HW card),
crypto algorithms are implemented in software then (no secure key) */
typedef struct const_info {
unsigned const int code;
const char *name;
} const_info_t;
#define CONSTINFO(_X) { (_X), (#_X) }
/* mechanisms defined by EP11 with an invalid (outdated) ID */
#define CKM_EP11_SHA512_224 0x000002B0 // 0x00000048 in PKCS#11
#define CKM_EP11_SHA512_224_HMAC 0x000002B1 // 0x00000049 in PKCS#11
#define CKM_EP11_SHA512_224_HMAC_GENERAL 0x000002B2 // 0x0000004A in PKCS#11
#define CKM_EP11_SHA512_256 0x000002C0 // 0x0000004C in PKCS#11
#define CKM_EP11_SHA512_256_HMAC 0x000002C1 // 0x0000004D in PKCS#11
#define CKM_EP11_SHA512_256_HMAC_GENERAL 0x000002C2 // 0x0000004E in PKCS#11
/* Vendor specific mechanisms unknown by ock, but known by EP11 */
#define CKM_IBM_ECDSA_SHA224 CKM_VENDOR_DEFINED + 0x00010008
#define CKM_IBM_ECDSA_SHA256 CKM_VENDOR_DEFINED + 0x00010009
#define CKM_IBM_ECDSA_SHA384 CKM_VENDOR_DEFINED + 0x0001000A
#define CKM_IBM_ECDSA_SHA512 CKM_VENDOR_DEFINED + 0x0001000B
#define CKM_IBM_EC_MULTIPLY CKM_VENDOR_DEFINED + 0x0001000C
#define CKM_IBM_EAC CKM_VENDOR_DEFINED + 0x0001000D
#define CKM_IBM_TESTCODE CKM_VENDOR_DEFINED + 0x0001000E
#define CKM_IBM_SHA512_256 CKM_VENDOR_DEFINED + 0x00010012
#define CKM_IBM_SHA512_224 CKM_VENDOR_DEFINED + 0x00010013
#define CKM_IBM_SHA512_256_HMAC CKM_VENDOR_DEFINED + 0x00010014
#define CKM_IBM_SHA512_224_HMAC CKM_VENDOR_DEFINED + 0x00010015
#define CKM_IBM_SHA512_256_KEY_DERIVATION CKM_VENDOR_DEFINED + 0x00010016
#define CKM_IBM_SHA512_224_KEY_DERIVATION CKM_VENDOR_DEFINED + 0x00010017
#define CKM_IBM_EC_X25519 CKM_VENDOR_DEFINED + 0x0001001B
#define CKM_IBM_EDDSA_PH_SHA512 CKM_VENDOR_DEFINED + 0x0001001D
#define CKM_IBM_EC_X448 CKM_VENDOR_DEFINED + 0x0001001E
#define CKM_IBM_SIPHASH CKM_VENDOR_DEFINED + 0x00010021
#define CKM_IBM_DILITHIUM CKM_VENDOR_DEFINED + 0x00010023
#define CKM_IBM_CLEARKEY_TRANSPORT CKM_VENDOR_DEFINED + 0x00020001
#define CKM_IBM_ATTRIBUTEBOUND_WRAP CKM_VENDOR_DEFINED + 0x00020004
#define CKM_IBM_TRANSPORTKEY CKM_VENDOR_DEFINED + 0x00020005
#define CKM_IBM_DH_PKCS_DERIVE_RAW CKM_VENDOR_DEFINED + 0x00020006
#define CKM_IBM_ECDH1_DERIVE_RAW CKM_VENDOR_DEFINED + 0x00020007
#define CKM_IBM_WIRETEST CKM_VENDOR_DEFINED + 0x00030004
#define CKM_IBM_RETAINKEY CKM_VENDOR_DEFINED + 0x00040001
#define CKM_IBM_SM3 CKM_VENDOR_DEFINED + 0x0005000e
#define CKM_IBM_CPACF_WRAP CKM_VENDOR_DEFINED + 0x00060001
static CK_RV cleanse_attribute(TEMPLATE *template,
CK_ATTRIBUTE_TYPE attr_type)
{
CK_ATTRIBUTE *attr;
if (!template_attribute_find(template, attr_type, &attr))
return CKR_FUNCTION_FAILED;
OPENSSL_cleanse(attr->pValue, attr->ulValueLen);
return CKR_OK;
}
static CK_RV check_key_attributes(STDLL_TokData_t * tokdata,
CK_KEY_TYPE kt, CK_OBJECT_CLASS kc,
CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len,
CK_ATTRIBUTE_PTR * p_attrs,
CK_ULONG * p_attrs_len, int curve_type)
{
CK_RV rc;
CK_ULONG i;
CK_BBOOL cktrue = TRUE;
CK_ULONG check_types_pub[] = { CKA_VERIFY, CKA_ENCRYPT, CKA_WRAP };
CK_ULONG check_types_priv[] = { CKA_SIGN, CKA_DECRYPT, CKA_UNWRAP };
CK_ULONG check_types_sec[] =
{ CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP };
CK_ULONG check_types_sec_sensitive[] =
{ CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SENSITIVE };
CK_ULONG check_types_gen_sec[] =
{ CKA_SIGN, CKA_VERIFY, CKA_ENCRYPT, CKA_DECRYPT };
CK_ULONG check_types_gen_sec_sensitive[] =
{ CKA_SIGN, CKA_VERIFY, CKA_ENCRYPT, CKA_DECRYPT, CKA_SENSITIVE };
CK_ULONG check_types_derive[] = { CKA_DERIVE };
CK_ULONG *check_types = NULL;
CK_BBOOL *check_values[] = { &cktrue, &cktrue, &cktrue, &cktrue, &cktrue };
CK_ULONG attr_cnt = 0;
ep11_private_data_t *ep11_data = tokdata->private_data;
/* check/add attributes for public key template */
if ((rc = dup_attribute_array(attrs, attrs_len, p_attrs, p_attrs_len)))
return rc;
switch (kc) {
case CKO_SECRET_KEY:
if (kt == CKK_GENERIC_SECRET) {
if (ep11_data->cka_sensitive_default_true) {
check_types = &check_types_gen_sec_sensitive[0];
attr_cnt =
sizeof(check_types_gen_sec_sensitive) / sizeof(CK_ULONG);
} else {
check_types = &check_types_gen_sec[0];
attr_cnt = sizeof(check_types_gen_sec) / sizeof(CK_ULONG);
}
} else {
if (ep11_data->cka_sensitive_default_true) {
check_types = &check_types_sec_sensitive[0];
attr_cnt = sizeof(check_types_sec_sensitive) / sizeof(CK_ULONG);
} else {
check_types = &check_types_sec[0];
attr_cnt = sizeof(check_types_sec) / sizeof(CK_ULONG);
}
}
break;
case CKO_PUBLIC_KEY:
if ((kt == CKK_EC) || (kt == CKK_ECDSA) || (kt == CKK_DSA)) {
check_types = &check_types_pub[0];
attr_cnt = 1; /* only CKA_VERIFY */
if (kt == CKK_EC && curve_type == MONTGOMERY_CURVE)
attr_cnt = 0;
} else if (kt == CKK_RSA) {
check_types = &check_types_pub[0];
attr_cnt = sizeof(check_types_pub) / sizeof(CK_ULONG);
}
/* do nothing for CKM_DH_PKCS_KEY_PAIR_GEN
and CKM_DH_PKCS_PARAMETER_GEN and CKK_IBM_PQC_DILITHIUM */
break;
case CKO_PRIVATE_KEY:
if ((kt == CKK_EC) || (kt == CKK_ECDSA) || (kt == CKK_DSA)) {
check_types = &check_types_priv[0];
attr_cnt = 1; /* only CKA_SIGN */
if (kt == CKK_EC && curve_type == MONTGOMERY_CURVE)
attr_cnt = 0;
} else if (kt == CKK_RSA) {
check_types = &check_types_priv[0];
attr_cnt = sizeof(check_types_priv) / sizeof(CK_ULONG);
} else if (kt == CKK_DH) {
check_types = &check_types_derive[0];
attr_cnt = sizeof(check_types_derive) / sizeof(CK_ULONG);
}
/* Do nothing for CKK_IBM_PQC_DILITHIUM */
break;
default:
return CKR_OK;
}
for (i = 0; i < attr_cnt; i++, check_types++) {
CK_ATTRIBUTE_PTR attr = get_attribute_by_type(*p_attrs,
*p_attrs_len,
*check_types);
if (!attr) {
rc = add_to_attribute_array(p_attrs, p_attrs_len,
*check_types,
(CK_BYTE *) check_values[i],
sizeof(*check_values[i]));
if (rc)
goto cleanup;
}
}
return CKR_OK;
cleanup:
if (rc) {
free_attribute_array(*p_attrs, *p_attrs_len);
*p_attrs = NULL;
*p_attrs_len = 0;
}
return rc;
}
static CK_RV override_key_attributes(STDLL_TokData_t *tokdata,
CK_KEY_TYPE kt, CK_OBJECT_CLASS kc,
CK_ATTRIBUTE_PTR attrs,
CK_ULONG attrs_len)
{
CK_ULONG i;
CK_BBOOL cktrue = TRUE;
CK_ULONG override_types_public_key[] =
{ CKA_VERIFY, CKA_ENCRYPT };
CK_ULONG *override_types = NULL;
CK_BBOOL *override_values[] = { &cktrue, &cktrue };
CK_ULONG attr_cnt = 0;
UNUSED(tokdata);
switch (kc) {
case CKO_PUBLIC_KEY:
/*
* EP11 does not allow to restrict public RSA/DSA/EC keys with
* CKA_VERIFY=FALSE and/or CKA_ENCRYPT=FALSE since it can not
* technically enforce the restrictions. Therefore override these
* attributes for the EP11 library, but keep the original attribute
* values in the object.
*/
if (kt != CKK_EC && kt != CKK_RSA && kt != CKK_DSA)
return CKR_OK;
override_types = &override_types_public_key[0];
attr_cnt = sizeof(override_types_public_key) /
sizeof(override_types_public_key[0]);
break;
default:
return CKR_OK;
}
for (i = 0; i < attr_cnt; i++, override_types++) {
CK_ATTRIBUTE_PTR attr = get_attribute_by_type(attrs,
attrs_len,
*override_types);
if (attr != NULL)
*(CK_BBOOL *)(attr->pValue) = *override_values[i];
}
return CKR_OK;
}
static CK_RV check_key_restriction(OBJECT *key_obj, CK_ATTRIBUTE_TYPE type)
{
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
CK_BBOOL flag;
rc = template_attribute_find(key_obj->template, type, &attr);
if (rc == FALSE) {
TRACE_ERROR("Could not find attribute 0x%lx for the key.\n", type);
return CKR_KEY_FUNCTION_NOT_PERMITTED;
}
flag = *(CK_BBOOL *) attr->pValue;
if (flag != TRUE) {
TRACE_ERROR("%s\n", ock_err(ERR_KEY_FUNCTION_NOT_PERMITTED));
return CKR_KEY_FUNCTION_NOT_PERMITTED;
}
return CKR_OK;
}
static CK_RV ep11_get_keytype(CK_ATTRIBUTE * attrs, CK_ULONG attrs_len,
CK_MECHANISM_PTR mech, CK_ULONG * type, CK_ULONG * class)
{
CK_ULONG i;
CK_RV rc = CKR_TEMPLATE_INCONSISTENT;
*type = 0;
*class = 0;
for (i = 0; i < attrs_len; i++) {
if (attrs[i].type == CKA_CLASS)
*class = *(CK_ULONG *) attrs[i].pValue;
}
for (i = 0; i < attrs_len; i++) {
if (attrs[i].type == CKA_KEY_TYPE) {
*type = *(CK_ULONG *) attrs[i].pValue;
return CKR_OK;
}
}
/* no CKA_KEY_TYPE found, derive from mech */
switch (mech->mechanism) {
case CKM_DES_KEY_GEN:
*type = CKK_DES;
break;
case CKM_DES2_KEY_GEN:
*type = CKK_DES2;
break;
case CKM_DES3_KEY_GEN:
*type = CKK_DES3;
break;
case CKM_CDMF_KEY_GEN:
*type = CKK_CDMF;
break;
case CKM_AES_KEY_GEN:
*type = CKK_AES;
break;
case CKM_RSA_PKCS_KEY_PAIR_GEN:
*type = CKK_RSA;
break;
case CKM_EC_KEY_PAIR_GEN:
*type = CKK_EC;
break;
case CKM_DSA_KEY_PAIR_GEN:
*type = CKK_DSA;
break;
case CKM_DH_PKCS_KEY_PAIR_GEN:
*type = CKK_DH;
break;
case CKM_IBM_DILITHIUM:
*type = CKK_IBM_PQC_DILITHIUM;
break;
default:
return CKR_MECHANISM_INVALID;
}
rc = CKR_OK;
return rc;
}
static const_info_t ep11_mechanisms[] = {
CONSTINFO(CKM_RSA_PKCS_KEY_PAIR_GEN),
CONSTINFO(CKM_RSA_PKCS),
CONSTINFO(CKM_RSA_9796),
CONSTINFO(CKM_RSA_X_509),
CONSTINFO(CKM_MD2_RSA_PKCS),
CONSTINFO(CKM_MD5_RSA_PKCS),
CONSTINFO(CKM_SHA1_RSA_PKCS),
CONSTINFO(CKM_RIPEMD128_RSA_PKCS),
CONSTINFO(CKM_RIPEMD160_RSA_PKCS),
CONSTINFO(CKM_RSA_PKCS_OAEP),
CONSTINFO(CKM_RSA_X9_31_KEY_PAIR_GEN),
CONSTINFO(CKM_RSA_X9_31),
CONSTINFO(CKM_SHA1_RSA_X9_31),
CONSTINFO(CKM_RSA_PKCS_PSS),
CONSTINFO(CKM_SHA1_RSA_PKCS_PSS),
CONSTINFO(CKM_DSA_KEY_PAIR_GEN),
CONSTINFO(CKM_DSA),
CONSTINFO(CKM_DSA_SHA1),
CONSTINFO(CKM_DH_PKCS_KEY_PAIR_GEN),
CONSTINFO(CKM_DH_PKCS_DERIVE),
CONSTINFO(CKM_X9_42_DH_KEY_PAIR_GEN),
CONSTINFO(CKM_X9_42_DH_DERIVE),
CONSTINFO(CKM_X9_42_DH_HYBRID_DERIVE),
CONSTINFO(CKM_X9_42_MQV_DERIVE),
CONSTINFO(CKM_SHA256_RSA_PKCS),
CONSTINFO(CKM_SHA384_RSA_PKCS),
CONSTINFO(CKM_SHA512_RSA_PKCS),
CONSTINFO(CKM_RC2_KEY_GEN),
CONSTINFO(CKM_RC2_ECB),
CONSTINFO(CKM_RC2_CBC),
CONSTINFO(CKM_RC2_MAC),
CONSTINFO(CKM_RC2_MAC_GENERAL),
CONSTINFO(CKM_RC2_CBC_PAD),
CONSTINFO(CKM_RC4_KEY_GEN),
CONSTINFO(CKM_RC4),
CONSTINFO(CKM_DES_KEY_GEN),
CONSTINFO(CKM_DES_ECB),
CONSTINFO(CKM_DES_CBC),
CONSTINFO(CKM_DES_MAC),
CONSTINFO(CKM_DES_MAC_GENERAL),
CONSTINFO(CKM_DES_CBC_PAD),
CONSTINFO(CKM_DES2_KEY_GEN),
CONSTINFO(CKM_DES3_KEY_GEN),
CONSTINFO(CKM_DES3_ECB),
CONSTINFO(CKM_DES3_CBC),
CONSTINFO(CKM_DES3_MAC),
CONSTINFO(CKM_DES3_MAC_GENERAL),
CONSTINFO(CKM_DES3_CMAC),
CONSTINFO(CKM_DES3_CMAC_GENERAL),
CONSTINFO(CKM_DES3_CBC_PAD),
CONSTINFO(CKM_CDMF_KEY_GEN),
CONSTINFO(CKM_CDMF_ECB),
CONSTINFO(CKM_CDMF_CBC),
CONSTINFO(CKM_CDMF_MAC),
CONSTINFO(CKM_CDMF_MAC_GENERAL),
CONSTINFO(CKM_CDMF_CBC_PAD),
CONSTINFO(CKM_MD2),
CONSTINFO(CKM_MD2_HMAC),
CONSTINFO(CKM_MD2_HMAC_GENERAL),
CONSTINFO(CKM_MD5),
CONSTINFO(CKM_MD5_HMAC),
CONSTINFO(CKM_MD5_HMAC_GENERAL),
CONSTINFO(CKM_SHA_1),
CONSTINFO(CKM_SHA_1_HMAC),
CONSTINFO(CKM_SHA_1_HMAC_GENERAL),
CONSTINFO(CKM_RIPEMD128),
CONSTINFO(CKM_RIPEMD128_HMAC),
CONSTINFO(CKM_RIPEMD128_HMAC_GENERAL),
CONSTINFO(CKM_RIPEMD160),
CONSTINFO(CKM_RIPEMD160_HMAC),
CONSTINFO(CKM_RIPEMD160_HMAC_GENERAL),
CONSTINFO(CKM_SHA224),
CONSTINFO(CKM_SHA224_HMAC),
CONSTINFO(CKM_SHA224_HMAC_GENERAL),
CONSTINFO(CKM_SHA256),
CONSTINFO(CKM_SHA256_HMAC),
CONSTINFO(CKM_SHA256_HMAC_GENERAL),
CONSTINFO(CKM_SHA384),
CONSTINFO(CKM_SHA384_HMAC),
CONSTINFO(CKM_SHA384_HMAC_GENERAL),
CONSTINFO(CKM_SHA512),
CONSTINFO(CKM_SHA512_HMAC),
CONSTINFO(CKM_SHA512_HMAC_GENERAL),
CONSTINFO(CKM_CAST_KEY_GEN),
CONSTINFO(CKM_CAST_ECB),
CONSTINFO(CKM_CAST_CBC),
CONSTINFO(CKM_CAST_MAC),
CONSTINFO(CKM_CAST_MAC_GENERAL),
CONSTINFO(CKM_CAST_CBC_PAD),
CONSTINFO(CKM_CAST3_KEY_GEN),
CONSTINFO(CKM_CAST3_ECB),
CONSTINFO(CKM_CAST3_CBC),
CONSTINFO(CKM_CAST3_MAC),
CONSTINFO(CKM_CAST3_MAC_GENERAL),
CONSTINFO(CKM_CAST3_CBC_PAD),
CONSTINFO(CKM_CAST5_KEY_GEN),
CONSTINFO(CKM_CAST5_ECB),
CONSTINFO(CKM_CAST5_CBC),
CONSTINFO(CKM_CAST5_MAC),
CONSTINFO(CKM_CAST5_MAC_GENERAL),
CONSTINFO(CKM_CAST5_CBC_PAD),
CONSTINFO(CKM_RC5_KEY_GEN),
CONSTINFO(CKM_RC5_ECB),
CONSTINFO(CKM_RC5_CBC),
CONSTINFO(CKM_RC5_MAC),
CONSTINFO(CKM_RC5_MAC_GENERAL),
CONSTINFO(CKM_RC5_CBC_PAD),
CONSTINFO(CKM_IDEA_KEY_GEN),
CONSTINFO(CKM_IDEA_ECB),
CONSTINFO(CKM_IDEA_CBC),
CONSTINFO(CKM_IDEA_MAC),
CONSTINFO(CKM_IDEA_MAC_GENERAL),
CONSTINFO(CKM_IDEA_CBC_PAD),
CONSTINFO(CKM_GENERIC_SECRET_KEY_GEN),
CONSTINFO(CKM_CONCATENATE_BASE_AND_KEY),
CONSTINFO(CKM_CONCATENATE_BASE_AND_DATA),
CONSTINFO(CKM_CONCATENATE_DATA_AND_BASE),
CONSTINFO(CKM_XOR_BASE_AND_DATA),
CONSTINFO(CKM_EXTRACT_KEY_FROM_KEY),
CONSTINFO(CKM_SSL3_PRE_MASTER_KEY_GEN),
CONSTINFO(CKM_SSL3_MASTER_KEY_DERIVE),
CONSTINFO(CKM_SSL3_KEY_AND_MAC_DERIVE),
CONSTINFO(CKM_SSL3_MASTER_KEY_DERIVE_DH),
CONSTINFO(CKM_TLS_PRE_MASTER_KEY_GEN),
CONSTINFO(CKM_TLS_MASTER_KEY_DERIVE),
CONSTINFO(CKM_TLS_KEY_AND_MAC_DERIVE),
CONSTINFO(CKM_TLS_MASTER_KEY_DERIVE_DH),
CONSTINFO(CKM_SSL3_MD5_MAC),
CONSTINFO(CKM_SSL3_SHA1_MAC),
CONSTINFO(CKM_MD5_KEY_DERIVATION),
CONSTINFO(CKM_MD2_KEY_DERIVATION),
CONSTINFO(CKM_SHA1_KEY_DERIVATION),
CONSTINFO(CKM_SHA256_KEY_DERIVATION),
CONSTINFO(CKM_PBE_MD2_DES_CBC),
CONSTINFO(CKM_PBE_MD5_DES_CBC),
CONSTINFO(CKM_PBE_MD5_CAST_CBC),
CONSTINFO(CKM_PBE_MD5_CAST3_CBC),
CONSTINFO(CKM_PBE_MD5_CAST5_CBC),
CONSTINFO(CKM_PBE_SHA1_CAST5_CBC),
CONSTINFO(CKM_PBE_SHA1_RC4_128),
CONSTINFO(CKM_PBE_SHA1_RC4_40),
CONSTINFO(CKM_PBE_SHA1_DES3_EDE_CBC),
CONSTINFO(CKM_PBE_SHA1_DES2_EDE_CBC),
CONSTINFO(CKM_PBE_SHA1_RC2_128_CBC),
CONSTINFO(CKM_PBE_SHA1_RC2_40_CBC),
CONSTINFO(CKM_PKCS5_PBKD2),
CONSTINFO(CKM_PBA_SHA1_WITH_SHA1_HMAC),
CONSTINFO(CKM_KEY_WRAP_LYNKS),
CONSTINFO(CKM_KEY_WRAP_SET_OAEP),
CONSTINFO(CKM_SKIPJACK_KEY_GEN),
CONSTINFO(CKM_SKIPJACK_ECB64),
CONSTINFO(CKM_SKIPJACK_CBC64),
CONSTINFO(CKM_SKIPJACK_OFB64),
CONSTINFO(CKM_SKIPJACK_CFB64),
CONSTINFO(CKM_SKIPJACK_CFB32),
CONSTINFO(CKM_SKIPJACK_CFB16),
CONSTINFO(CKM_SKIPJACK_CFB8),
CONSTINFO(CKM_SKIPJACK_WRAP),
CONSTINFO(CKM_SKIPJACK_PRIVATE_WRAP),
CONSTINFO(CKM_SKIPJACK_RELAYX),
CONSTINFO(CKM_KEA_KEY_PAIR_GEN),
CONSTINFO(CKM_KEA_KEY_DERIVE),
CONSTINFO(CKM_FORTEZZA_TIMESTAMP),
CONSTINFO(CKM_BATON_KEY_GEN),
CONSTINFO(CKM_BATON_ECB128),
CONSTINFO(CKM_BATON_ECB96),
CONSTINFO(CKM_BATON_CBC128),
CONSTINFO(CKM_BATON_COUNTER),
CONSTINFO(CKM_BATON_SHUFFLE),
CONSTINFO(CKM_BATON_WRAP),
CONSTINFO(CKM_EC_KEY_PAIR_GEN),
CONSTINFO(CKM_ECDSA),
CONSTINFO(CKM_ECDSA_SHA1),
CONSTINFO(CKM_ECDSA_SHA224),
CONSTINFO(CKM_ECDSA_SHA256),
CONSTINFO(CKM_ECDSA_SHA384),
CONSTINFO(CKM_ECDSA_SHA512),
CONSTINFO(CKM_ECDH1_DERIVE),
CONSTINFO(CKM_ECDH1_COFACTOR_DERIVE),
CONSTINFO(CKM_ECMQV_DERIVE),
CONSTINFO(CKM_JUNIPER_KEY_GEN),
CONSTINFO(CKM_JUNIPER_ECB128),
CONSTINFO(CKM_JUNIPER_CBC128),
CONSTINFO(CKM_JUNIPER_COUNTER),
CONSTINFO(CKM_JUNIPER_SHUFFLE),
CONSTINFO(CKM_JUNIPER_WRAP),
CONSTINFO(CKM_FASTHASH),
CONSTINFO(CKM_AES_KEY_GEN),
CONSTINFO(CKM_AES_ECB),
CONSTINFO(CKM_AES_CBC),
CONSTINFO(CKM_AES_MAC),
CONSTINFO(CKM_AES_MAC_GENERAL),
CONSTINFO(CKM_AES_CBC_PAD),
CONSTINFO(CKM_AES_CTR),
CONSTINFO(CKM_AES_CMAC),
CONSTINFO(CKM_AES_CMAC_GENERAL),
CONSTINFO(CKM_DSA_PARAMETER_GEN),
CONSTINFO(CKM_DH_PKCS_PARAMETER_GEN),
CONSTINFO(CKM_X9_42_DH_PARAMETER_GEN),
CONSTINFO(CKM_VENDOR_DEFINED),
CONSTINFO(CKM_SHA256_RSA_PKCS_PSS),
CONSTINFO(CKM_SHA224_RSA_PKCS),
CONSTINFO(CKM_SHA224_RSA_PKCS_PSS),
CONSTINFO(CKM_SHA384_RSA_PKCS_PSS),
CONSTINFO(CKM_SHA512_RSA_PKCS_PSS),
CONSTINFO(CKM_SHA224_KEY_DERIVATION),
CONSTINFO(CKM_SHA384_KEY_DERIVATION),
CONSTINFO(CKM_SHA512_KEY_DERIVATION),
CONSTINFO(CKM_SHA512_224),
CONSTINFO(CKM_SHA512_224_HMAC),
CONSTINFO(CKM_SHA512_224_HMAC_GENERAL),
CONSTINFO(CKM_SHA512_256),
CONSTINFO(CKM_SHA512_256_HMAC),
CONSTINFO(CKM_SHA512_256_HMAC_GENERAL),
CONSTINFO(CKM_EP11_SHA512_224),
CONSTINFO(CKM_EP11_SHA512_224_HMAC),
CONSTINFO(CKM_EP11_SHA512_224_HMAC_GENERAL),
CONSTINFO(CKM_EP11_SHA512_256),
CONSTINFO(CKM_EP11_SHA512_256_HMAC),
CONSTINFO(CKM_EP11_SHA512_256_HMAC_GENERAL),
CONSTINFO(CKM_IBM_CMAC),
CONSTINFO(CKM_IBM_ECDSA_SHA224),
CONSTINFO(CKM_IBM_ECDSA_SHA256),
CONSTINFO(CKM_IBM_ECDSA_SHA384),
CONSTINFO(CKM_IBM_ECDSA_SHA512),
CONSTINFO(CKM_IBM_EC_MULTIPLY),
CONSTINFO(CKM_IBM_EAC),
CONSTINFO(CKM_IBM_TESTCODE),
CONSTINFO(CKM_IBM_SHA512_256),
CONSTINFO(CKM_IBM_SHA512_224),
CONSTINFO(CKM_IBM_SHA512_256_HMAC),
CONSTINFO(CKM_IBM_SHA512_224_HMAC),
CONSTINFO(CKM_IBM_SHA512_256_KEY_DERIVATION),
CONSTINFO(CKM_IBM_SHA512_224_KEY_DERIVATION),
CONSTINFO(CKM_IBM_EC_C25519),
CONSTINFO(CKM_IBM_ED25519_SHA512),
CONSTINFO(CKM_IBM_EDDSA_SHA512),
CONSTINFO(CKM_IBM_EDDSA_PH_SHA512),
CONSTINFO(CKM_IBM_EC_C448),
CONSTINFO(CKM_IBM_ED448_SHA3),
CONSTINFO(CKM_IBM_SIPHASH),
CONSTINFO(CKM_IBM_CLEARKEY_TRANSPORT),
CONSTINFO(CKM_IBM_ATTRIBUTEBOUND_WRAP),
CONSTINFO(CKM_IBM_TRANSPORTKEY),
CONSTINFO(CKM_IBM_DH_PKCS_DERIVE_RAW),
CONSTINFO(CKM_IBM_ECDH1_DERIVE_RAW),
CONSTINFO(CKM_IBM_WIRETEST),
CONSTINFO(CKM_IBM_RETAINKEY),
CONSTINFO(CKM_IBM_CPACF_WRAP),
CONSTINFO(CKM_IBM_SM3),
CONSTINFO(CKM_IBM_DILITHIUM),
CONSTINFO(CKM_IBM_SHA3_224),
CONSTINFO(CKM_IBM_SHA3_256),
CONSTINFO(CKM_IBM_SHA3_384),
CONSTINFO(CKM_IBM_SHA3_512),
CONSTINFO(CKM_IBM_SHA3_224_HMAC),
CONSTINFO(CKM_IBM_SHA3_256_HMAC),
CONSTINFO(CKM_IBM_SHA3_384_HMAC),
CONSTINFO(CKM_IBM_SHA3_512_HMAC),
};
#define UNKNOWN_MECHANISM 0xFFFFFFFF
/* for logging, debugging */
static const char *ep11_get_ckm(CK_ULONG mechanism)
{
unsigned int i;
for (i = 0;
i < (sizeof(ep11_mechanisms) / sizeof(ep11_mechanisms[0]));
i++) {
if (ep11_mechanisms[i].code == mechanism)
return ep11_mechanisms[i].name;
}
TRACE_WARNING("%s unknown mechanism %lx\n", __func__, mechanism);
return "UNKNOWN";
}
static CK_ULONG ep11_get_mechanisms_by_name(const char *name)
{
unsigned int i;
for (i = 0;
i < (sizeof(ep11_mechanisms) / sizeof(ep11_mechanisms[0]));
i++) {
if (strcmp(ep11_mechanisms[i].name, name) == 0)
return ep11_mechanisms[i].code;
}
TRACE_WARNING("%s unknown mechanism name '%s'\n", __func__, name);
return UNKNOWN_MECHANISM;
}
static CK_RV h_opaque_2_blob(STDLL_TokData_t * tokdata, CK_OBJECT_HANDLE handle,
CK_BYTE ** blob, size_t * blob_len,
OBJECT ** kobj, OBJ_LOCK_TYPE lock_type);
static CK_RV obj_opaque_2_blob(STDLL_TokData_t *tokdata, OBJECT *key_obj,
CK_BYTE **blob, size_t *blobsize);
#define EP11_DEFAULT_CFG_FILE "ep11tok.conf"
#define EP11_CFG_FILE_SIZE 4096
#define EP11_DEFAULT_CPFILTER_FILE "ep11cpfilter.conf"
/* error rc for reading the adapter config file */
static const int APQN_FILE_INV = 3;
static const int APQN_FILE_INV_FILE_SIZE = 5;
static const int APQN_FILE_SYNTAX_ERROR_0 = 7;
static const int APQN_FILE_SYNTAX_ERROR_1 = 8;
static const int APQN_FILE_SYNTAX_ERROR_2 = 9;
static const int APQN_FILE_SYNTAX_ERROR_3 = 10;
static const int APQN_FILE_SYNTAX_ERROR_4 = 11;
static const int APQN_FILE_SYNTAX_ERROR_5 = 12;
static const int APQN_FILE_NO_APQN_GIVEN = 13;
static const int APQN_FILE_NO_APQN_MODE = 14;
static const int APQN_FILE_UNEXPECTED_END_OF_FILE = 15;
static const int APQN_FILE_SYNTAX_ERROR_6 = 16;
static const int APQN_FILE_SYNTAX_ERROR_7 = 17;
static const int APQN_FILE_SYNTAX_ERROR_8 = 18;
static const int APQN_OUT_OF_MEMORY = 19;
static int read_adapter_config_file(STDLL_TokData_t * tokdata,
const char *conf_name);
static int read_cp_filter_config_file(const char *conf_name,
cp_config_t ** cp_config);
/*
* EP11 specific return codes
*/
#define CKR_IBM_WKID_MISMATCH CKR_VENDOR_DEFINED + 0x00010001
#define CKR_IBM_INTERNAL_ERROR CKR_VENDOR_DEFINED + 0x00010002
#define CKR_IBM_TRANSPORT_ERROR CKR_VENDOR_DEFINED + 0x00010003
#define CKR_IBM_BLOB_ERROR CKR_VENDOR_DEFINED + 0x00010004
#define CKR_IBM_BLOBKEY_CONFLICT CKR_VENDOR_DEFINED + 0x00010005
#define CKR_IBM_MODE_CONFLICT CKR_VENDOR_DEFINED + 0x00010006
#define CKR_IBM_NONCRT_KEY_SIZE CKR_VENDOR_DEFINED + 0x00010008
#define CKR_IBM_WK_NOT_INITIALIZED CKR_VENDOR_DEFINED + 0x00010009
#define CKR_IBM_OA_API_ERROR CKR_VENDOR_DEFINED + 0x0001000a
#define CKR_IBM_REQ_TIMEOUT CKR_VENDOR_DEFINED + 0x0001000b
#define CKR_IBM_READONLY CKR_VENDOR_DEFINED + 0x0001000c
#define CKR_IBM_STATIC_POLICY CKR_VENDOR_DEFINED + 0x0001000d
#define CKR_IBM_TRANSPORT_LIMIT CKR_VENDOR_DEFINED + 0x00010010
static CK_RV ep11_error_to_pkcs11_error(CK_RV rc, SESSION *session)
{
if (rc < CKR_VENDOR_DEFINED)
return rc;
TRACE_ERROR("%s ep11 specific error: rc=0x%lx\n", __func__, rc);
if (session != NULL)
session->session_info.ulDeviceError = rc;
switch (rc) {
case CKR_IBM_INTERNAL_ERROR:
case CKR_IBM_TRANSPORT_ERROR:
case CKR_IBM_OA_API_ERROR:
case CKR_IBM_TRANSPORT_LIMIT:
case CKR_IBM_REQ_TIMEOUT:
return CKR_FUNCTION_FAILED;
case CKR_IBM_WKID_MISMATCH:
case CKR_IBM_WK_NOT_INITIALIZED:
return CKR_DEVICE_ERROR;
case CKR_IBM_STATIC_POLICY:
return CKR_KEY_SIZE_RANGE;
case CKR_IBM_READONLY:
return CKR_ARGUMENTS_BAD;
case CKR_IBM_BLOB_ERROR:
case CKR_IBM_BLOBKEY_CONFLICT:
return CKR_ENCRYPTED_DATA_INVALID;
case CKR_IBM_MODE_CONFLICT:
case CKR_IBM_NONCRT_KEY_SIZE:
return CKR_ARGUMENTS_BAD;
default:
return CKR_FUNCTION_FAILED;
}
}
/* import a DES/AES key, that is, make a blob for a DES/AES key
* that was not created by EP11 hardware, encrypt the key by the wrap key,
* unwrap it by the wrap key
*/
static CK_RV rawkey_2_blob(STDLL_TokData_t * tokdata, SESSION * sess,
unsigned char *key,
CK_ULONG ksize, CK_KEY_TYPE ktype,
unsigned char *blob, size_t * blen, OBJECT * key_obj)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_BYTE cipher[MAX_BLOBSIZE];
CK_ULONG clen = sizeof(cipher);
CK_BYTE csum[MAX_CSUMSIZE];
size_t cslen = sizeof(csum);
CK_BYTE iv[AES_BLOCK_SIZE];
CK_MECHANISM mech = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE };
DL_NODE *node = key_obj->template->attribute_list;
CK_RV rc;
CK_ATTRIBUTE_PTR p_attrs = NULL;
CK_ULONG attrs_len = 0;
CK_ATTRIBUTE_PTR new_p_attrs = NULL;
CK_ULONG new_attrs_len = 0;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
/* tell ep11 the attributes the user specified */
node = key_obj->template->attribute_list;
while (node != NULL) {
CK_ATTRIBUTE_PTR a = node->data;
/* ep11 handles this as 'read only' and reports
* an error if specified
*/
if (CKA_NEVER_EXTRACTABLE == a->type || CKA_MODIFIABLE == a->type
|| CKA_LOCAL == a->type) {
;
} else {
rc = add_to_attribute_array(&p_attrs, &attrs_len,
a->type, a->pValue, a->ulValueLen);
if (rc != CKR_OK) {
TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n",
__func__, a->type, rc);
goto rawkey_2_blob_end;
}
}
node = node->next;
}
memset(cipher, 0, sizeof(cipher));
memcpy(iv, "1234567812345678", AES_BLOCK_SIZE);
/*
* calls the ep11 lib (which in turns sends the request to the card),
* all m_ function are ep11 functions
*/
RETRY_START
rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l, &mech, key,
ksize, cipher, &clen, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s encrypt ksize=0x%lx clen=0x%lx rc=0x%lx\n",
__func__, ksize, clen, rc);
goto rawkey_2_blob_end;
}
TRACE_INFO("%s encrypt ksize=0x%lx clen=0x%lx rc=0x%lx\n",
__func__, ksize, clen, rc);
rc = check_key_attributes(tokdata, ktype, CKO_SECRET_KEY, p_attrs,
attrs_len, &new_p_attrs, &new_attrs_len, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
return rc;
}
ep11_get_pin_blob(ep11_session, object_is_session_object(key_obj),
&ep11_pin_blob, &ep11_pin_blob_len);
/* the encrypted key is decrypted and a blob is build,
* card accepts only blobs as keys
*/
RETRY_START
rc = dll_m_UnwrapKey(cipher, clen, ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l, NULL, ~0,
ep11_pin_blob, ep11_pin_blob_len, &mech,
new_p_attrs, new_attrs_len, blob, blen, csum,
&cslen, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s unwrap blen=%zd rc=0x%lx\n", __func__, *blen, rc);
} else {
TRACE_INFO("%s unwrap blen=%zd rc=0x%lx\n", __func__, *blen, rc);
}
rawkey_2_blob_end:
if (p_attrs != NULL)
free_attribute_array(p_attrs, attrs_len);
if (new_p_attrs)
free_attribute_array(new_p_attrs, new_attrs_len);
return rc;
}
/* random number generator */
CK_RV token_specific_rng(STDLL_TokData_t * tokdata, CK_BYTE * output,
CK_ULONG bytes)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc = dll_m_GenerateRandom(output, bytes, ep11_data->target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s output=%p bytes=%lu rc=0x%lx\n",
__func__, (void *)output, bytes, rc);
}
return rc;
}
/*
* for importing keys we need to encrypt the keys and build the blob by
* m_UnwrapKey, use one wrap key for this purpose, can be any key,
* we use an AES key
*/
static CK_RV make_wrapblob(STDLL_TokData_t * tokdata, CK_ATTRIBUTE * tmpl_in,
CK_ULONG tmpl_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_MECHANISM mech = { CKM_AES_KEY_GEN, NULL_PTR, 0 };
CK_BYTE csum[MAX_CSUMSIZE];
size_t csum_l = sizeof(csum);
CK_RV rc;
if (ep11_data->raw2key_wrap_blob_l != 0) {
TRACE_INFO("%s blob already exists raw2key_wrap_blob_l=0x%zx\n",
__func__, ep11_data->raw2key_wrap_blob_l);
return CKR_OK;
}
ep11_data->raw2key_wrap_blob_l = sizeof(ep11_data->raw2key_wrap_blob);
rc = dll_m_GenerateKey(&mech, tmpl_in, tmpl_len, NULL, 0,
ep11_data->raw2key_wrap_blob,
&ep11_data->raw2key_wrap_blob_l, csum, &csum_l,
ep11_data->target);
if (rc != CKR_OK) {
TRACE_ERROR("%s end raw2key_wrap_blob_l=0x%zx rc=0x%lx\n",
__func__, ep11_data->raw2key_wrap_blob_l, rc);
} else {
TRACE_INFO("%s end raw2key_wrap_blob_l=0x%zx rc=0x%lx\n",
__func__, ep11_data->raw2key_wrap_blob_l, rc);
}
return rc;
}
#ifdef EP11_HSMSIM
#define DLOPEN_FLAGS RTLD_GLOBAL | RTLD_NOW | RTLD_DEEPBIND
#else
#define DLOPEN_FLAGS RTLD_GLOBAL | RTLD_NOW
#endif
static void *ep11_load_host_lib()
{
void *lib_ep11;
char *ep11_lib_name;
char *errstr;
ep11_lib_name = secure_getenv(EP11SHAREDLIB_NAME);
if (ep11_lib_name != NULL) {
lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS);
if (lib_ep11 == NULL) {
errstr = dlerror();
OCK_SYSLOG(LOG_ERR,
"%s: Error loading shared library '%s' [%s]\n",
__func__, ep11_lib_name, errstr);
TRACE_ERROR("%s Error loading shared library '%s' [%s]\n",
__func__, ep11_lib_name, errstr);
return NULL;
}
return lib_ep11;
}
ep11_lib_name = EP11SHAREDLIB_V3;
lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS);
if (lib_ep11 == NULL) {
TRACE_DEVEL("%s Error loading shared library '%s', trying '%s'\n",
__func__, EP11SHAREDLIB_V3, EP11SHAREDLIB_V2);
/* Try version 2 instead */
ep11_lib_name = EP11SHAREDLIB_V2;
lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS);
}
if (lib_ep11 == NULL) {
TRACE_DEVEL("%s Error loading shared library '%s', trying '%s'\n",
__func__, EP11SHAREDLIB_V2, EP11SHAREDLIB_V1);
/* Try version 1 instead */
ep11_lib_name = EP11SHAREDLIB_V1;
lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS);
}
if (lib_ep11 == NULL) {
TRACE_DEVEL("%s Error loading shared library '%s', trying '%s'\n",
__func__, EP11SHAREDLIB_V1, EP11SHAREDLIB);
/* Try unversioned library instead */
ep11_lib_name = EP11SHAREDLIB;
lib_ep11 = dlopen(ep11_lib_name, DLOPEN_FLAGS);
}
if (lib_ep11 == NULL) {
errstr = dlerror();
OCK_SYSLOG(LOG_ERR,
"%s: Error loading shared library '%s[.3|.2|.1]' [%s]\n",
__func__, EP11SHAREDLIB, errstr);
TRACE_ERROR("%s Error loading shared library '%s[.3|.2|.1]' [%s]\n",
__func__, EP11SHAREDLIB, errstr);
return NULL;
}
return lib_ep11;
}
static CK_RV ep11_resolve_lib_sym(void *hdl)
{
char *error = NULL;
dlerror(); /* Clear existing error */
*(void **)(&dll_m_GenerateRandom) = dlsym(hdl, "m_GenerateRandom");
*(void **)(&dll_m_SeedRandom) = dlsym(hdl, "m_SeedRandom");
*(void **)(&dll_m_Digest) = dlsym(hdl, "m_Digest");
*(void **)(&dll_m_DigestInit) = dlsym(hdl, "m_DigestInit");
*(void **)(&dll_m_DigestUpdate) = dlsym(hdl, "m_DigestUpdate");
*(void **)(&dll_m_DigestFinal) = dlsym(hdl, "m_DigestFinal");
*(void **)(&dll_m_DigestKey) = dlsym(hdl, "m_DigestKey");
*(void **)(&dll_m_DigestSingle) = dlsym(hdl, "m_DigestSingle");
*(void **)(&dll_m_Encrypt) = dlsym(hdl, "m_Encrypt");
*(void **)(&dll_m_EncryptInit) = dlsym(hdl, "m_EncryptInit");
*(void **)(&dll_m_EncryptUpdate) = dlsym(hdl, "m_EncryptUpdate");
*(void **)(&dll_m_EncryptFinal) = dlsym(hdl, "m_EncryptFinal");
*(void **)(&dll_m_EncryptSingle) = dlsym(hdl, "m_EncryptSingle");
*(void **)(&dll_m_Decrypt) = dlsym(hdl, "m_Decrypt");
*(void **)(&dll_m_DecryptInit) = dlsym(hdl, "m_DecryptInit");
*(void **)(&dll_m_DecryptUpdate) = dlsym(hdl, "m_DecryptUpdate");
*(void **)(&dll_m_DecryptFinal) = dlsym(hdl, "m_DecryptFinal");
*(void **)(&dll_m_DecryptSingle) = dlsym(hdl, "m_DecryptSingle");
*(void **)(&dll_m_ReencryptSingle) = dlsym(hdl, "m_ReencryptSingle");
*(void **)(&dll_m_GenerateKey) = dlsym(hdl, "m_GenerateKey");
*(void **)(&dll_m_GenerateKeyPair) = dlsym(hdl, "m_GenerateKeyPair");
*(void **)(&dll_m_Sign) = dlsym(hdl, "m_Sign");
*(void **)(&dll_m_SignInit) = dlsym(hdl, "m_SignInit");
*(void **)(&dll_m_SignUpdate) = dlsym(hdl, "m_SignUpdate");
*(void **)(&dll_m_SignFinal) = dlsym(hdl, "m_SignFinal");
*(void **)(&dll_m_SignSingle) = dlsym(hdl, "m_SignSingle");
*(void **)(&dll_m_Verify) = dlsym(hdl, "m_Verify");
*(void **)(&dll_m_VerifyInit) = dlsym(hdl, "m_VerifyInit");
*(void **)(&dll_m_VerifyUpdate) = dlsym(hdl, "m_VerifyUpdate");
*(void **)(&dll_m_VerifyFinal) = dlsym(hdl, "m_VerifyFinal");
*(void **)(&dll_m_VerifySingle) = dlsym(hdl, "m_VerifySingle");
*(void **)(&dll_m_WrapKey) = dlsym(hdl, "m_WrapKey");
*(void **)(&dll_m_UnwrapKey) = dlsym(hdl, "m_UnwrapKey");
*(void **)(&dll_m_DeriveKey) = dlsym(hdl, "m_DeriveKey");
*(void **)(&dll_m_GetMechanismList) = dlsym(hdl, "m_GetMechanismList");
*(void **)(&dll_m_GetMechanismInfo) = dlsym(hdl, "m_GetMechanismInfo");
*(void **)(&dll_m_GetAttributeValue) = dlsym(hdl, "m_GetAttributeValue");
*(void **)(&dll_m_SetAttributeValue) = dlsym(hdl, "m_SetAttributeValue");
*(void **)(&dll_m_Login) = dlsym(hdl, "m_Login");
*(void **)(&dll_m_Logout) = dlsym(hdl, "m_Logout");
*(void **)(&dll_m_admin) = dlsym(hdl, "m_admin");
*(void **)(&dll_m_init) = dlsym(hdl, "m_init");
*(void **)(&dll_m_add_backend) = dlsym(hdl, "m_add_backend");
*(void **)(&dll_m_shutdown) = dlsym(hdl, "m_shutdown");
*(void **)(&dll_xcpa_queryblock) = dlsym(hdl, "xcpa_queryblock");
*(void **)(&dll_xcpa_internal_rv) = dlsym(hdl, "xcpa_internal_rv");
*(void **)(&dll_m_get_xcp_info) = dlsym(hdl, "m_get_xcp_info");
if ((error = dlerror()) != NULL) {
TRACE_ERROR("%s Error: %s\n", __func__, error);
OCK_SYSLOG(LOG_ERR, "%s: Error: %s\n", __func__, error);
return CKR_FUNCTION_FAILED;
}
/*
* The following are only available since EP11 host library version 2.
* Ignore if they fail to load, the code will fall back to the old target
* handling in this case.
*/
*(void **)(&dll_m_add_module) = dlsym(hdl, "m_add_module");
*(void **)(&dll_m_rm_module) = dlsym(hdl, "m_rm_module");
if (dll_m_add_module == NULL || dll_m_rm_module == NULL) {
dll_m_add_module = NULL;
dll_m_rm_module = NULL;
}
return CKR_OK;
}
static CK_RV ep11tok_load_libica(STDLL_TokData_t *tokdata)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
libica_t *libica = &ep11_data->libica;
int default_libica = 0;
char *errstr;
if (ep11_data->digest_libica == 0)
return CKR_OK;
if (strcmp(ep11_data->digest_libica_path, "") == 0) {
strcpy(ep11_data->digest_libica_path, ICASHAREDLIB);
default_libica = 1;
}
libica->library = dlopen(ep11_data->digest_libica_path,
RTLD_GLOBAL | RTLD_NOW);
if (libica->library == NULL) {
errstr = dlerror();
OCK_SYSLOG(default_libica ? LOG_WARNING : LOG_ERR,
"%s: Error loading shared library '%s' [%s]\n",
__func__, ep11_data->digest_libica_path, errstr);
TRACE_ERROR("%s Error loading shared library '%s' [%s]\n",
__func__, ep11_data->digest_libica_path, errstr);
ep11_data->digest_libica = 0;
return default_libica ? CKR_OK : CKR_FUNCTION_FAILED;
}
*(void **)(&libica->ica_sha1) = dlsym(libica->library, "ica_sha1");
*(void **)(&libica->ica_sha224) = dlsym(libica->library, "ica_sha224");
*(void **)(&libica->ica_sha256) = dlsym(libica->library, "ica_sha256");
*(void **)(&libica->ica_sha384) = dlsym(libica->library, "ica_sha384");
*(void **)(&libica->ica_sha512) = dlsym(libica->library, "ica_sha512");
*(void **)(&libica->ica_sha512_224) =
dlsym(libica->library, "ica_sha512_224");
*(void **)(&libica->ica_sha512_256) =
dlsym(libica->library, "ica_sha512_256");
#ifdef SHA3_224
*(void **)(&libica->ica_sha3_224) = dlsym(libica->library, "ica_sha3_224");
*(void **)(&libica->ica_sha3_256) = dlsym(libica->library, "ica_sha3_256");
*(void **)(&libica->ica_sha3_384) = dlsym(libica->library, "ica_sha3_384");
*(void **)(&libica->ica_sha3_512) = dlsym(libica->library, "ica_sha3_512");
#endif
/* No error checking, each of the libica functions is allowed to be NULL */
TRACE_DEVEL("%s: Loaded libica from '%s'\n", __func__,
ep11_data->digest_libica_path);
return CKR_OK;
}
CK_RV ep11tok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber,
char *conf_name)
{
CK_RV rc;
void *lib_ep11;
CK_ULONG len = 16;
CK_BBOOL cktrue = 1;
CK_ATTRIBUTE wrap_tmpl[] = { {CKA_VALUE_LEN, &len, sizeof(CK_ULONG)}
,
{CKA_WRAP, (void *) &cktrue, sizeof(cktrue)}
,
{CKA_UNWRAP, (void *) &cktrue, sizeof(cktrue)}
,
{CKA_ENCRYPT, (void *) &cktrue, sizeof(cktrue)}
,
{CKA_DECRYPT, (void *) &cktrue, sizeof(cktrue)}
,
{CKA_EXTRACTABLE, (void *) &cktrue, sizeof(cktrue)}
,
{CKA_LABEL, (void *) wrap_key_name, sizeof(wrap_key_name)}
,
{CKA_TOKEN, (void *) &cktrue, sizeof(cktrue)}
};
ep11_private_data_t *ep11_data;
TRACE_INFO("ep11 %s slot=%lu running\n", __func__, SlotNumber);
ep11_data = calloc(1, sizeof(ep11_private_data_t));
if (ep11_data == NULL)
return CKR_HOST_MEMORY;
tokdata->private_data = ep11_data;
/* read ep11 specific config file with user specified
* adapter/domain pairs */
rc = read_adapter_config_file(tokdata, conf_name);
if (rc != CKR_OK) {
TRACE_ERROR("%s ep11 config file error rc=0x%lx\n", __func__, rc);
rc = CKR_GENERAL_ERROR;
goto error;
}
/* dynamically load in the ep11 shared library */
lib_ep11 = ep11_load_host_lib();
if (lib_ep11 == NULL) {
rc = CKR_FUNCTION_FAILED;
goto error;
}
rc = ep11_resolve_lib_sym(lib_ep11);
if (rc != CKR_OK)
goto error;
#ifndef XCP_STANDALONE
/* call ep11 shared lib init */
if (dll_m_init() < 0) {
TRACE_ERROR("%s ep11 lib init failed\n", __func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: EP 11 library initialization failed\n",
__func__);
rc = CKR_DEVICE_ERROR;
goto error;
}
#endif
rc = ep11tok_get_ep11_version(tokdata);
if (rc != CKR_OK)
goto error;
rc = ep11tok_setup_target(tokdata);
if (rc != CKR_OK)
goto error;
if (ep11_data->digest_libica) {
rc = ep11tok_load_libica(tokdata);
if (rc != CKR_OK)
goto error;
}
ep11_data->control_points_len = sizeof(ep11_data->control_points);
rc = get_control_points(tokdata, ep11_data->control_points,
&ep11_data->control_points_len,
&ep11_data->max_control_point_index);
if (rc != CKR_OK) {
TRACE_ERROR("%s Failed to get the control points (get_control_points "
"rc=0x%lx)\n", __func__, rc);
OCK_SYSLOG(LOG_ERR, "%s: Failed to get the control points rc=0x%lx\n",
__func__, rc);
goto error;
}
/* create an AES key needed for importing keys
* (encrypt by wrap_key and m_UnwrapKey by wrap key)
*/
rc = make_wrapblob(tokdata, wrap_tmpl, 8);
if (rc != CKR_OK) {
TRACE_ERROR("%s make_wrapblob failed rc=0x%lx\n", __func__, rc);
if (rc == CKR_IBM_WK_NOT_INITIALIZED) {
TRACE_ERROR("%s rc is CKR_IBM_WK_NOT_INITIALIZED, "
"no master key set ?\n", __func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: CKR_IBM_WK_NOT_INITIALIZED occurred, no "
"master key set ?\n", __func__);
}
if (rc == CKR_FUNCTION_CANCELED) {
TRACE_ERROR("%s rc is CKR_FUNCTION_CANCELED, "
"control point 13 (generate or derive symmetric "
"keys including DSA parameters) disabled ?\n",
__func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: CKR_FUNCTION_CANCELED occurred, "
"control point 13 (generate or derive symmetric "
"keys including DSA parameters) disabled ?\n", __func__);
}
rc = CKR_GENERAL_ERROR;
goto error;
}
TRACE_INFO("%s init done successfully\n", __func__);
return CKR_OK;
error:
ep11tok_final(tokdata);
TRACE_INFO("%s init failed with rc: 0x%lx\n", __func__, rc);
return rc;
}
CK_RV ep11tok_final(STDLL_TokData_t * tokdata)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
TRACE_INFO("ep11 %s running\n", __func__);
if (ep11_data != NULL) {
if (dll_m_rm_module != NULL)
dll_m_rm_module(NULL, ep11_data->target);
free_cp_config(ep11_data->cp_config);
free_card_versions(ep11_data->card_versions);
free(ep11_data);
tokdata->private_data = NULL;
}
return CKR_OK;
}
/*
* Makes a public key blob which is a MACed SPKI of the public key.
*/
static CK_RV make_maced_spki(STDLL_TokData_t *tokdata, SESSION * sess,
OBJECT *pub_key_obj,
CK_BYTE *spki, CK_ULONG spki_len,
CK_BYTE *maced_spki, CK_ULONG *maced_spki_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
CK_MECHANISM mech = { CKM_IBM_TRANSPORTKEY, 0, 0 };
CK_ATTRIBUTE_PTR p_attrs = NULL;
CK_ULONG attrs_len = 0;
CK_ATTRIBUTE_PTR attr;
CK_BBOOL bool_value;
DL_NODE *node;
CK_BYTE csum[MAX_BLOBSIZE];
CK_ULONG cslen = sizeof(csum);
CK_KEY_TYPE keytype;
CK_RV rc;
rc = template_attribute_find(pub_key_obj->template, CKA_KEY_TYPE, &attr);
if (rc == FALSE) {
TRACE_ERROR("Could not find CKA_KEY_TYPE for the key.\n");
return CKR_TEMPLATE_INCOMPLETE;
}
keytype = *(CK_KEY_TYPE *)attr->pValue;
/*
* m_UnwrapKey with CKM_IBM_TRANSPORTKEY allows boolean attributes only to
* be added to MACed-SPKIs
*/
node = pub_key_obj->template->attribute_list;
while (node != NULL) {
attr = node->data;
switch (attr->type) {
case CKA_ENCRYPT:
case CKA_VERIFY:
case CKA_VERIFY_RECOVER:
/*
* EP11 does not allow to restrict public RSA/DSA/EC keys with
* CKA_VERIFY=FALSE and/or CKA_ENCRYPT=FALSE since it can not
* technically enforce the restrictions. Therefore override these
* attributes for the EP11 library, but keep the original attribute
* values in the object.
*/
if (keytype == CKK_EC || keytype == CKK_RSA || keytype == CKK_DSA)
bool_value = CK_TRUE;
else
bool_value = *(CK_BBOOL *)attr->pValue;
rc = add_to_attribute_array(&p_attrs, &attrs_len, attr->type,
&bool_value, sizeof(bool_value));
if (rc != CKR_OK) {
TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n",
__func__, attr->type, rc);
goto make_maced_spki_end;
}
break;
case CKA_EXTRACTABLE:
//case CKA_NEVER_EXTRACTABLE:
//case CKA_MODIFIABLE:
case CKA_DERIVE:
case CKA_WRAP:
//case CKA_LOCAL:
case CKA_TRUSTED:
case CKA_IBM_RESTRICTABLE:
case CKA_IBM_NEVER_MODIFIABLE:
case CKA_IBM_ATTRBOUND:
case CKA_IBM_USE_AS_DATA:
rc = add_to_attribute_array(&p_attrs, &attrs_len, attr->type,
attr->pValue, attr->ulValueLen);
if (rc != CKR_OK) {
TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n",
__func__, attr->type, rc);
goto make_maced_spki_end;
}
break;
default:
break;
}
node = node->next;
}
ep11_get_pin_blob(ep11_session, object_is_session_object(pub_key_obj),
&ep11_pin_blob, &ep11_pin_blob_len);
RETRY_START
rc = dll_m_UnwrapKey(spki, spki_len, NULL, 0, NULL, 0,
ep11_pin_blob, ep11_pin_blob_len, &mech,
p_attrs, attrs_len, maced_spki, maced_spki_len,
csum, &cslen, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s unwrapping SPKI rc=0x%lx spki_len=0x%zx maced_spki_len=0x%zx\n",
__func__, rc, spki_len, *maced_spki_len);
} else {
TRACE_INFO("%s unwrapping SPKI rc=0x%lx spki_len=0x%zx maced_spki_len=0x%zx\n",
__func__, rc, spki_len, *maced_spki_len);
}
make_maced_spki_end:
if (p_attrs != NULL)
cleanse_and_free_attribute_array(p_attrs, attrs_len);
return rc;
}
/*
* makes blobs for private imported RSA keys and
* SPKIs for public imported RSA keys.
* Similar to rawkey_2_blob, but keys must follow a standard BER encoding.
*/
static CK_RV import_RSA_key(STDLL_TokData_t * tokdata, SESSION * sess,
OBJECT * rsa_key_obj,
CK_BYTE * blob, size_t * blob_size)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE iv[AES_BLOCK_SIZE];
CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE };
CK_BYTE cipher[MAX_BLOBSIZE];
CK_ULONG cipher_l = sizeof(cipher);
DL_NODE *node;
CK_ATTRIBUTE_PTR p_attrs = NULL;
CK_ULONG attrs_len = 0;
CK_ATTRIBUTE_PTR new_p_attrs = NULL;
CK_ULONG new_attrs_len = 0;
CK_BYTE csum[MAX_BLOBSIZE];
CK_ULONG cslen = sizeof(csum);
CK_OBJECT_CLASS class;
CK_BYTE *data = NULL;
CK_ULONG data_len;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
memcpy(iv, "1234567812345678", AES_BLOCK_SIZE);
/* need class for private/public key info */
if (!template_attribute_find(rsa_key_obj->template, CKA_CLASS, &attr)) {
TRACE_ERROR("%s no CKA_CLASS\n", __func__);
return CKR_TEMPLATE_INCOMPLETE;
}
/* m_Unwrap builds key blob in the card,
* tell ep11 the attributes the user specified for that key.
*/
node = rsa_key_obj->template->attribute_list;
while (node != NULL) {
CK_ATTRIBUTE_PTR a = node->data;
/* ep11 handles this as 'read only' */
if (CKA_NEVER_EXTRACTABLE == a->type ||
CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) {
;
} else {
rc = add_to_attribute_array(&p_attrs, &attrs_len,
a->type, a->pValue, a->ulValueLen);
if (rc != CKR_OK) {
TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n",
__func__, a->type, rc);
goto import_RSA_key_end;
}
}
node = node->next;
}
class = *(CK_OBJECT_CLASS *) attr->pValue;
if (class != CKO_PRIVATE_KEY) {
/* an imported public RSA key, we need a SPKI for it. */
CK_ATTRIBUTE *modulus;
CK_ATTRIBUTE *publ_exp;
if (!template_attribute_find(rsa_key_obj->template,
CKA_MODULUS, &modulus)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_RSA_key_end;
}
if (!template_attribute_find(rsa_key_obj->template,
CKA_PUBLIC_EXPONENT, &publ_exp)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_RSA_key_end;
}
/* our contribution to asn1.c,
* builds the BER encoding that is a SPKI.
*/
rc = ber_encode_RSAPublicKey(0, &data, &data_len, modulus, publ_exp);
if (rc != CKR_OK) {
TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
goto import_RSA_key_end;
} else {
TRACE_INFO("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
}
/* save the SPKI as blob although it is not a blob.
* The card expects MACed-SPKIs as public keys.
*/
rc = make_maced_spki(tokdata, sess, rsa_key_obj, data, data_len,
blob, blob_size);
if (rc != CKR_OK) {
TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n",
__func__, rc);
goto import_RSA_key_end;
}
} else {
/* imported private RSA key goes here */
/* extract the secret data to be wrapped
* since this is AES_CBC_PAD, padding is done in mechanism.
*/
rc = rsa_priv_wrap_get_data(rsa_key_obj->template, FALSE,
&data, &data_len);
if (rc != CKR_OK) {
TRACE_DEVEL("%s RSA wrap get data failed\n", __func__);
goto import_RSA_key_end;
}
/* encrypt */
RETRY_START
rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l, &mech_w,
data, data_len, cipher, &cipher_l,
ep11_data->target);
RETRY_END(rc, tokdata, sess)
TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
goto import_RSA_key_end;
}
rc = check_key_attributes(tokdata, CKK_RSA, CKO_PRIVATE_KEY, p_attrs,
attrs_len, &new_p_attrs, &new_attrs_len, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto import_RSA_key_end;
}
ep11_get_pin_blob(ep11_session, object_is_session_object(rsa_key_obj),
&ep11_pin_blob, &ep11_pin_blob_len);
/* calls the card, it decrypts the private RSA key,
* reads its BER format and builds a blob.
*/
RETRY_START
rc = dll_m_UnwrapKey(cipher, cipher_l, ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l, NULL, ~0,
ep11_pin_blob, ep11_pin_blob_len, &mech_w,
new_p_attrs, new_attrs_len, blob, blob_size,
csum, &cslen, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
} else {
TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
}
cleanse_attribute(rsa_key_obj->template, CKA_PRIVATE_EXPONENT);
cleanse_attribute(rsa_key_obj->template, CKA_PRIME_1);
cleanse_attribute(rsa_key_obj->template, CKA_PRIME_2);
cleanse_attribute(rsa_key_obj->template, CKA_EXPONENT_1);
cleanse_attribute(rsa_key_obj->template, CKA_EXPONENT_2);
cleanse_attribute(rsa_key_obj->template, CKA_COEFFICIENT);
}
import_RSA_key_end:
if (data) {
OPENSSL_cleanse(data, data_len);
free(data);
}
if (p_attrs != NULL)
cleanse_and_free_attribute_array(p_attrs, attrs_len);
if (new_p_attrs)
cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len);
return rc;
}
/*
* makes blobs for private imported EC keys and
* SPKIs for public imported EC keys.
* Similar to rawkey_2_blob, but keys must follow a standard BER encoding.
*/
static CK_RV import_EC_key(STDLL_TokData_t * tokdata, SESSION * sess,
OBJECT * ec_key_obj,
CK_BYTE * blob, size_t * blob_size)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE iv[AES_BLOCK_SIZE];
CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE };
CK_BYTE cipher[MAX_BLOBSIZE];
CK_ULONG cipher_l = sizeof(cipher);
DL_NODE *node;
CK_ATTRIBUTE_PTR p_attrs = NULL;
CK_ULONG attrs_len = 0;
CK_ATTRIBUTE_PTR new_p_attrs = NULL;
CK_ULONG new_attrs_len = 0;
CK_BYTE csum[MAX_BLOBSIZE];
CK_ULONG cslen = sizeof(csum);
CK_OBJECT_CLASS class;
CK_BYTE *data = NULL;
CK_ULONG data_len;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
CK_ULONG privkey_len, pubkey_len;
CK_BYTE *pubkey = NULL;
memcpy(iv, "1234567812345678", AES_BLOCK_SIZE);
/* need class for private/public key info */
if (!template_attribute_find(ec_key_obj->template, CKA_CLASS, &attr)) {
TRACE_ERROR("%s no CKA_CLASS\n", __func__);
return CKR_TEMPLATE_INCOMPLETE;
}
/* m_Unwrap builds key blob in the card,
* tell ep11 the attributes the user specified for that key.
*/
node = ec_key_obj->template->attribute_list;
while (node != NULL) {
CK_ATTRIBUTE_PTR a = node->data;
/* ep11 handles this as 'read only' */
if (CKA_NEVER_EXTRACTABLE == a->type ||
CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) {
;
} else {
rc = add_to_attribute_array(&p_attrs, &attrs_len,
a->type, a->pValue, a->ulValueLen);
if (rc != CKR_OK) {
TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n",
__func__, a->type, rc);
goto import_EC_key_end;
}
}
node = node->next;
}
class = *(CK_OBJECT_CLASS *) attr->pValue;
if (class != CKO_PRIVATE_KEY) {
/* an imported public EC key, we need a SPKI for it. */
CK_ATTRIBUTE *ec_params;
CK_ATTRIBUTE *ec_point_attr;
CK_ATTRIBUTE ec_point_uncompr;
CK_BYTE *ecpoint;
CK_ULONG ecpoint_len, field_len;
if (!template_attribute_find(ec_key_obj->template,
CKA_EC_PARAMS, &ec_params)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_EC_key_end;
}
if (!template_attribute_find(ec_key_obj->template,
CKA_EC_POINT, &ec_point_attr)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_EC_key_end;
}
/* CKA_EC_POINT is an BER encoded OCTET STRING. Extract it. */
rc = ber_decode_OCTET_STRING((CK_BYTE *)ec_point_attr->pValue, &ecpoint,
&ecpoint_len, &field_len);
if (rc != CKR_OK || ec_point_attr->ulValueLen != field_len) {
TRACE_DEVEL("%s ber_decode_OCTET_STRING failed\n", __func__);
rc = CKR_ATTRIBUTE_VALUE_INVALID;
goto import_EC_key_end;
}
/* Uncompress the public key (EC_POINT) */
rc = get_ecsiglen(ec_key_obj, &privkey_len);
if (rc != CKR_OK)
goto import_EC_key_end;
privkey_len /= 2; /* private key is half the size of an EC signature */
pubkey_len = 1 + 2 * privkey_len;
pubkey = (CK_BYTE *)malloc(pubkey_len);
if (pubkey == NULL) {
rc = CKR_HOST_MEMORY;
goto import_EC_key_end;
}
rc = ec_uncompress_public_key(ec_params->pValue, ec_params->ulValueLen,
ecpoint, ecpoint_len,
privkey_len, pubkey, &pubkey_len);
if (rc != CKR_OK)
goto import_EC_key_end;
/* build ec-point attribute as BER encoded OCTET STRING */
rc = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len,
pubkey, pubkey_len);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_OCTET_STRING failed\n");
goto import_EC_key_end;
}
ec_point_uncompr.type = ec_point_attr->type;
ec_point_uncompr.pValue = ecpoint;
ec_point_uncompr.ulValueLen = ecpoint_len;
/*
* Builds the DER encoding (ansi_x962) SPKI.
* (get the length first)
*/
rc = ber_encode_ECPublicKey(TRUE, &data, &data_len,
ec_params, &ec_point_uncompr);
data = malloc(data_len);
rc = ber_encode_ECPublicKey(FALSE, &data, &data_len,
ec_params, &ec_point_uncompr);
free(ecpoint);
if (rc != CKR_OK) {
TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
goto import_EC_key_end;
} else {
TRACE_INFO("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
}
/* save the SPKI as blob although it is not a blob.
* The card expects MACed-SPKIs as public keys.
*/
rc = make_maced_spki(tokdata, sess, ec_key_obj, data, data_len,
blob, blob_size);
if (rc != CKR_OK) {
TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n",
__func__, rc);
goto import_EC_key_end;
}
} else {
/* imported private EC key goes here */
CK_ATTRIBUTE *ec_params;
int i, curve_type = -1;
if (!template_attribute_find(ec_key_obj->template,
CKA_EC_PARAMS, &ec_params)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_EC_key_end;
}
for (i = 0; i < NUMEC; i++) {
if (der_ec_supported[i].data_size == ec_params->ulValueLen &&
memcmp(ec_params->pValue, der_ec_supported[i].data,
ec_params->ulValueLen) == 0) {
curve_type = der_ec_supported[i].curve_type;
break;
}
}
/* extract the secret data to be wrapped
* since this is AES_CBC_PAD, padding is done in mechanism.
*/
rc = ecdsa_priv_wrap_get_data(ec_key_obj->template, FALSE,
&data, &data_len);
if (rc != CKR_OK) {
TRACE_DEVEL("%s EC wrap get data failed\n", __func__);
goto import_EC_key_end;
}
/* encrypt */
RETRY_START
rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l,
&mech_w, data, data_len,
cipher, &cipher_l, ep11_data->target);
RETRY_END(rc, tokdata, sess)
TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
goto import_EC_key_end;
}
rc = check_key_attributes(tokdata, CKK_EC, CKO_PRIVATE_KEY, p_attrs,
attrs_len, &new_p_attrs, &new_attrs_len,
curve_type);
if (rc != CKR_OK) {
TRACE_ERROR("%s EC check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto import_EC_key_end;
}
ep11_get_pin_blob(ep11_session, object_is_session_object(ec_key_obj),
&ep11_pin_blob, &ep11_pin_blob_len);
/* calls the card, it decrypts the private EC key,
* reads its BER format and builds a blob.
*/
RETRY_START
rc = dll_m_UnwrapKey(cipher, cipher_l,
ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l, NULL, ~0,
ep11_pin_blob,
ep11_pin_blob_len, &mech_w,
new_p_attrs, new_attrs_len, blob,
blob_size, csum, &cslen, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
} else {
TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
}
cleanse_attribute(ec_key_obj->template, CKA_VALUE);
}
import_EC_key_end:
if (pubkey)
free(pubkey);
if (data) {
OPENSSL_cleanse(data, data_len);
free(data);
}
if (p_attrs != NULL)
cleanse_and_free_attribute_array(p_attrs, attrs_len);
if (new_p_attrs)
cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len);
return rc;
}
/*
* makes blobs for private imported DSA keys and
* SPKIs for public imported DSA keys.
* Similar to rawkey_2_blob, but keys must follow a standard BER encoding.
*/
static CK_RV import_DSA_key(STDLL_TokData_t * tokdata, SESSION * sess,
OBJECT * dsa_key_obj,
CK_BYTE * blob, size_t * blob_size)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE iv[AES_BLOCK_SIZE];
CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE };
CK_BYTE cipher[MAX_BLOBSIZE];
CK_ULONG cipher_l = sizeof(cipher);
DL_NODE *node;
CK_ATTRIBUTE_PTR p_attrs = NULL;
CK_ULONG attrs_len = 0;
CK_ATTRIBUTE_PTR new_p_attrs = NULL;
CK_ULONG new_attrs_len = 0;
CK_BYTE csum[MAX_BLOBSIZE];
CK_ULONG cslen = sizeof(csum);
CK_OBJECT_CLASS class;
CK_BYTE *data = NULL;
CK_ULONG data_len;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
memcpy(iv, "1234567812345678", AES_BLOCK_SIZE);
/* need class for private/public key info */
if (!template_attribute_find(dsa_key_obj->template, CKA_CLASS, &attr)) {
TRACE_ERROR("%s no CKA_CLASS\n", __func__);
return CKR_TEMPLATE_INCOMPLETE;
}
/* m_Unwrap builds key blob in the card,
* tell ep11 the attributes the user specified for that key.
*/
node = dsa_key_obj->template->attribute_list;
while (node != NULL) {
CK_ATTRIBUTE_PTR a = node->data;
/* ep11 handles this as 'read only' */
if (CKA_NEVER_EXTRACTABLE == a->type ||
CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) {
;
} else {
rc = add_to_attribute_array(&p_attrs, &attrs_len,
a->type, a->pValue, a->ulValueLen);
if (rc != CKR_OK) {
TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n",
__func__, a->type, rc);
goto import_DSA_key_end;
}
}
node = node->next;
}
class = *(CK_OBJECT_CLASS *) attr->pValue;
if (class != CKO_PRIVATE_KEY) {
/* an imported public DSA key, we need a SPKI for it. */
CK_ATTRIBUTE *prime;
CK_ATTRIBUTE *subprime;
CK_ATTRIBUTE *base;
CK_ATTRIBUTE *value;
if (!template_attribute_find(dsa_key_obj->template,
CKA_PRIME, &prime)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_DSA_key_end;
}
if (!template_attribute_find(dsa_key_obj->template,
CKA_SUBPRIME, &subprime)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_DSA_key_end;
}
if (!template_attribute_find(dsa_key_obj->template, CKA_BASE, &base)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_DSA_key_end;
}
if (!template_attribute_find(dsa_key_obj->template,
CKA_VALUE, &value)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_DSA_key_end;
}
/*
* Builds the DER encoding (ansi_x962) SPKI.
* (get the length first)
*/
rc = ber_encode_DSAPublicKey(TRUE, &data, &data_len,
prime, subprime, base, value);
data = malloc(data_len);
rc = ber_encode_DSAPublicKey(FALSE, &data, &data_len,
prime, subprime, base, value);
if (rc != CKR_OK) {
TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
goto import_DSA_key_end;
} else {
TRACE_INFO("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
}
/* save the SPKI as blob although it is not a blob.
* The card expects MACed-SPKIs as public keys.
*/
rc = make_maced_spki(tokdata, sess, dsa_key_obj, data, data_len,
blob, blob_size);
if (rc != CKR_OK) {
TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n",
__func__, rc);
goto import_DSA_key_end;
}
} else {
/* imported private DSA key goes here */
/* extract the secret data to be wrapped
* since this is AES_CBC_PAD, padding is done in mechanism.
*/
rc = dsa_priv_wrap_get_data(dsa_key_obj->template, FALSE,
&data, &data_len);
if (rc != CKR_OK) {
TRACE_DEVEL("%s DSA wrap get data failed\n", __func__);
goto import_DSA_key_end;
}
/* encrypt */
RETRY_START
rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l,
&mech_w, data, data_len,
cipher, &cipher_l, ep11_data->target);
RETRY_END(rc, tokdata, sess)
TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
goto import_DSA_key_end;
}
rc = check_key_attributes(tokdata, CKK_DSA, CKO_PRIVATE_KEY, p_attrs,
attrs_len, &new_p_attrs, &new_attrs_len, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s DSA check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto import_DSA_key_end;
}
ep11_get_pin_blob(ep11_session, object_is_session_object(dsa_key_obj),
&ep11_pin_blob, &ep11_pin_blob_len);
/* calls the card, it decrypts the private EC key,
* reads its BER format and builds a blob.
*/
RETRY_START
rc = dll_m_UnwrapKey(cipher, cipher_l,
ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l, NULL, ~0,
ep11_pin_blob,
ep11_pin_blob_len, &mech_w,
new_p_attrs, new_attrs_len, blob,
blob_size, csum, &cslen, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
} else {
TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
}
cleanse_attribute(dsa_key_obj->template, CKA_VALUE);
}
import_DSA_key_end:
if (data) {
OPENSSL_cleanse(data, data_len);
free(data);
}
if (p_attrs != NULL)
cleanse_and_free_attribute_array(p_attrs, attrs_len);
if (new_p_attrs)
cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len);
return rc;
}
/*
* makes blobs for private imported DH keys and
* SPKIs for public imported DH keys.
* Similar to rawkey_2_blob, but keys must follow a standard BER encoding.
*/
static CK_RV import_DH_key(STDLL_TokData_t * tokdata, SESSION * sess,
OBJECT * dh_key_obj,
CK_BYTE * blob, size_t * blob_size)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE iv[AES_BLOCK_SIZE];
CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE };
CK_BYTE cipher[MAX_BLOBSIZE];
CK_ULONG cipher_l = sizeof(cipher);
DL_NODE *node;
CK_ATTRIBUTE_PTR p_attrs = NULL;
CK_ULONG attrs_len = 0;
CK_ATTRIBUTE_PTR new_p_attrs = NULL;
CK_ULONG new_attrs_len = 0;
CK_BYTE csum[MAX_BLOBSIZE];
CK_ULONG cslen = sizeof(csum);
CK_OBJECT_CLASS class;
CK_BYTE *data = NULL;
CK_ULONG data_len;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
memcpy(iv, "1234567812345678", AES_BLOCK_SIZE);
/* need class for private/public key info */
if (!template_attribute_find(dh_key_obj->template, CKA_CLASS, &attr)) {
TRACE_ERROR("%s no CKA_CLASS\n", __func__);
return CKR_TEMPLATE_INCOMPLETE;
}
/* m_Unwrap builds key blob in the card,
* tell ep11 the attributes the user specified for that key.
*/
node = dh_key_obj->template->attribute_list;
while (node != NULL) {
CK_ATTRIBUTE_PTR a = node->data;
/* ep11 handles this as 'read only' */
if (CKA_NEVER_EXTRACTABLE == a->type ||
CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) {
;
} else {
rc = add_to_attribute_array(&p_attrs, &attrs_len,
a->type, a->pValue, a->ulValueLen);
if (rc != CKR_OK) {
TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n",
__func__, a->type, rc);
goto import_DH_key_end;
}
}
node = node->next;
}
class = *(CK_OBJECT_CLASS *) attr->pValue;
if (class != CKO_PRIVATE_KEY) {
/* an imported public DH key, we need a SPKI for it. */
CK_ATTRIBUTE *prime;
CK_ATTRIBUTE *base;
CK_ATTRIBUTE *value;
if (!template_attribute_find(dh_key_obj->template, CKA_PRIME, &prime)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_DH_key_end;
}
if (!template_attribute_find(dh_key_obj->template, CKA_BASE, &base)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_DH_key_end;
}
if (!template_attribute_find(dh_key_obj->template, CKA_VALUE, &value)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto import_DH_key_end;
}
/*
* Builds the DER encoding (ansi_x962) SPKI.
* (get the length first)
*/
rc = ber_encode_DHPublicKey(TRUE, &data, &data_len, prime, base, value);
data = malloc(data_len);
rc = ber_encode_DHPublicKey(FALSE, &data, &data_len,
prime, base, value);
if (rc != CKR_OK) {
TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
goto import_DH_key_end;
} else {
TRACE_INFO("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
}
/* save the SPKI as blob although it is not a blob.
* The card expects MACed-SPKIs as public keys.
*/
rc = make_maced_spki(tokdata, sess, dh_key_obj, data, data_len,
blob, blob_size);
if (rc != CKR_OK) {
TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n",
__func__, rc);
goto import_DH_key_end;
}
} else {
/* imported private DH key goes here */
/* extract the secret data to be wrapped
* since this is AES_CBC_PAD, padding is done in mechanism.
*/
rc = dh_priv_wrap_get_data(dh_key_obj->template, FALSE,
&data, &data_len);
if (rc != CKR_OK) {
TRACE_DEVEL("%s DH wrap get data failed\n", __func__);
goto import_DH_key_end;
}
/* encrypt */
RETRY_START
rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l,
&mech_w, data, data_len,
cipher, &cipher_l, ep11_data->target);
RETRY_END(rc, tokdata, sess)
TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
goto import_DH_key_end;
}
rc = check_key_attributes(tokdata, CKK_DH, CKO_PRIVATE_KEY, p_attrs,
attrs_len, &new_p_attrs, &new_attrs_len, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s DH check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto import_DH_key_end;
}
ep11_get_pin_blob(ep11_session, object_is_session_object(dh_key_obj),
&ep11_pin_blob, &ep11_pin_blob_len);
/* calls the card, it decrypts the private EC key,
* reads its BER format and builds a blob.
*/
RETRY_START
rc = dll_m_UnwrapKey(cipher, cipher_l,
ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l, NULL, ~0,
ep11_pin_blob,
ep11_pin_blob_len, &mech_w,
new_p_attrs, new_attrs_len, blob,
blob_size, csum, &cslen, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
} else {
TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
}
cleanse_attribute(dh_key_obj->template, CKA_VALUE);
}
import_DH_key_end:
if (data) {
OPENSSL_cleanse(data, data_len);
free(data);
}
if (p_attrs != NULL)
cleanse_and_free_attribute_array(p_attrs, attrs_len);
if (new_p_attrs)
cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len);
return rc;
}
/*
* makes blobs for private imported IBM Dilithium keys and
* SPKIs for public imported IBM Dilithium keys.
* Similar to rawkey_2_blob, but keys must follow a standard BER encoding.
*/
static CK_RV import_IBM_Dilithium_key(STDLL_TokData_t * tokdata, SESSION * sess,
OBJECT * dilithium_key_obj,
CK_BYTE * blob, size_t * blob_size)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE iv[AES_BLOCK_SIZE];
CK_MECHANISM mech_w = { CKM_AES_CBC_PAD, iv, AES_BLOCK_SIZE };
CK_BYTE cipher[MAX_BLOBSIZE];
CK_ULONG cipher_l = sizeof(cipher);
DL_NODE *node;
CK_ATTRIBUTE_PTR p_attrs = NULL;
CK_ULONG attrs_len = 0;
CK_ATTRIBUTE_PTR new_p_attrs = NULL;
CK_ULONG new_attrs_len = 0;
CK_BYTE csum[MAX_BLOBSIZE];
CK_ULONG cslen = sizeof(csum);
CK_OBJECT_CLASS class;
CK_BYTE *data = NULL;
CK_ULONG data_len;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
CK_BYTE *pubkey = NULL;
memcpy(iv, "1234567812345678", AES_BLOCK_SIZE);
/* need class for secret/public key info */
if (!template_attribute_find(dilithium_key_obj->template, CKA_CLASS, &attr)) {
TRACE_ERROR("%s no CKA_CLASS\n", __func__);
return CKR_TEMPLATE_INCOMPLETE;
}
/* m_Unwrap builds key blob in the card,
* tell ep11 the attributes the user specified for that key.
*/
node = dilithium_key_obj->template->attribute_list;
while (node != NULL) {
CK_ATTRIBUTE_PTR a = node->data;
/* ep11 handles this as 'read only' */
if (CKA_NEVER_EXTRACTABLE == a->type ||
CKA_MODIFIABLE == a->type || CKA_LOCAL == a->type) {
;
} else {
rc = add_to_attribute_array(&p_attrs, &attrs_len,
a->type, a->pValue, a->ulValueLen);
if (rc != CKR_OK) {
TRACE_ERROR("%s adding attribute failed type=0x%lx rc=0x%lx\n",
__func__, a->type, rc);
goto done;
}
}
node = node->next;
}
class = *(CK_OBJECT_CLASS *) attr->pValue;
if (class != CKO_PRIVATE_KEY) {
/* Make an SPKI for the public IBM Dilithium key */
CK_ATTRIBUTE *keyform;
CK_ATTRIBUTE *rho;
CK_ATTRIBUTE *t1;
/* A public IBM Dilithium key must have a keyform value */
if (!template_attribute_find(dilithium_key_obj->template,
CKA_IBM_DILITHIUM_KEYFORM, &keyform)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto done;
}
/* Check if it's an expected keyform */
if (*(CK_ULONG *) keyform->pValue != IBM_DILITHIUM_KEYFORM_ROUND2) {
rc = CKR_TEMPLATE_INCONSISTENT;
goto done;
}
/* A public IBM Dilithium key must have a rho value */
if (!template_attribute_find(dilithium_key_obj->template,
CKA_IBM_DILITHIUM_RHO, &rho)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto done;
}
/* A public IBM Dilithium key must have a t1 value */
if (!template_attribute_find(dilithium_key_obj->template,
CKA_IBM_DILITHIUM_T1, &t1)) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto done;
}
/* Encode the public key */
rc = ber_encode_IBM_DilithiumPublicKey(0, &data, &data_len, rho, t1);
if (rc != CKR_OK) {
TRACE_ERROR("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
goto done;
} else {
TRACE_INFO("%s public key import class=0x%lx rc=0x%lx "
"data_len=0x%lx\n", __func__, class, rc, data_len);
}
/* save the SPKI as blob although it is not a blob.
* The card expects MACed-SPKIs as public keys.
*/
rc = make_maced_spki(tokdata, sess, dilithium_key_obj, data, data_len,
blob, blob_size);
if (rc != CKR_OK) {
TRACE_ERROR("%s failed to make a MACed-SPKI rc=0x%lx\n",
__func__, rc);
goto done;
}
} else {
/* imported private IBM Dilithium key goes here */
/* extract the secret data to be wrapped
* since this is AES_CBC_PAD, padding is done in mechanism.
*/
rc = ibm_dilithium_priv_wrap_get_data(dilithium_key_obj->template, FALSE,
&data, &data_len);
if (rc != CKR_OK) {
TRACE_DEVEL("%s Dilithium wrap get data failed\n", __func__);
goto done;
}
/* encrypt */
RETRY_START
rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l,
&mech_w, data, data_len,
cipher, &cipher_l, ep11_data->target);
RETRY_END(rc, tokdata, sess)
TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n",
__func__, rc, cipher_l);
goto done;
}
rc = check_key_attributes(tokdata, CKK_IBM_PQC_DILITHIUM,
CKO_PRIVATE_KEY,
p_attrs, attrs_len,
&new_p_attrs, &new_attrs_len, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s EC check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto done;
}
ep11_get_pin_blob(ep11_session, object_is_session_object(dilithium_key_obj),
&ep11_pin_blob, &ep11_pin_blob_len);
/* calls the card, it decrypts the private Dilithium key,
* reads its BER format and builds a blob.
*/
RETRY_START
rc = dll_m_UnwrapKey(cipher, cipher_l,
ep11_data->raw2key_wrap_blob,
ep11_data->raw2key_wrap_blob_l, NULL, ~0,
ep11_pin_blob,
ep11_pin_blob_len, &mech_w,
new_p_attrs, new_attrs_len, blob,
blob_size, csum, &cslen, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
} else {
TRACE_INFO("%s wrapping unwrap key rc=0x%lx blob_size=0x%zx\n",
__func__, rc, *blob_size);
}
cleanse_attribute(dilithium_key_obj->template, CKA_VALUE);
}
done:
if (pubkey)
free(pubkey);
if (data) {
OPENSSL_cleanse(data, data_len);
free(data);
}
if (p_attrs != NULL)
cleanse_and_free_attribute_array(p_attrs, attrs_len);
if (new_p_attrs)
cleanse_and_free_attribute_array(new_p_attrs, new_attrs_len);
return rc;
}
CK_RV token_specific_object_add(STDLL_TokData_t * tokdata, SESSION * sess,
OBJECT * obj)
{
CK_KEY_TYPE keytype;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE blob[MAX_BLOBSIZE];
size_t blobsize = sizeof(blob);
CK_RV rc;
/* get key type */
if (template_attribute_find(obj->template, CKA_KEY_TYPE, &attr) == FALSE) {
/* not a key, so nothing to do. Just return. */
return CKR_OK;
}
keytype = *(CK_KEY_TYPE *) attr->pValue;
memset(blob, 0, sizeof(blob));
/* only these keys can be imported */
switch (keytype) {
case CKK_RSA:
rc = import_RSA_key(tokdata, sess, obj, blob, &blobsize);
if (rc != CKR_OK) {
TRACE_ERROR("%s import RSA key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
return rc;
}
TRACE_INFO("%s import RSA key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
break;
case CKK_EC:
rc = import_EC_key(tokdata, sess, obj, blob, &blobsize);
if (rc != CKR_OK) {
TRACE_ERROR("%s import EC key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
return rc;
}
TRACE_INFO("%s import EC key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
break;
case CKK_DSA:
rc = import_DSA_key(tokdata, sess, obj, blob, &blobsize);
if (rc != CKR_OK) {
TRACE_ERROR("%s import DSA key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
return rc;
}
TRACE_INFO("%s import DSA key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
break;
case CKK_DH:
rc = import_DH_key(tokdata, sess, obj, blob, &blobsize);
if (rc != CKR_OK) {
TRACE_ERROR("%s import DH key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
return rc;
}
TRACE_INFO("%s import DH key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
break;
case CKK_IBM_PQC_DILITHIUM:
rc = import_IBM_Dilithium_key(tokdata, sess, obj, blob, &blobsize);
if (rc != CKR_OK) {
TRACE_ERROR("%s import IBM Dilithium key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
return rc;
}
TRACE_INFO("%s import IBM Dilithium key rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
break;
case CKK_DES2:
case CKK_DES3:
case CKK_AES:
case CKK_GENERIC_SECRET:
/* get key value */
if (template_attribute_find(obj->template, CKA_VALUE, &attr) == FALSE) {
TRACE_ERROR("%s token_specific_object_add incomplete template\n",
__func__);
return CKR_TEMPLATE_INCOMPLETE;
}
/* attr holds key value specified by user,
* import that key (make a blob)
*/
rc = rawkey_2_blob(tokdata, sess, attr->pValue, attr->ulValueLen,
keytype, blob, &blobsize, obj);
if (rc != CKR_OK) {
TRACE_ERROR("%s rawkey_2_blob rc=0x%lx "
"blobsize=0x%zx\n", __func__, rc, blobsize);
return rc;
}
/* clear value attribute */
OPENSSL_cleanse(attr->pValue, attr->ulValueLen);
TRACE_INFO("%s rawkey_2_blob rc=0x%lx blobsize=0x%zx\n",
__func__, rc, blobsize);
break;
default:
return CKR_KEY_FUNCTION_NOT_PERMITTED;
}
/* store the blob in the key obj */
rc = build_attribute(CKA_IBM_OPAQUE, blob, blobsize, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
return rc;
}
rc = template_update_attribute(obj->template, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
return rc;
}
return CKR_OK;
}
CK_RV ep11tok_generate_key(STDLL_TokData_t * tokdata, SESSION * session,
CK_MECHANISM_PTR mech, CK_ATTRIBUTE_PTR attrs,
CK_ULONG attrs_len, CK_OBJECT_HANDLE_PTR handle)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_BYTE blob[MAX_BLOBSIZE];
size_t blobsize = sizeof(blob);
CK_BYTE csum[MAX_CSUMSIZE];
size_t csum_len = sizeof(csum);
CK_ATTRIBUTE *attr = NULL;
OBJECT *key_obj = NULL;
CK_ULONG ktype;
CK_ULONG class;
CK_ATTRIBUTE_PTR new_attrs = NULL;
CK_ULONG new_attrs_len = 0;
CK_RV rc;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) session->private_data;
memset(blob, 0, sizeof(blob));
memset(csum, 0, sizeof(csum));
/* Get the keytype to use when creating the key object */
rc = ep11_get_keytype(attrs, attrs_len, mech, &ktype, &class);
if (rc != CKR_OK) {
TRACE_ERROR("%s get_subclass failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = check_key_attributes(tokdata, ktype, CKO_SECRET_KEY, attrs, attrs_len,
&new_attrs, &new_attrs_len, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s check secret key attributes failed: rc=0x%lx\n",
__func__, rc);
return rc;
}
ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len),
&ep11_pin_blob, &ep11_pin_blob_len);
RETRY_START
rc = dll_m_GenerateKey(mech, new_attrs, new_attrs_len, ep11_pin_blob,
ep11_pin_blob_len, blob, &blobsize,
csum, &csum_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n",
__func__, rc, ep11_get_ckm(mech->mechanism), attrs_len);
return rc;
}
TRACE_INFO("%s m_GenerateKey rc=0x%lx mech='%s' attrs_len=0x%lx\n",
__func__, rc, ep11_get_ckm(mech->mechanism), attrs_len);
/* Start creating the key object */
rc = object_mgr_create_skel(tokdata, session, new_attrs, new_attrs_len,
MODE_KEYGEN, CKO_SECRET_KEY, ktype, &key_obj);
if (rc != CKR_OK) {
TRACE_ERROR("%s object_mgr_create_skel failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = build_attribute(CKA_IBM_OPAQUE, blob, blobsize, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = template_update_attribute(key_obj->template, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
/* key should be fully constructed.
* Assign an object handle and store key
*/
rc = object_mgr_create_final(tokdata, session, key_obj, handle);
if (rc != CKR_OK) {
TRACE_ERROR("%s object_mgr_create_final with rc=0x%lx\n", __func__, rc);
goto error;
}
goto done;
error:
if (key_obj)
object_free(key_obj);
*handle = 0;
done:
if (new_attrs)
free_attribute_array(new_attrs, new_attrs_len);
return rc;
}
static CK_BBOOL ep11tok_libica_digest_available(ep11_private_data_t *ep11_data,
CK_MECHANISM_TYPE mech)
{
int use_libica;
switch (mech) {
case CKM_SHA_1:
use_libica = ep11_data->libica.ica_sha1 != NULL;
break;
case CKM_SHA224:
use_libica = ep11_data->libica.ica_sha224 != NULL;
break;
case CKM_SHA256:
use_libica = ep11_data->libica.ica_sha256 != NULL;
break;
case CKM_SHA384:
use_libica = ep11_data->libica.ica_sha384 != NULL;
break;
case CKM_SHA512:
use_libica = ep11_data->libica.ica_sha512 != NULL;
break;
case CKM_SHA512_224:
use_libica = ep11_data->libica.ica_sha512_224 != NULL;
break;
case CKM_SHA512_256:
use_libica = ep11_data->libica.ica_sha512_256 != NULL;
break;
#ifdef SHA3_224
case CKM_IBM_SHA3_224:
use_libica = ep11_data->libica.ica_sha3_224 != NULL;
break;
case CKM_IBM_SHA3_256:
use_libica = ep11_data->libica.ica_sha3_256 != NULL;
break;
case CKM_IBM_SHA3_384:
use_libica = ep11_data->libica.ica_sha3_384 != NULL;
break;
case CKM_IBM_SHA3_512:
use_libica = ep11_data->libica.ica_sha3_512 != NULL;
break;
#endif
default:
use_libica = 0;
}
if (use_libica == 0)
TRACE_DEVEL("%s mech=%s is not supported by libica\n", __func__,
ep11_get_ckm(mech));
return use_libica ? CK_TRUE : CK_FALSE;
}
static CK_RV ep11tok_digest_from_mech(CK_MECHANISM_TYPE mech,
CK_MECHANISM_TYPE *digest_mech)
{
switch (mech) {
case CKM_SHA_1:
case CKM_SHA1_RSA_PKCS:
case CKM_SHA1_RSA_PKCS_PSS:
case CKM_ECDSA_SHA1:
*digest_mech = CKM_SHA_1;
break;
case CKM_SHA224:
case CKM_SHA224_RSA_PKCS:
case CKM_SHA224_RSA_PKCS_PSS:
case CKM_ECDSA_SHA224:
*digest_mech = CKM_SHA224;
break;
case CKM_SHA256:
case CKM_SHA256_RSA_PKCS:
case CKM_SHA256_RSA_PKCS_PSS:
case CKM_ECDSA_SHA256:
*digest_mech = CKM_SHA256;
break;
case CKM_SHA384:
case CKM_SHA384_RSA_PKCS:
case CKM_SHA384_RSA_PKCS_PSS:
case CKM_ECDSA_SHA384:
*digest_mech = CKM_SHA384;
break;
case CKM_SHA512:
case CKM_SHA512_RSA_PKCS:
case CKM_SHA512_RSA_PKCS_PSS:
case CKM_ECDSA_SHA512:
*digest_mech = CKM_SHA512;
break;
case CKM_SHA512_224:
*digest_mech = CKM_SHA512_224;
break;
case CKM_SHA512_256:
*digest_mech = CKM_SHA512_256;
break;
case CKM_IBM_SHA3_224:
*digest_mech = CKM_IBM_SHA3_224;
break;
case CKM_IBM_SHA3_256:
*digest_mech = CKM_IBM_SHA3_256;
break;
case CKM_IBM_SHA3_384:
*digest_mech = CKM_IBM_SHA3_384;
break;
case CKM_IBM_SHA3_512:
*digest_mech = CKM_IBM_SHA3_512;
break;
default:
return CKR_MECHANISM_INVALID;
}
return CKR_OK;
}
static CK_BBOOL ep11tok_ec_curve_supported(STDLL_TokData_t *tokdata,
CK_OBJECT_HANDLE hKey)
{
CK_RV rc;
OBJECT *key_obj;
CK_ATTRIBUTE *attr = NULL;
int i;
rc = object_mgr_find_in_map1(tokdata, hKey, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s key 0x%lx not mapped\n", __func__, hKey);
return CK_FALSE;
}
if (!template_attribute_find(key_obj->template, CKA_ECDSA_PARAMS, &attr)) {
TRACE_ERROR("%s Could not find CKA_ECDSA_PARAMS for the key.\n",
__func__);
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return CK_FALSE;
}
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
for (i = 0; i < NUMEC; i++) {
if ((memcmp(attr->pValue, der_ec_supported[i].data,
attr->ulValueLen) == 0)) {
return CK_TRUE;
}
}
TRACE_DEVEL("%s EC curve not supported\n", __func__);
return CK_FALSE;
}
CK_BBOOL ep11tok_libica_mech_available(STDLL_TokData_t *tokdata,
CK_MECHANISM_TYPE mech,
CK_OBJECT_HANDLE hKey)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_MECHANISM_TYPE digest_mech;
CK_RV rc;
rc = ep11tok_digest_from_mech(mech, &digest_mech);
if (rc != CKR_OK)
return CK_FALSE;
switch (mech) {
case CKM_ECDSA_SHA1:
case CKM_ECDSA_SHA224:
case CKM_ECDSA_SHA256:
case CKM_ECDSA_SHA384:
case CKM_ECDSA_SHA512:
if (!ep11tok_ec_curve_supported(tokdata, hKey))
return CK_FALSE;
break;
}
return ep11tok_libica_digest_available(ep11_data, digest_mech);
}
static CK_RV ep11tok_libica_digest(ep11_private_data_t *ep11_data,
CK_MECHANISM_TYPE mech, libica_sha_context_t *ctx,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len,
unsigned int message_part)
{
CK_ULONG hsize;
CK_RV rc;
rc = get_sha_size(mech, &hsize);
if (rc != CKR_OK)
return rc;
if (*out_data_len < hsize)
return CKR_BUFFER_TOO_SMALL;
TRACE_DEVEL("%s mech=%s part=%u\n", __func__,
ep11_get_ckm(mech), message_part);
switch (mech) {
case CKM_SHA_1:
rc = ep11_data->libica.ica_sha1(message_part, in_data_len, in_data,
&ctx->ctx.sha1, out_data);
break;
case CKM_SHA224:
rc = ep11_data->libica.ica_sha224(message_part, in_data_len, in_data,
&ctx->ctx.sha256, out_data);
break;
case CKM_SHA256:
rc = ep11_data->libica.ica_sha256(message_part, in_data_len, in_data,
&ctx->ctx.sha256, out_data);
break;
case CKM_SHA384:
rc = ep11_data->libica.ica_sha384(message_part, in_data_len, in_data,
&ctx->ctx.sha512, out_data);
break;
case CKM_SHA512:
rc = ep11_data->libica.ica_sha512(message_part, in_data_len, in_data,
&ctx->ctx.sha512, out_data);
break;
case CKM_SHA512_224:
rc = ep11_data->libica.ica_sha512_224(message_part, in_data_len, in_data,
&ctx->ctx.sha512, out_data);
break;
case CKM_SHA512_256:
rc = ep11_data->libica.ica_sha512_256(message_part, in_data_len, in_data,
&ctx->ctx.sha512, out_data);
break;
#ifdef SHA3_224
case CKM_IBM_SHA3_224:
rc = ep11_data->libica.ica_sha3_224(message_part, in_data_len, in_data,
&ctx->ctx.sha3_224, out_data);
break;
case CKM_IBM_SHA3_256:
rc = ep11_data->libica.ica_sha3_256(message_part, in_data_len, in_data,
&ctx->ctx.sha3_256, out_data);
break;
case CKM_IBM_SHA3_384:
rc = ep11_data->libica.ica_sha3_384(message_part, in_data_len, in_data,
&ctx->ctx.sha3_384, out_data);
break;
case CKM_IBM_SHA3_512:
rc = ep11_data->libica.ica_sha3_512(message_part, in_data_len, in_data,
&ctx->ctx.sha3_512, out_data);
break;
#endif
default:
TRACE_ERROR("%s Invalid mechanism: mech=%s\n", __func__,
ep11_get_ckm(mech));
return CKR_MECHANISM_INVALID;
}
if (rc != CKR_OK) {
TRACE_ERROR("%s Libica SHA failed. mech=%s rc=0x%lx\n", __func__,
ep11_get_ckm(mech), rc);
switch (rc) {
case EINVAL:
return CKR_ARGUMENTS_BAD;
case ENODEV:
return CKR_DEVICE_ERROR;
default:
return CKR_FUNCTION_FAILED;
}
}
*out_data_len = hsize;
return CKR_OK;
}
CK_RV token_specific_sha_init(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c,
CK_MECHANISM * mech)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
size_t state_len = MAX(MAX_DIGEST_STATE_BYTES, sizeof(libica_sha_context_t));
CK_BYTE *state;
libica_sha_context_t *libica_ctx;
state = calloc(state_len, 1); /* freed by dig_mgr.c */
if (!state) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
if (ep11tok_libica_digest_available(ep11_data, mech->mechanism)) {
libica_ctx = (libica_sha_context_t *)state;
state_len = sizeof(libica_sha_context_t);
libica_ctx->first = CK_TRUE;
rc = get_sha_block_size(mech->mechanism, &libica_ctx->block_size);
} else {
rc = dll_m_DigestInit(state, &state_len, mech, ep11_data->target);
}
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
free(state);
} else {
/* DIGEST_CONTEXT will show up with following
* requests (sha_update), 'state' is build by the card
* and holds all to continue, even by another adapter
*/
c->mech.ulParameterLen = mech->ulParameterLen;
c->mech.mechanism = mech->mechanism;
c->mech.pParameter = NULL;
c->context = state;
c->context_len = state_len;
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV token_specific_sha(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c,
CK_BYTE * in_data,
CK_ULONG in_data_len, CK_BYTE * out_data,
CK_ULONG * out_data_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
if (ep11tok_libica_digest_available(ep11_data, c->mech.mechanism)) {
rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism,
(libica_sha_context_t *)c->context,
in_data, in_data_len,
out_data, out_data_len,
SHA_MSG_PART_ONLY);
} else {
rc = dll_m_Digest(c->context, c->context_len, in_data, in_data_len,
out_data, out_data_len, ep11_data->target);
}
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV token_specific_sha_update(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c,
CK_BYTE * in_data, CK_ULONG in_data_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
libica_sha_context_t *libica_ctx = (libica_sha_context_t *)c->context;
CK_BYTE temp_out[MAX_SHA_HASH_SIZE];
CK_ULONG out_len = sizeof(temp_out);
CK_ULONG len;
CK_RV rc = CKR_OK;
if (ep11tok_libica_digest_available(ep11_data, c->mech.mechanism)) {
if (libica_ctx->offset > 0 || in_data_len < libica_ctx->block_size) {
len = MIN(libica_ctx->block_size - libica_ctx->offset,
in_data_len);
memcpy(&libica_ctx->buffer[libica_ctx->offset], in_data, len);
libica_ctx->offset += len;
in_data += len;
in_data_len -= len;
if (libica_ctx->offset == libica_ctx->block_size) {
rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism,
libica_ctx, libica_ctx->buffer,
libica_ctx->offset, temp_out,
&out_len, libica_ctx->first ?
SHA_MSG_PART_FIRST :
SHA_MSG_PART_MIDDLE);
if (rc != CKR_OK)
goto out;
libica_ctx->first = CK_FALSE;
libica_ctx->offset = 0;
}
}
if (in_data_len > 0) {
len = (in_data_len / libica_ctx->block_size) * libica_ctx->block_size;
rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism,
libica_ctx, in_data, len, temp_out,
&out_len, libica_ctx->first ?
SHA_MSG_PART_FIRST :
SHA_MSG_PART_MIDDLE);
if (rc != CKR_OK)
goto out;
libica_ctx->first = CK_FALSE;
in_data += len;
in_data_len -= len;
if (in_data_len > 0) {
memcpy(libica_ctx->buffer, in_data, in_data_len);
libica_ctx->offset = in_data_len;
}
}
} else {
rc = dll_m_DigestUpdate(c->context, c->context_len,
in_data, in_data_len, ep11_data->target);
}
out:
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV token_specific_sha_final(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c,
CK_BYTE * out_data, CK_ULONG * out_data_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
libica_sha_context_t *libica_ctx = (libica_sha_context_t *)c->context;
CK_RV rc;
if (ep11tok_libica_digest_available(ep11_data, c->mech.mechanism)) {
rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism,
libica_ctx, libica_ctx->buffer,
libica_ctx->offset,
out_data, out_data_len,
libica_ctx->first ?
SHA_MSG_PART_ONLY :
SHA_MSG_PART_FINAL);
} else {
rc = dll_m_DigestFinal(c->context, c->context_len,
out_data, out_data_len, ep11_data->target);
}
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV token_specific_rsa_sign(STDLL_TokData_t *tokdata, SESSION *session,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len,
OBJECT *key_obj)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
size_t keyblobsize = 0;
CK_BYTE *keyblob;
CK_MECHANISM mech;
rc = obj_opaque_2_blob(tokdata, key_obj, &keyblob, &keyblobsize);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
mech.mechanism = CKM_RSA_PKCS;
mech.pParameter = NULL;
mech.ulParameterLen = 0;
RETRY_START
rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len,
out_data, out_data_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV token_specific_rsa_verify(STDLL_TokData_t *tokdata, SESSION *session,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG sig_len,
OBJECT *key_obj)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE *spki;
size_t spki_len = 0;
CK_MECHANISM mech;
rc = obj_opaque_2_blob(tokdata, key_obj, &spki, &spki_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
mech.mechanism = CKM_RSA_PKCS;
mech.pParameter = NULL;
mech.ulParameterLen = 0;
RETRY_START
rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len,
signature, sig_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV token_specific_rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *session,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *sig, CK_ULONG *sig_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
size_t keyblobsize = 0;
CK_BYTE *keyblob;
OBJECT *key_obj;
CK_MECHANISM mech;
rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj,
READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
mech.mechanism = CKM_RSA_PKCS_PSS;
mech.ulParameterLen = ctx->mech.ulParameterLen;
mech.pParameter = ctx->mech.pParameter;
RETRY_START
rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len,
sig, sig_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV token_specific_rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *session,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG sig_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE *spki;
size_t spki_len = 0;
OBJECT *key_obj;
CK_MECHANISM mech;
rc = h_opaque_2_blob(tokdata, ctx->key, &spki, &spki_len, &key_obj,
READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
mech.mechanism = CKM_RSA_PKCS_PSS;
mech.ulParameterLen = ctx->mech.ulParameterLen;
mech.pParameter = ctx->mech.pParameter;
RETRY_START
rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len,
signature, sig_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV token_specific_ec_sign(STDLL_TokData_t *tokdata, SESSION *session,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len,
OBJECT *key_obj )
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
size_t keyblobsize = 0;
CK_BYTE *keyblob;
CK_MECHANISM mech;
rc = obj_opaque_2_blob(tokdata, key_obj, &keyblob, &keyblobsize);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
mech.mechanism = CKM_ECDSA;
mech.pParameter = NULL;
mech.ulParameterLen = 0;
RETRY_START
rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len,
out_data, out_data_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV token_specific_ec_verify(STDLL_TokData_t *tokdata, SESSION *session,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG out_data_len,
OBJECT *key_obj )
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE *spki;
size_t spki_len = 0;
CK_MECHANISM mech;
rc = obj_opaque_2_blob(tokdata, key_obj, &spki, &spki_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
mech.mechanism = CKM_ECDSA;
mech.pParameter = NULL;
mech.ulParameterLen = 0;
RETRY_START
rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len,
out_data, out_data_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV token_specific_reencrypt_single(STDLL_TokData_t *tokdata,
SESSION *session,
ENCR_DECR_CONTEXT *decr_ctx,
CK_MECHANISM *decr_mech,
OBJECT *decr_key_obj,
ENCR_DECR_CONTEXT *encr_ctx,
CK_MECHANISM *encr_mech,
OBJECT *encr_key_obj,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE *decr_key, *encr_key;
size_t decr_key_len = 0, encr_key_len = 0;
int status;
UNUSED(decr_ctx);
UNUSED(encr_ctx);
if (dll_m_ReencryptSingle == NULL)
return CKR_FUNCTION_NOT_SUPPORTED;
status = check_required_versions(tokdata, reencrypt_single_req_versions,
NUM_REENCRYPT_SINGLE_REQ);
if (status != 1)
return CKR_FUNCTION_NOT_SUPPORTED;
rc = obj_opaque_2_blob(tokdata, decr_key_obj, &decr_key, &decr_key_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s no decr-blob rc=0x%lx\n", __func__, rc);
return rc;
}
rc = obj_opaque_2_blob(tokdata, encr_key_obj, &encr_key, &encr_key_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s no encrr-blob rc=0x%lx\n", __func__, rc);
return rc;
}
RETRY_START
rc = dll_m_ReencryptSingle(decr_key, decr_key_len, encr_key, encr_key_len,
decr_mech, encr_mech, in_data, in_data_len,
out_data, out_data_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session,
CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE hBaseKey,
CK_OBJECT_HANDLE_PTR handle, CK_ATTRIBUTE_PTR attrs,
CK_ULONG attrs_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE *keyblob;
size_t keyblobsize;
CK_BYTE newblob[MAX_BLOBSIZE];
size_t newblobsize = sizeof(newblob);
CK_BYTE csum[MAX_BLOBSIZE];
CK_ULONG cslen = sizeof(csum);
CK_ATTRIBUTE *opaque_attr = NULL;
OBJECT *base_key_obj = NULL;
OBJECT *key_obj = NULL;
CK_ULONG ktype;
CK_ULONG class;
CK_ATTRIBUTE_PTR new_attrs = NULL;
CK_ULONG new_attrs_len = 0;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) session->private_data;
CK_ECDH1_DERIVE_PARAMS *ecdh1_parms;
CK_ECDH1_DERIVE_PARAMS ecdh1_parms2;
CK_MECHANISM ecdh1_mech, ecdh1_mech2;
CK_BYTE *ecpoint;
CK_ULONG ecpoint_len, field_len;
memset(newblob, 0, sizeof(newblob));
if (mech->mechanism == CKM_ECDH1_DERIVE ||
mech->mechanism == CKM_IBM_EC_C25519 ||
mech->mechanism == CKM_IBM_EC_C448) {
if (mech->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) {
TRACE_ERROR("%s Param len for %s wrong: %lu\n",
__func__, ep11_get_ckm(mech->mechanism ),
mech->ulParameterLen);
return CKR_MECHANISM_PARAM_INVALID;
}
ecdh1_parms = mech->pParameter;
/* As per PKCS#11, a token MUST be able to accept this value encoded
* as a raw octet string (as per section A.5.2 of [ANSI X9.62]).
* A token MAY, in addition, support accepting this value as a
* DER-encoded ECPoint (as per section E.6 of [ANSI X9.62]) i.e.
* the same as a CKA_EC_POINT encoding.
* The EP11 host library only accepts the raw form, thus convert
* it to the raw format if the caller specified it in the DER-encoded
* form.
*/
if (ecdh1_parms->pPublicData != NULL &&
ecdh1_parms->ulPublicDataLen > 0) {
ecdh1_parms2 = *ecdh1_parms;
rc = ber_decode_OCTET_STRING(ecdh1_parms->pPublicData, &ecpoint,
&ecpoint_len, &field_len);
if (rc != CKR_OK || field_len != ecdh1_parms->ulPublicDataLen ||
ecpoint_len > ecdh1_parms->ulPublicDataLen - 2) {
/* no valid BER OCTET STRING encoding, assume raw octet string */
ecpoint = ecdh1_parms->pPublicData;
ecpoint_len = ecdh1_parms->ulPublicDataLen;
}
ecdh1_parms2.pPublicData = ecpoint;
ecdh1_parms2.ulPublicDataLen = ecpoint_len;
ecdh1_mech2.mechanism = mech->mechanism;
ecdh1_mech2.pParameter = &ecdh1_parms2;
ecdh1_mech2.ulParameterLen = sizeof(ecdh1_parms2);
mech = &ecdh1_mech2;
ecdh1_parms = mech->pParameter;
}
/*
* EP11 supports CKM_ECDH1_DERIVE (and CKM_IBM_EC_C*) slightly different
* than specified in PKCS#11 v2.11 or later. It expects the public data
* directly as mechanism param, not via CK_ECDH1_DERIVE_PARAMS. It also
* does not support KDFs and shared data.
*
* Newer EP11 crypto cards that support API version 3 support this
* mechanism in the PKCS#11 c2.11 way. If the used API version is > 2,
* then we can pass the mechanism parameters as-is, otherwise we still
* need to use the old way.
*/
if (ep11_data->used_firmware_API_version <= 2) {
if (ecdh1_parms->kdf != CKD_NULL) {
TRACE_ERROR("%s KDF for CKM_ECDH1_DERIVE not supported: %lu\n",
__func__, ecdh1_parms->kdf);
return CKR_MECHANISM_PARAM_INVALID;
}
if (ecdh1_parms->pSharedData != NULL ||
ecdh1_parms->ulSharedDataLen > 0) {
TRACE_ERROR("%s Shared data for CKM_ECDH1_DERIVE not "
"supported\n", __func__);
return CKR_MECHANISM_PARAM_INVALID;
}
ecdh1_mech.mechanism = mech->mechanism;
ecdh1_mech.pParameter = ecdh1_parms->pPublicData;
ecdh1_mech.ulParameterLen = ecdh1_parms->ulPublicDataLen;
mech = &ecdh1_mech;
}
}
rc = h_opaque_2_blob(tokdata, hBaseKey, &keyblob, &keyblobsize,
&base_key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s failedL hBaseKey=0x%lx\n", __func__, hBaseKey);
return rc;
}
/* Get the keytype to use when creating the key object */
rc = ep11_get_keytype(attrs, attrs_len, mech, &ktype, &class);
if (rc != CKR_OK) {
TRACE_ERROR("%s get_subclass failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = check_key_attributes(tokdata, ktype, class, attrs, attrs_len,
&new_attrs, &new_attrs_len, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s Check key attributes for derived key failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len),
&ep11_pin_blob, &ep11_pin_blob_len);
RETRY_START
rc =
dll_m_DeriveKey(mech, new_attrs, new_attrs_len, keyblob, keyblobsize,
NULL, 0, ep11_pin_blob, ep11_pin_blob_len, newblob,
&newblobsize, csum, &cslen, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
TRACE_ERROR("%s hBaseKey=0x%lx rc=0x%lx handle=0x%lx blobsize=0x%zx\n",
__func__, hBaseKey, rc, *handle, newblobsize);
goto error;
}
TRACE_INFO("%s hBaseKey=0x%lx rc=0x%lx handle=0x%lx blobsize=0x%zx\n",
__func__, hBaseKey, rc, *handle, newblobsize);
/* Start creating the key object */
rc = object_mgr_create_skel(tokdata, session, new_attrs, new_attrs_len,
MODE_DERIVE, class, ktype, &key_obj);
if (rc != CKR_OK) {
TRACE_ERROR("%s object_mgr_create_skel failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = build_attribute(CKA_IBM_OPAQUE, newblob, newblobsize, &opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = template_update_attribute(key_obj->template, opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
/* key should be fully constructed.
* Assign an object handle and store key
*/
rc = object_mgr_create_final(tokdata, session, key_obj, handle);
if (rc != CKR_OK) {
TRACE_ERROR("%s object_mgr_create_final with rc=0x%lx\n", __func__, rc);
goto error;
}
object_put(tokdata, base_key_obj, TRUE);
base_key_obj = NULL;
return rc;
error:
if (key_obj)
object_free(key_obj);
*handle = 0;
if (new_attrs)
free_attribute_array(new_attrs, new_attrs_len);
object_put(tokdata, base_key_obj, TRUE);
base_key_obj = NULL;
return rc;
}
static CK_RV dh_generate_keypair(STDLL_TokData_t * tokdata,
SESSION * sess,
CK_MECHANISM_PTR pMechanism,
TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl,
CK_ATTRIBUTE_PTR pPublicKeyTemplate,
CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
CK_ULONG ulPrivateKeyAttributeCount,
CK_SESSION_HANDLE h)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE publblob[MAX_BLOBSIZE];
size_t publblobsize = sizeof(publblob);
CK_BYTE privblob[MAX_BLOBSIZE];
size_t privblobsize = sizeof(privblob);
CK_ATTRIBUTE *prime_attr = NULL;
CK_ATTRIBUTE *base_attr = NULL;
CK_ATTRIBUTE *opaque_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *attr = NULL;
CK_ATTRIBUTE *pPublicKeyTemplate_new = NULL;
CK_ATTRIBUTE_PTR dh_pPublicKeyTemplate = NULL;
CK_ULONG dh_ulPublicKeyAttributeCount = 0;
CK_ATTRIBUTE_PTR dh_pPrivateKeyTemplate = NULL;
CK_ULONG dh_ulPrivateKeyAttributeCount = 0;
size_t p_len = 0, g_len = 0;
int new_public_attr;
CK_ULONG i;
CK_ULONG data_len;
CK_ULONG field_len;
CK_BYTE *data;
CK_BYTE *y_start, *oid, *parm;
CK_ULONG bit_str_len, oid_len, parm_len;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
/* ep11 accepts CKA_PRIME and CKA_BASE parameters/attributes
* only in this format
*/
struct {
size_t pg_bytes; /* total size: 2*bytecount(P) */
unsigned char *pg;
} dh_pgs;
UNUSED(h);
memset(&dh_pgs, 0, sizeof(dh_pgs));
memset(publblob, 0, sizeof(publblob));
memset(privblob, 0, sizeof(privblob));
/* card does not want CKA_PRIME/CKA_BASE in template but in dh_pgs */
pPublicKeyTemplate_new =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) *
ulPublicKeyAttributeCount);
if (!pPublicKeyTemplate_new) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
memset(pPublicKeyTemplate_new, 0,
sizeof(CK_ATTRIBUTE) * ulPublicKeyAttributeCount);
for (i = 0, new_public_attr = 0; i < ulPublicKeyAttributeCount; i++) {
/* filter out CKA_PRIME/CKA_BASE,
* but remember where they can be found
*/
switch (pPublicKeyTemplate[i].type) {
case CKA_PRIME:
prime_attr = &(pPublicKeyTemplate[i]);
p_len = pPublicKeyTemplate[i].ulValueLen;
break;
case CKA_BASE:
base_attr = &(pPublicKeyTemplate[i]);
g_len = pPublicKeyTemplate[i].ulValueLen;
break;
default:
/* copy all other attributes */
memcpy(&pPublicKeyTemplate_new[new_public_attr],
&(pPublicKeyTemplate[i]), sizeof(CK_ATTRIBUTE));
new_public_attr++;
}
}
if (prime_attr == NULL || base_attr == NULL) {
TRACE_ERROR("%s Incomplete template prime_attr=%p base_attr=%p\n",
__func__, (void *)prime_attr, (void *)base_attr);
rc = CKR_TEMPLATE_INCOMPLETE;
goto dh_generate_keypair_end;
}
/* copy CKA_PRIME/CKA_BASE to private template */
rc = build_attribute(CKA_PRIME, prime_attr->pValue,
prime_attr->ulValueLen, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
rc = template_update_attribute(priv_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto dh_generate_keypair_end;
}
rc = build_attribute(CKA_BASE, base_attr->pValue,
base_attr->ulValueLen, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
rc = template_update_attribute(priv_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto dh_generate_keypair_end;
}
/* copy CKA_PRIME/CKA_BASE values */
dh_pgs.pg = malloc(p_len * 2);
if (!dh_pgs.pg) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
rc = CKR_HOST_MEMORY;
goto dh_generate_keypair_end;
}
memset(dh_pgs.pg, 0, p_len * 2);
memcpy(dh_pgs.pg, prime_attr->pValue, p_len); /* copy CKA_PRIME value */
/* copy CKA_BASE value, it must have leading zeros
* if it is shorter than CKA_PRIME
*/
memcpy(dh_pgs.pg + p_len + (p_len - g_len), base_attr->pValue, g_len);
dh_pgs.pg_bytes = p_len * 2;
#ifdef DEBUG
TRACE_DEBUG("%s P:\n", __func__);
TRACE_DEBUG_DUMP(&dh_pgs.pg[0], p_len);
TRACE_DEBUG("%s G:\n", __func__);
TRACE_DEBUG_DUMP(&dh_pgs.pg[p_len], p_len);
#endif
/* add special attribute, do not add it to ock's pPublicKeyTemplate */
CK_ATTRIBUTE pgs[] = { {CKA_IBM_STRUCT_PARAMS, (CK_VOID_PTR) dh_pgs.pg,
dh_pgs.pg_bytes}
};
memcpy(&(pPublicKeyTemplate_new[new_public_attr]),
&(pgs[0]), sizeof(CK_ATTRIBUTE));
rc = check_key_attributes(tokdata, CKK_DH, CKO_PUBLIC_KEY,
pPublicKeyTemplate_new, new_public_attr + 1,
&dh_pPublicKeyTemplate,
&dh_ulPublicKeyAttributeCount, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s DH check public key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
rc = check_key_attributes(tokdata, CKK_DH, CKO_PRIVATE_KEY,
pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
&dh_pPrivateKeyTemplate,
&dh_ulPrivateKeyAttributeCount, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s DH check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
rc = override_key_attributes(tokdata, CKK_DH, CKO_PUBLIC_KEY,
dh_pPublicKeyTemplate,
dh_ulPublicKeyAttributeCount);
if (rc != CKR_OK) {
TRACE_ERROR("%s DH override public key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
rc = override_key_attributes(tokdata, CKK_DH, CKO_PRIVATE_KEY,
dh_pPrivateKeyTemplate,
dh_ulPrivateKeyAttributeCount);
if (rc != CKR_OK) {
TRACE_ERROR("%s DH override private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
ep11_get_pin_blob(ep11_session,
(ep11_is_session_object
(pPublicKeyTemplate, ulPublicKeyAttributeCount)
|| ep11_is_session_object(pPrivateKeyTemplate,
ulPrivateKeyAttributeCount)),
&ep11_pin_blob, &ep11_pin_blob_len);
RETRY_START
rc = dll_m_GenerateKeyPair(pMechanism, dh_pPublicKeyTemplate,
dh_ulPublicKeyAttributeCount,
dh_pPrivateKeyTemplate,
dh_ulPrivateKeyAttributeCount, ep11_pin_blob,
ep11_pin_blob_len, privblob, &privblobsize,
publblob, &publblobsize, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s m_GenerateKeyPair failed rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
TRACE_INFO("%s rc=0x%lx plen=%zd publblobsize=0x%zx privblobsize=0x%zx\n",
__func__, rc, p_len, publblobsize, privblobsize);
/* store the blobs */
rc = build_attribute(CKA_IBM_OPAQUE, publblob, publblobsize, &opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
rc = template_update_attribute(publ_tmpl, opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto dh_generate_keypair_end;
}
rc = build_attribute(CKA_IBM_OPAQUE, privblob, privblobsize, &opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
rc = template_update_attribute(priv_tmpl, opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto dh_generate_keypair_end;
}
#ifdef DEBUG
TRACE_DEBUG("%s DH SPKI\n", __func__);
TRACE_DEBUG_DUMP(publblob, publblobsize);
#endif
/* CKA_VALUE of the public key must hold 'y' */
rc = ber_decode_SPKI(publblob, &oid, &oid_len, &parm, &parm_len,
&y_start, &bit_str_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s ber_decode SKPI failed rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
/* DHPublicKey ::= INTEGER -- public key, y = g^x mod p */
rc = ber_decode_INTEGER(y_start, &data, &data_len, &field_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s ber_decode_INTEGER failed rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
TRACE_INFO("%s DH SPKI decode INTEGER rc=0x%lx y_start=0x%x"
" field_len=%lu data_len=%lu data=0x%hhx\n",
__func__, rc, y_start[1], field_len, data_len, data[0]);
/* remove leading zero, a leading zero is needed
* (according to standard) if left most bit of first byte is 1,
* in order to indicate a positive number.
* ock, like many others, interpret 'y' always as positive number,
* a leading zero is not expected by ock.
*/
if (data[0] == 0) {
data_len = data_len - 1;
data = data + 1;
TRACE_INFO("%s DH SPKI removed leading zero rc=0x%lx"
" y_start=0x%x field_len=%lu data_len=%lu data=0x%hhx\n",
__func__, rc, y_start[1], field_len, data_len, data[0]);
}
rc = build_attribute(CKA_VALUE, data, data_len, &value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dh_generate_keypair_end;
}
rc = template_update_attribute(publ_tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
}
dh_generate_keypair_end:
free(pPublicKeyTemplate_new);
if (dh_pgs.pg != NULL)
free(dh_pgs.pg);
if (dh_pPublicKeyTemplate)
free_attribute_array(dh_pPublicKeyTemplate,
dh_ulPublicKeyAttributeCount);
if (dh_pPrivateKeyTemplate)
free_attribute_array(dh_pPrivateKeyTemplate,
dh_ulPrivateKeyAttributeCount);
return rc;
}
static CK_RV dsa_generate_keypair(STDLL_TokData_t * tokdata,
SESSION * sess,
CK_MECHANISM_PTR pMechanism,
TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl,
CK_ATTRIBUTE_PTR pPublicKeyTemplate,
CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
CK_ULONG ulPrivateKeyAttributeCount,
CK_SESSION_HANDLE h)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE publblob[MAX_BLOBSIZE];
size_t publblobsize = sizeof(publblob);
CK_BYTE privblob[MAX_BLOBSIZE];
size_t privblobsize = sizeof(privblob);
CK_ATTRIBUTE *prime_attr = NULL;
CK_ATTRIBUTE *sub_prime_attr = NULL;
CK_ATTRIBUTE *base_attr = NULL;
CK_ATTRIBUTE *opaque_attr = NULL;
CK_ATTRIBUTE *value_attr = NULL;
CK_ATTRIBUTE *attr = NULL;
size_t p_len = 0, q_len = 0, g_len = 0;
int new_public_attr;
CK_ULONG i;
CK_ATTRIBUTE *pPublicKeyTemplate_new = NULL;
CK_BYTE *key;
CK_BYTE *data, *oid, *parm;
CK_ULONG data_len, field_len, bit_str_len, oid_len, parm_len;
CK_ATTRIBUTE_PTR dsa_pPublicKeyTemplate = NULL;
CK_ULONG dsa_ulPublicKeyAttributeCount = 0;
CK_ATTRIBUTE_PTR dsa_pPrivateKeyTemplate = NULL;
CK_ULONG dsa_ulPrivateKeyAttributeCount = 0;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
/* ep11 accepts CKA_PRIME,CKA_SUBPRIME,CKA_BASE only in this format */
struct {
size_t pqg_bytes; /* total size: 3*bytecount(P) */
unsigned char *pqg;
} dsa_pqgs;
UNUSED(h);
memset(&dsa_pqgs, 0, sizeof(dsa_pqgs));
memset(publblob, 0, sizeof(publblob));
memset(privblob, 0, sizeof(privblob));
/* card does not want CKA_PRIME/CKA_BASE/CKA_SUBPRIME
* in template but in dsa_pqgs
*/
pPublicKeyTemplate_new =
(CK_ATTRIBUTE *) malloc(sizeof(CK_ATTRIBUTE) *
ulPublicKeyAttributeCount);
if (!pPublicKeyTemplate_new) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
memset(pPublicKeyTemplate_new, 0,
sizeof(CK_ATTRIBUTE) * ulPublicKeyAttributeCount);
for (i = 0, new_public_attr = 0; i < ulPublicKeyAttributeCount; i++) {
switch (pPublicKeyTemplate[i].type) {
case CKA_PRIME:
prime_attr = &(pPublicKeyTemplate[i]);
p_len = pPublicKeyTemplate[i].ulValueLen;
break;
case CKA_SUBPRIME:
sub_prime_attr = &(pPublicKeyTemplate[i]);
q_len = pPublicKeyTemplate[i].ulValueLen;
break;
case CKA_BASE:
base_attr = &(pPublicKeyTemplate[i]);
g_len = pPublicKeyTemplate[i].ulValueLen;
break;
default:
/* copy all other attributes */
memcpy(&pPublicKeyTemplate_new[new_public_attr],
&(pPublicKeyTemplate[i]), sizeof(CK_ATTRIBUTE));
new_public_attr++;
}
}
if (prime_attr == NULL || sub_prime_attr == NULL || base_attr == NULL) {
rc = CKR_TEMPLATE_INCOMPLETE;
goto dsa_generate_keypair_end;
}
/* copy CKA_PRIME/CKA_BASE/CKA_SUBPRIME to private template */
rc = build_attribute(CKA_PRIME, prime_attr->pValue,
prime_attr->ulValueLen, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
rc = template_update_attribute(priv_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto dsa_generate_keypair_end;
}
rc = build_attribute(CKA_BASE, base_attr->pValue,
base_attr->ulValueLen, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
rc = template_update_attribute(priv_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto dsa_generate_keypair_end;
}
rc = build_attribute(CKA_PRIME, sub_prime_attr->pValue,
sub_prime_attr->ulValueLen, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
rc = template_update_attribute(priv_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto dsa_generate_keypair_end;
}
/* if CKA_SUBPRIME,CKA_BASE are smaller than CKA_PRIME
* then they are extented by leading zeros till they have
* the size of CKA_PRIME
*/
dsa_pqgs.pqg = malloc(p_len * 3);
if (!dsa_pqgs.pqg) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
rc = CKR_HOST_MEMORY;
goto dsa_generate_keypair_end;
}
memset(dsa_pqgs.pqg, 0, p_len * 3);
memcpy(dsa_pqgs.pqg, prime_attr->pValue, p_len);
memcpy(dsa_pqgs.pqg + p_len + (p_len - q_len),
sub_prime_attr->pValue, q_len);
memcpy(dsa_pqgs.pqg + 2 * p_len + (p_len - g_len),
base_attr->pValue, g_len);
dsa_pqgs.pqg_bytes = p_len * 3;
#ifdef DEBUG
TRACE_DEBUG("%s P:\n", __func__);
TRACE_DEBUG_DUMP(&dsa_pqgs.pqg[0], p_len);
TRACE_DEBUG("%s Q:\n", __func__);
TRACE_DEBUG_DUMP(&dsa_pqgs.pqg[p_len], p_len);
TRACE_DEBUG("%s G:\n", __func__);
TRACE_DEBUG_DUMP(&dsa_pqgs.pqg[2 * p_len], p_len);
#endif
CK_ATTRIBUTE pqgs[] = { {CKA_IBM_STRUCT_PARAMS,
(CK_VOID_PTR) dsa_pqgs.pqg, dsa_pqgs.pqg_bytes}
};
/* add special attribute, do not add it to ock's pPublicKeyTemplate */
memcpy(&(pPublicKeyTemplate_new[new_public_attr]),
&(pqgs[0]), sizeof(CK_ATTRIBUTE));
rc = check_key_attributes(tokdata, CKK_DSA, CKO_PUBLIC_KEY,
pPublicKeyTemplate_new, new_public_attr + 1,
&dsa_pPublicKeyTemplate,
&dsa_ulPublicKeyAttributeCount, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC check public key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
rc = check_key_attributes(tokdata, CKK_DSA, CKO_PRIVATE_KEY,
pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
&dsa_pPrivateKeyTemplate,
&dsa_ulPrivateKeyAttributeCount, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
rc = override_key_attributes(tokdata, CKK_DSA, CKO_PUBLIC_KEY,
dsa_pPublicKeyTemplate,
dsa_ulPublicKeyAttributeCount);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC override public key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
rc = override_key_attributes(tokdata, CKK_DSA, CKO_PRIVATE_KEY,
dsa_pPrivateKeyTemplate,
dsa_ulPrivateKeyAttributeCount);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC override private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
ep11_get_pin_blob(ep11_session,
(ep11_is_session_object
(pPublicKeyTemplate, ulPublicKeyAttributeCount)
|| ep11_is_session_object(pPrivateKeyTemplate,
ulPrivateKeyAttributeCount)),
&ep11_pin_blob, &ep11_pin_blob_len);
RETRY_START
rc = dll_m_GenerateKeyPair(pMechanism, dsa_pPublicKeyTemplate,
dsa_ulPublicKeyAttributeCount,
dsa_pPrivateKeyTemplate,
dsa_ulPrivateKeyAttributeCount,
ep11_pin_blob, ep11_pin_blob_len, privblob,
&privblobsize, publblob, &publblobsize,
ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s m_GenerateKeyPair failed with rc=0x%lx\n", __func__,
rc);
goto dsa_generate_keypair_end;
}
TRACE_INFO("%s rc=0x%lx p_len=%zd publblobsize=0x%zx privblobsize=0x%zx "
"npattr=0x%x\n",
__func__, rc, p_len, publblobsize, privblobsize,
new_public_attr + 1);
rc = build_attribute(CKA_IBM_OPAQUE, publblob, publblobsize, &opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
rc = template_update_attribute(publ_tmpl, opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto dsa_generate_keypair_end;
}
rc = build_attribute(CKA_IBM_OPAQUE, privblob, privblobsize, &opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
rc = template_update_attribute(priv_tmpl, opaque_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto dsa_generate_keypair_end;
}
/* set CKA_VALUE of the public key, first get key from SPKI */
rc = ber_decode_SPKI(publblob, &oid, &oid_len, &parm, &parm_len,
&key, &bit_str_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s reading DSA SPKI failed with rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
/* key must be an integer */
rc = ber_decode_INTEGER(key, &data, &data_len, &field_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s reading DSA public key failed with rc=0x%lx\n",
__func__, rc);
goto dsa_generate_keypair_end;
}
#ifdef DEBUG
TRACE_DEBUG("%s dsa_generate_keypair public key:\n", __func__);
TRACE_DEBUG_DUMP(data, data_len);
#endif
rc = build_attribute(CKA_VALUE, data, data_len, &value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto dsa_generate_keypair_end;
}
rc = template_update_attribute(publ_tmpl, value_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
}
dsa_generate_keypair_end:
free(pPublicKeyTemplate_new);
if (dsa_pqgs.pqg != NULL)
free(dsa_pqgs.pqg);
if (dsa_pPublicKeyTemplate)
free_attribute_array(dsa_pPublicKeyTemplate,
dsa_ulPublicKeyAttributeCount);
if (dsa_pPrivateKeyTemplate)
free_attribute_array(dsa_pPrivateKeyTemplate,
dsa_ulPrivateKeyAttributeCount);
return rc;
}
static CK_RV rsa_ec_generate_keypair(STDLL_TokData_t * tokdata,
SESSION * sess,
CK_MECHANISM_PTR pMechanism,
TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl,
CK_ATTRIBUTE_PTR pPublicKeyTemplate,
CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
CK_ULONG ulPrivateKeyAttributeCount,
CK_SESSION_HANDLE h)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
CK_ATTRIBUTE *n_attr = NULL;
CK_BYTE privkey_blob[MAX_BLOBSIZE];
size_t privkey_blob_len = sizeof(privkey_blob);
unsigned char spki[MAX_BLOBSIZE];
size_t spki_len = sizeof(spki);
CK_ULONG i;
CK_ULONG bit_str_len;
CK_BYTE *key;
CK_BYTE *data, *oid, *parm;
CK_ULONG data_len, oid_len, parm_len;
CK_ULONG field_len;
CK_ATTRIBUTE_PTR new_pPublicKeyTemplate = NULL;
CK_ULONG new_ulPublicKeyAttributeCount = 0;
CK_ATTRIBUTE_PTR new_pPrivateKeyTemplate = NULL;
CK_ULONG new_ulPrivateKeyAttributeCount = 0;
CK_ULONG ktype;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
int curve_type = -1;
UNUSED(h);
if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN) {
ktype = CKK_EC;
} else if ((pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN) ||
(pMechanism->mechanism == CKM_RSA_X9_31_KEY_PAIR_GEN)) {
ktype = CKK_RSA;
} else {
TRACE_ERROR("%s Neither RSA nor EC mech type provided for "
"RSA/EC_key_pair_gen\n", __func__);
return CKR_MECHANISM_INVALID;
}
if (ktype == CKK_EC) {
attr = get_attribute_by_type(pPublicKeyTemplate,
ulPublicKeyAttributeCount,
CKA_ECDSA_PARAMS);
if (attr != NULL) {
for (i = 0; i < NUMEC; i++) {
if (der_ec_supported[i].data_size == attr->ulValueLen &&
memcmp(attr->pValue, der_ec_supported[i].data,
attr->ulValueLen) == 0) {
curve_type = der_ec_supported[i].curve_type;
break;
}
}
}
}
rc = check_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY,
pPublicKeyTemplate, ulPublicKeyAttributeCount,
&new_pPublicKeyTemplate,
&new_ulPublicKeyAttributeCount,
curve_type);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC check public key attributes failed with "
"rc=0x%lx\n", __func__, rc);
return rc;
}
rc = check_key_attributes(tokdata, ktype, CKO_PRIVATE_KEY,
pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
&new_pPrivateKeyTemplate,
&new_ulPrivateKeyAttributeCount,
curve_type);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
rc = override_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY,
new_pPublicKeyTemplate,
new_ulPublicKeyAttributeCount);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC override public key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
rc = override_key_attributes(tokdata, ktype, CKO_PRIVATE_KEY,
new_pPrivateKeyTemplate,
new_ulPrivateKeyAttributeCount);
if (rc != CKR_OK) {
TRACE_ERROR("%s RSA/EC override private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
/* debug */
for (i = 0; i < new_ulPrivateKeyAttributeCount; i++) {
TRACE_INFO("%s gen priv attr type=0x%lx valuelen=0x%lx attrcnt=0x%lx\n",
__func__, new_pPrivateKeyTemplate[i].type,
new_pPrivateKeyTemplate[i].ulValueLen,
new_ulPrivateKeyAttributeCount);
}
ep11_get_pin_blob(ep11_session,
(ep11_is_session_object
(pPublicKeyTemplate, ulPublicKeyAttributeCount)
|| ep11_is_session_object(pPrivateKeyTemplate,
ulPrivateKeyAttributeCount)),
&ep11_pin_blob, &ep11_pin_blob_len);
RETRY_START
rc = dll_m_GenerateKeyPair(pMechanism, new_pPublicKeyTemplate,
new_ulPublicKeyAttributeCount,
new_pPrivateKeyTemplate,
new_ulPrivateKeyAttributeCount,
ep11_pin_blob, ep11_pin_blob_len,
privkey_blob, &privkey_blob_len, spki,
&spki_len, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx "
"privkey_blob_len=0x%zx mech='%s'\n",
__func__, rc, spki_len, privkey_blob_len,
ep11_get_ckm(pMechanism->mechanism));
goto error;
}
TRACE_INFO("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx "
"privkey_blob_len=0x%zx mech='%s'\n",
__func__, rc, spki_len, privkey_blob_len,
ep11_get_ckm(pMechanism->mechanism));
if (spki_len > MAX_BLOBSIZE || privkey_blob_len > MAX_BLOBSIZE) {
TRACE_ERROR("%s blobsize error\n", __func__);
rc = CKR_KEY_INDIGESTIBLE;
goto error;
}
rc = build_attribute(CKA_IBM_OPAQUE, spki, spki_len, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = template_update_attribute(publ_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = build_attribute(CKA_IBM_OPAQUE, privkey_blob, privkey_blob_len, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = template_update_attribute(priv_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN) {
/* scan the SPKI for CKA_EC_POINT */
#ifdef DEBUG
TRACE_DEBUG("%s ec_generate_keypair spki:\n", __func__);
TRACE_DEBUG_DUMP(spki, spki_len);
#endif
rc = ber_decode_SPKI(spki, &oid, &oid_len, &parm, &parm_len,
&key, &bit_str_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s read key from SPKI failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
/* 'key' is already EC point,
* SEC 1: Elliptic Curve Cryptography:
* The elliptic curve public key (a value of type ECPoint
* that is an OCTET STRING) is mapped to a subjectPublicKey
* (a value encoded as type BIT STRING) as follows: The most
* significant bit of the value of the OCTET STRING becomes
* the most significant bit of the value of the BIT STRING
* and so on with consecutive bits until the least significant
* bit of the OCTET STRING becomes the least significant bit
* of the BIT STRING.
*/
TRACE_INFO("%s ecpoint length 0x%lx\n", __func__, bit_str_len);
data_len = bit_str_len;
data = key;
#ifdef DEBUG
TRACE_DEBUG("%s ec_generate_keypair ecpoint:\n", __func__);
TRACE_DEBUG_DUMP(data, data_len);
#endif
/* build and add CKA_EC_POINT as BER encoded OCTET STRING */
rc = ber_encode_OCTET_STRING(FALSE, &data, &data_len,
key, bit_str_len);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_OCTET_STRING failed\n");
goto error;
}
rc = build_attribute(CKA_EC_POINT, data, data_len, &attr);
free(data);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = template_update_attribute(publ_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
/* copy CKA_EC_PARAMS/CKA_ECDSA_PARAMS to private template */
if (template_attribute_find(publ_tmpl, CKA_EC_PARAMS, &attr)) {
rc = build_attribute(attr->type, attr->pValue,
attr->ulValueLen, &n_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = template_update_attribute(priv_tmpl, n_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
}
if (template_attribute_find(publ_tmpl, CKA_ECDSA_PARAMS, &attr)) {
rc = build_attribute(attr->type, attr->pValue,
attr->ulValueLen, &n_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = template_update_attribute(priv_tmpl, n_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
}
} else {
/* scan the SPKI for modulus and public exponent and
* set the public key attributes, a user would use the
* already built SPKI (in CKA_IBM_OPAQUE of the public key).
*/
CK_BYTE *modulus, *publ_exp;
rc = ber_decode_SPKI(spki, &oid, &oid_len, &parm, &parm_len,
&key, &bit_str_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s read key from SPKI failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
/* key must be a sequence holding two integers,
* modulus and public exponent
*/
rc = ber_decode_SEQUENCE(key, &data, &data_len, &field_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s read sequence failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
modulus = key + field_len - data_len;
rc = ber_decode_INTEGER(modulus, &data, &data_len, &field_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s read modulus failed with rc=0x%lx\n", __func__, rc);
goto error;
}
#ifdef DEBUG
TRACE_DEBUG("%s rsa_generate_keypair modulus:\n", __func__);
TRACE_DEBUG_DUMP(data, data_len);
#endif
/* build and add CKA_MODULUS */
rc = build_attribute(CKA_MODULUS, data, data_len, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = template_update_attribute(publ_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
/* read public exponent */
publ_exp = modulus + field_len;
rc = ber_decode_INTEGER(publ_exp, &data, &data_len, &field_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s read public exponent failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
#ifdef DEBUG
TRACE_DEBUG("%s rsa_generate_keypair public exponent:\n", __func__);
TRACE_DEBUG_DUMP(data, data_len);
#endif
/* build and add CKA_PUBLIC_EXPONENT */
rc = build_attribute(CKA_PUBLIC_EXPONENT, data, data_len, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = template_update_attribute(publ_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
}
error:
if (new_pPrivateKeyTemplate)
free_attribute_array(new_pPrivateKeyTemplate,
new_ulPrivateKeyAttributeCount);
if (new_pPublicKeyTemplate)
free_attribute_array(new_pPublicKeyTemplate,
new_ulPublicKeyAttributeCount);
return rc;
}
static CK_RV ibm_dilithium_generate_keypair(STDLL_TokData_t * tokdata,
SESSION * sess,
CK_MECHANISM_PTR pMechanism,
TEMPLATE * publ_tmpl, TEMPLATE * priv_tmpl,
CK_ATTRIBUTE_PTR pPublicKeyTemplate,
CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
CK_ULONG ulPrivateKeyAttributeCount,
CK_SESSION_HANDLE h)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_ATTRIBUTE *attr = NULL;
CK_BYTE privkey_blob[MAX_BLOBSIZE];
size_t privkey_blob_len = sizeof(privkey_blob);
unsigned char spki[MAX_BLOBSIZE];
size_t spki_len = sizeof(spki);
CK_ULONG i;
CK_ULONG bit_str_len;
CK_BYTE *key;
CK_BYTE *data, *oid, *parm;
CK_ULONG data_len, oid_len, parm_len;
CK_ULONG field_len;
CK_ATTRIBUTE_PTR new_pPublicKeyTemplate = NULL;
CK_ULONG new_ulPublicKeyAttributeCount = 0;
CK_ATTRIBUTE_PTR new_pPrivateKeyTemplate = NULL;
CK_ULONG new_ulPrivateKeyAttributeCount = 0;
CK_ULONG ktype = CKK_IBM_PQC_DILITHIUM;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data;
CK_BYTE *rho, *t1;
UNUSED(h);
if (pMechanism->mechanism != CKM_IBM_DILITHIUM) {
TRACE_ERROR("Invalid mechanism provided for %s\n ", __func__);
return CKR_MECHANISM_INVALID;
}
rc = check_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY,
pPublicKeyTemplate, ulPublicKeyAttributeCount,
&new_pPublicKeyTemplate,
&new_ulPublicKeyAttributeCount, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s Dilithium check public key attributes failed with "
"rc=0x%lx\n", __func__, rc);
return rc;
}
rc = check_key_attributes(tokdata, ktype, CKO_PRIVATE_KEY,
pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
&new_pPrivateKeyTemplate,
&new_ulPrivateKeyAttributeCount, -1);
if (rc != CKR_OK) {
TRACE_ERROR("%s Dilithium check private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
rc = override_key_attributes(tokdata, ktype, CKO_PUBLIC_KEY,
new_pPublicKeyTemplate,
new_ulPublicKeyAttributeCount);
if (rc != CKR_OK) {
TRACE_ERROR("%s Dilithium override public key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
rc = override_key_attributes(tokdata, ktype, CKO_PRIVATE_KEY,
new_pPrivateKeyTemplate,
new_ulPrivateKeyAttributeCount);
if (rc != CKR_OK) {
TRACE_ERROR("%s Dilithium override private key attributes failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
/* debug */
for (i = 0; i < new_ulPrivateKeyAttributeCount; i++) {
TRACE_INFO("%s gen priv attr type=0x%lx valuelen=0x%lx attrcnt=0x%lx\n",
__func__, new_pPrivateKeyTemplate[i].type,
new_pPrivateKeyTemplate[i].ulValueLen,
new_ulPrivateKeyAttributeCount);
}
ep11_get_pin_blob(ep11_session,
(ep11_is_session_object
(pPublicKeyTemplate, ulPublicKeyAttributeCount)
|| ep11_is_session_object(pPrivateKeyTemplate,
ulPrivateKeyAttributeCount)),
&ep11_pin_blob, &ep11_pin_blob_len);
RETRY_START
rc = dll_m_GenerateKeyPair(pMechanism, new_pPublicKeyTemplate,
new_ulPublicKeyAttributeCount,
new_pPrivateKeyTemplate,
new_ulPrivateKeyAttributeCount,
ep11_pin_blob, ep11_pin_blob_len,
privkey_blob, &privkey_blob_len, spki,
&spki_len, ep11_data->target);
RETRY_END(rc, tokdata, sess)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, sess);
TRACE_ERROR("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx "
"privkey_blob_len=0x%zx mech='%s'\n",
__func__, rc, spki_len, privkey_blob_len,
ep11_get_ckm(pMechanism->mechanism));
goto error;
}
TRACE_INFO("%s m_GenerateKeyPair rc=0x%lx spki_len=0x%zx "
"privkey_blob_len=0x%zx mech='%s'\n",
__func__, rc, spki_len, privkey_blob_len,
ep11_get_ckm(pMechanism->mechanism));
if (spki_len > MAX_BLOBSIZE || privkey_blob_len > MAX_BLOBSIZE) {
TRACE_ERROR("%s blobsize error\n", __func__);
rc = CKR_KEY_INDIGESTIBLE;
goto error;
}
rc = build_attribute(CKA_IBM_OPAQUE, spki, spki_len, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = template_update_attribute(publ_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = build_attribute(CKA_IBM_OPAQUE, privkey_blob, privkey_blob_len, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = template_update_attribute(priv_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
/* Decode SPKI */
rc = ber_decode_SPKI(spki, &oid, &oid_len, &parm, &parm_len, &key,
&bit_str_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s read key from SPKI failed with rc=0x%lx\n", __func__,
rc);
goto error;
}
/* Public key must be a sequence holding two bit-strings: (rho, t1) */
rc = ber_decode_SEQUENCE(key, &data, &data_len, &field_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s read sequence failed with rc=0x%lx\n", __func__, rc);
goto error;
}
/* Decode rho */
rho = key + field_len - data_len;
rc = ber_decode_BIT_STRING(rho, &data, &data_len, &field_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s read rho failed with rc=0x%lx\n", __func__, rc);
goto error;
}
/* Remove leading unused-bits byte, returned by ber_decode_BIT_STRING */
data++;
data_len--;
#ifdef DEBUG
TRACE_DEBUG("%s dilithium_generate_keypair (rho):\n", __func__);
TRACE_DEBUG_DUMP(data, data_len);
#endif
/* build and add CKA_IBM_DILITHIUM_RHO */
rc = build_attribute(CKA_IBM_DILITHIUM_RHO, data, data_len, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = template_update_attribute(publ_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
/* Decode t1 */
t1 = rho + field_len;
rc = ber_decode_BIT_STRING(t1, &data, &data_len, &field_len);
if (rc != CKR_OK) {
TRACE_ERROR("%s read t failed with rc=0x%lx\n", __func__, rc);
goto error;
}
/* Remove leading unused-bits byte, returned by ber_decode_BIT_STRING */
data++;
data_len--;
#ifdef DEBUG
TRACE_DEBUG("%s dilithium_generate_keypair (t1):\n", __func__);
TRACE_DEBUG_DUMP(data, data_len);
#endif
/* build and add CKA_IBM_DILITHIUM_T1 */
rc = build_attribute(CKA_IBM_DILITHIUM_T1, data, data_len, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = template_update_attribute(publ_tmpl, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
error:
if (new_pPrivateKeyTemplate)
free_attribute_array(new_pPrivateKeyTemplate,
new_ulPrivateKeyAttributeCount);
if (new_pPublicKeyTemplate)
free_attribute_array(new_pPublicKeyTemplate,
new_ulPublicKeyAttributeCount);
return rc;
}
/* generic function to generate RSA,DH,EC and DSA key pairs */
CK_RV ep11tok_generate_key_pair(STDLL_TokData_t * tokdata, SESSION * sess,
CK_MECHANISM_PTR pMechanism,
CK_ATTRIBUTE_PTR pPublicKeyTemplate,
CK_ULONG ulPublicKeyAttributeCount,
CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
CK_ULONG ulPrivateKeyAttributeCount,
CK_OBJECT_HANDLE_PTR phPublicKey,
CK_OBJECT_HANDLE_PTR phPrivateKey)
{
CK_RV rc;
OBJECT *public_key_obj = NULL;
OBJECT *private_key_obj = NULL;
CK_ULONG priv_ktype, publ_ktype;
CK_ULONG class;
CK_ATTRIBUTE *attr = NULL;
CK_ATTRIBUTE *n_attr = NULL;
/* Get the keytype to use when creating the key object */
rc = ep11_get_keytype(pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
pMechanism, &priv_ktype, &class);
if (rc != CKR_OK) {
TRACE_ERROR("%s get_keytype failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = ep11_get_keytype(pPublicKeyTemplate, ulPublicKeyAttributeCount,
pMechanism, &publ_ktype, &class);
if (rc != CKR_OK) {
TRACE_ERROR("%s get_keytype failed with rc=0x%lx\n", __func__, rc);
goto error;
}
/* Now build the skeleton key. */
rc = object_mgr_create_skel(tokdata, sess, pPublicKeyTemplate,
ulPublicKeyAttributeCount, MODE_KEYGEN,
CKO_PUBLIC_KEY, publ_ktype, &public_key_obj);
if (rc != CKR_OK) {
TRACE_DEVEL("%s Object mgr create skeleton failed\n", __func__);
goto error;
}
rc = object_mgr_create_skel(tokdata, sess, pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, MODE_KEYGEN,
CKO_PRIVATE_KEY, priv_ktype, &private_key_obj);
if (rc != CKR_OK) {
TRACE_DEVEL("%s Object mgr create skeleton failed\n", __func__);
goto error;
}
switch (pMechanism->mechanism) {
case CKM_DH_PKCS_KEY_PAIR_GEN:
rc = dh_generate_keypair(tokdata, sess, pMechanism,
public_key_obj->template,
private_key_obj->template,
pPublicKeyTemplate,
ulPublicKeyAttributeCount,
pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, sess->handle);
break;
case CKM_EC_KEY_PAIR_GEN: /* takes same parameters as RSA */
case CKM_RSA_PKCS_KEY_PAIR_GEN:
case CKM_RSA_X9_31_KEY_PAIR_GEN:
rc = rsa_ec_generate_keypair(tokdata, sess, pMechanism,
public_key_obj->template,
private_key_obj->template,
pPublicKeyTemplate,
ulPublicKeyAttributeCount,
pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, sess->handle);
break;
case CKM_DSA_PARAMETER_GEN:
case CKM_DSA_KEY_PAIR_GEN:
rc = dsa_generate_keypair(tokdata, sess, pMechanism,
public_key_obj->template,
private_key_obj->template,
pPublicKeyTemplate,
ulPublicKeyAttributeCount,
pPrivateKeyTemplate,
ulPrivateKeyAttributeCount, sess->handle);
break;
case CKM_IBM_DILITHIUM:
rc = ibm_dilithium_generate_keypair(tokdata, sess, pMechanism,
public_key_obj->template,
private_key_obj->template,
pPublicKeyTemplate,
ulPublicKeyAttributeCount,
pPrivateKeyTemplate,
ulPrivateKeyAttributeCount,
sess->handle);
break;
default:
TRACE_ERROR("%s invalid mech %s\n", __func__,
ep11_get_ckm(pMechanism->mechanism));
rc = CKR_MECHANISM_INVALID;
goto error;
}
if (rc != CKR_OK) {
TRACE_ERROR("%s rc=0x%lx hpubkey=0x%lx hprivkey=0x%lx"
" pub_name='%s' priv_name='%s' pub_obj=%p priv_obj=%p\n",
__func__, rc, *phPublicKey, *phPrivateKey,
public_key_obj->name, private_key_obj->name,
(void *)public_key_obj, (void *)private_key_obj);
goto error;
} else {
TRACE_INFO("%s rc=0x%lx hpubkey=0x%lx hprivkey=0x%lx"
" pub_name='%s' priv_name='%s' pub_obj=%p priv_obj=%p\n",
__func__, rc, *phPublicKey, *phPrivateKey,
public_key_obj->name, private_key_obj->name,
(void *)public_key_obj, (void *)private_key_obj);
}
/* Copy CKA_MODULUS and CKA_PUBLIC_EXPONENT attributes from
* public key object to private key object to fulfill PKCS#11
* private key template requirements
*/
if (template_attribute_find(public_key_obj->template, CKA_MODULUS, &attr)) {
rc = build_attribute(attr->type, attr->pValue, attr->ulValueLen,
&n_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = template_update_attribute(private_key_obj->template, n_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
}
if (template_attribute_find(public_key_obj->template,
CKA_PUBLIC_EXPONENT, &attr)) {
rc = build_attribute(attr->type, attr->pValue, attr->ulValueLen,
&n_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = template_update_attribute(private_key_obj->template, n_attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
}
/* Keys should be fully constructed,
* assign object handles and store keys.
*/
rc = object_mgr_create_final(tokdata, sess, public_key_obj, phPublicKey);
if (rc != CKR_OK) {
TRACE_DEVEL("%s Object mgr create final failed\n", __func__);
goto error;
}
rc = object_mgr_create_final(tokdata, sess, private_key_obj, phPrivateKey);
if (rc != CKR_OK) {
TRACE_DEVEL("%s Object mgr create final failed\n", __func__);
object_mgr_destroy_object(tokdata, sess, *phPublicKey);
public_key_obj = NULL;
goto error;
}
return rc;
error:
if (public_key_obj)
object_free(public_key_obj);
if (private_key_obj)
object_free(private_key_obj);
*phPublicKey = 0;
*phPrivateKey = 0;
return rc;
}
/* Returns a blob for a key object.
* The blob is created if none was build yet.
* The passed key_obj must hold the READ lock!
*/
static CK_RV obj_opaque_2_blob(STDLL_TokData_t *tokdata, OBJECT *key_obj,
CK_BYTE **blob, size_t *blobsize)
{
CK_ATTRIBUTE *attr = NULL;
UNUSED(tokdata);
/* blob already exists */
if (template_attribute_find(key_obj->template, CKA_IBM_OPAQUE, &attr) &&
(attr->ulValueLen > 0)) {
*blob = attr->pValue;
*blobsize = (size_t) attr->ulValueLen;
TRACE_INFO("%s blob found blobsize=0x%zx\n", __func__, *blobsize);
return CKR_OK;
} else {
/* should not happen, imported key types not supported
* should cause a failing token_specific_object_add
*/
TRACE_ERROR("%s no blob\n", __func__);
return CKR_ATTRIBUTE_VALUE_INVALID;
}
}
/* Returns a blob for a key handle.
* The blob is created if none was build yet.
* The caller must put the returned kobj when no longer needed.
* The caller must unlock the returned kobj when no longer needed
*/
static CK_RV h_opaque_2_blob(STDLL_TokData_t *tokdata, CK_OBJECT_HANDLE handle,
CK_BYTE **blob, size_t *blobsize, OBJECT **kobj,
OBJ_LOCK_TYPE lock_type)
{
OBJECT *key_obj;
CK_RV rc;
/* find the key obj by the key handle */
rc = object_mgr_find_in_map1(tokdata, handle, &key_obj, lock_type);
if (rc != CKR_OK) {
TRACE_ERROR("%s key 0x%lx not mapped\n", __func__, handle);
if (rc == CKR_OBJECT_HANDLE_INVALID)
rc = CKR_KEY_HANDLE_INVALID;
return rc;
}
rc = obj_opaque_2_blob(tokdata, key_obj, blob, blobsize);
if (rc == CKR_OK) {
*kobj = key_obj;
} else {
object_put(tokdata, key_obj, lock_type != NO_LOCK);
key_obj = NULL;
}
return rc;
}
CK_RV ep11tok_sign_init(STDLL_TokData_t * tokdata, SESSION * session,
CK_MECHANISM * mech, CK_BBOOL recover_mode,
CK_OBJECT_HANDLE key)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
size_t keyblobsize = 0;
CK_BYTE *keyblob;
OBJECT *key_obj = NULL;
SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx;
size_t ep11_sign_state_l = MAX_SIGN_STATE_BYTES;
CK_BYTE *ep11_sign_state = malloc(ep11_sign_state_l);
UNUSED(recover_mode);
if (!ep11_sign_state) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj,
READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
RETRY_START
rc = dll_m_SignInit(ep11_sign_state, &ep11_sign_state_l,
mech, keyblob, keyblobsize, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx blobsize=0x%zx key=0x%lx mech=0x%lx\n",
__func__, rc, keyblobsize, key, mech->mechanism);
free(ep11_sign_state);
} else {
/* SIGN_VERIFY_CONTEX holds all needed for continuing,
* also by another adapter (stateless requests)
*/
ctx->key = key;
ctx->active = TRUE;
ctx->context = ep11_sign_state;
ctx->context_len = ep11_sign_state_l;
TRACE_INFO("%s rc=0x%lx blobsize=0x%zx key=0x%lx mech=0x%lx\n",
__func__, rc, keyblobsize, key, mech->mechanism);
}
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV ep11tok_sign(STDLL_TokData_t * tokdata, SESSION * session,
CK_BBOOL length_only, CK_BYTE * in_data,
CK_ULONG in_data_len, CK_BYTE * signature,
CK_ULONG * sig_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx;
UNUSED(length_only);
RETRY_START
rc = dll_m_Sign(ctx->context, ctx->context_len, in_data, in_data_len,
signature, sig_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_sign_update(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE * in_data, CK_ULONG in_data_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx;
if (!in_data || !in_data_len)
return CKR_OK;
RETRY_START
rc = dll_m_SignUpdate(ctx->context, ctx->context_len, in_data,
in_data_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_sign_final(STDLL_TokData_t * tokdata, SESSION * session,
CK_BBOOL length_only, CK_BYTE * signature,
CK_ULONG * sig_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx;
UNUSED(length_only);
RETRY_START
rc = dll_m_SignFinal(ctx->context, ctx->context_len, signature, sig_len,
ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_sign_single(STDLL_TokData_t *tokdata, SESSION *session,
CK_MECHANISM *mech, CK_BBOOL length_only,
CK_OBJECT_HANDLE key, CK_BYTE *in_data,
CK_ULONG in_data_len, CK_BYTE *signature,
CK_ULONG *sig_len)
{
CK_RV rc;
size_t keyblobsize = 0;
CK_BYTE *keyblob;
OBJECT *key_obj = NULL;
ep11_private_data_t *ep11_data = tokdata->private_data;
UNUSED(length_only);
rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj,
READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
RETRY_START
rc = dll_m_SignSingle(keyblob, keyblobsize, mech, in_data, in_data_len,
signature, sig_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV ep11tok_verify_init(STDLL_TokData_t * tokdata, SESSION * session,
CK_MECHANISM * mech, CK_BBOOL recover_mode,
CK_OBJECT_HANDLE key)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE *spki;
size_t spki_len = 0;
OBJECT *key_obj = NULL;
SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx;
size_t ep11_sign_state_l = MAX_SIGN_STATE_BYTES;
CK_BYTE *ep11_sign_state = malloc(ep11_sign_state_l);
if (!ep11_sign_state) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
rc = h_opaque_2_blob(tokdata, key, &spki, &spki_len, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
/*
* Enforce key usage restrictions. EP11 does not allow to restrict
* public keys with CKA_VERIFY=FALSE. Thus we need to enforce the
* restriction here.
*/
rc = check_key_restriction(key_obj,
recover_mode ? CKA_VERIFY_RECOVER : CKA_VERIFY);
if (rc != CKR_OK) {
TRACE_ERROR("%s check_key_restriction rc=0x%lx\n", __func__, rc);
goto done;
}
RETRY_START
rc = dll_m_VerifyInit(ep11_sign_state, &ep11_sign_state_l, mech,
spki, spki_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx spki_len=0x%zx key=0x%lx "
"ep11_sign_state_l=0x%zx mech=0x%lx\n", __func__,
rc, spki_len, key, ep11_sign_state_l, mech->mechanism);
} else {
ctx->key = key;
ctx->active = TRUE;
ctx->context = ep11_sign_state;
ctx->context_len = ep11_sign_state_l;
TRACE_INFO("%s rc=0x%lx spki_len=0x%zx key=0x%lx "
"ep11_sign_state_l=0x%zx mech=0x%lx\n", __func__,
rc, spki_len, key, ep11_sign_state_l, mech->mechanism);
}
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV ep11tok_verify(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE * in_data, CK_ULONG in_data_len,
CK_BYTE * signature, CK_ULONG sig_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx;
RETRY_START
rc = dll_m_Verify(ctx->context, ctx->context_len, in_data, in_data_len,
signature, sig_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_verify_update(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE * in_data, CK_ULONG in_data_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx;
if (!in_data || !in_data_len)
return CKR_OK;
RETRY_START
rc = dll_m_VerifyUpdate(ctx->context, ctx->context_len, in_data,
in_data_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_verify_final(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE * signature, CK_ULONG sig_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx;
RETRY_START
rc = dll_m_VerifyFinal(ctx->context, ctx->context_len, signature,
sig_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_verify_single(STDLL_TokData_t *tokdata, SESSION *session,
CK_MECHANISM *mech, CK_OBJECT_HANDLE key,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG sig_len)
{
CK_RV rc;
CK_BYTE *spki;
size_t spki_len = 0;
OBJECT *key_obj = NULL;
ep11_private_data_t *ep11_data = tokdata->private_data;
rc = h_opaque_2_blob(tokdata, key, &spki, &spki_len, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
/*
* Enforce key usage restrictions. EP11 does not allow to restrict
* public keys with CKA_VERIFY=FALSE. Thus we need to enforce the
* restriction here.
*/
rc = check_key_restriction(key_obj, CKA_VERIFY);
if (rc != CKR_OK) {
TRACE_ERROR("%s check_key_restriction rc=0x%lx\n", __func__, rc);
goto done;
}
RETRY_START
rc = dll_m_VerifySingle(spki, spki_len, mech, in_data, in_data_len,
signature, sig_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV ep11tok_decrypt_final(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE_PTR output_part,
CK_ULONG_PTR p_output_part_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc = CKR_OK;
ENCR_DECR_CONTEXT *ctx = &session->decr_ctx;
RETRY_START
rc = dll_m_DecryptFinal(ctx->context, ctx->context_len,
output_part, p_output_part_len,
ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_decrypt(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE_PTR input_data, CK_ULONG input_data_len,
CK_BYTE_PTR output_data, CK_ULONG_PTR p_output_data_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc = CKR_OK;
ENCR_DECR_CONTEXT *ctx = &session->decr_ctx;
RETRY_START
rc = dll_m_Decrypt(ctx->context, ctx->context_len, input_data,
input_data_len, output_data, p_output_data_len,
ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_decrypt_update(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE_PTR input_part, CK_ULONG input_part_len,
CK_BYTE_PTR output_part,
CK_ULONG_PTR p_output_part_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc = CKR_OK;
ENCR_DECR_CONTEXT *ctx = &session->decr_ctx;
if (!input_part || !input_part_len) {
*p_output_part_len = 0;
return CKR_OK; /* nothing to update, keep context */
}
RETRY_START
rc = dll_m_DecryptUpdate(ctx->context, ctx->context_len,
input_part, input_part_len, output_part,
p_output_part_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_decrypt_single(STDLL_TokData_t *tokdata, SESSION *session,
CK_MECHANISM *mech, CK_BBOOL length_only,
CK_OBJECT_HANDLE key, CK_BYTE_PTR input_data,
CK_ULONG input_data_len, CK_BYTE_PTR output_data,
CK_ULONG_PTR p_output_data_len)
{
CK_RV rc;
size_t keyblobsize = 0;
CK_BYTE *keyblob;
OBJECT *key_obj = NULL;
ep11_private_data_t *ep11_data = tokdata->private_data;
UNUSED(length_only);
rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj,
READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
RETRY_START
rc = dll_m_DecryptSingle(keyblob, keyblobsize, mech, input_data,
input_data_len, output_data, p_output_data_len,
ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV ep11tok_encrypt_final(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE_PTR output_part,
CK_ULONG_PTR p_output_part_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc = CKR_OK;
ENCR_DECR_CONTEXT *ctx = &session->encr_ctx;
RETRY_START
rc = dll_m_EncryptFinal(ctx->context, ctx->context_len,
output_part, p_output_part_len,
ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_encrypt(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE_PTR input_data, CK_ULONG input_data_len,
CK_BYTE_PTR output_data, CK_ULONG_PTR p_output_data_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc = CKR_OK;
ENCR_DECR_CONTEXT *ctx = &session->encr_ctx;
RETRY_START
rc = dll_m_Encrypt(ctx->context, ctx->context_len, input_data,
input_data_len, output_data, p_output_data_len,
ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_encrypt_update(STDLL_TokData_t * tokdata, SESSION * session,
CK_BYTE_PTR input_part, CK_ULONG input_part_len,
CK_BYTE_PTR output_part,
CK_ULONG_PTR p_output_part_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc = CKR_OK;
ENCR_DECR_CONTEXT *ctx = &session->encr_ctx;
if (!input_part || !input_part_len) {
*p_output_part_len = 0;
return CKR_OK; /* nothing to update, keep context */
}
RETRY_START
rc = dll_m_EncryptUpdate(ctx->context, ctx->context_len,
input_part, input_part_len, output_part,
p_output_part_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_encrypt_single(STDLL_TokData_t *tokdata, SESSION *session,
CK_MECHANISM *mech, CK_BBOOL length_only,
CK_OBJECT_HANDLE key, CK_BYTE_PTR input_data,
CK_ULONG input_data_len, CK_BYTE_PTR output_data,
CK_ULONG_PTR p_output_data_len)
{
CK_RV rc;
size_t keyblobsize = 0;
CK_BYTE *keyblob;
OBJECT *key_obj = NULL;
ep11_private_data_t *ep11_data = tokdata->private_data;
UNUSED(length_only);
rc = h_opaque_2_blob(tokdata, key, &keyblob, &keyblobsize, &key_obj,
READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
return rc;
}
/*
* Enforce key usage restrictions. EP11 does not allow to restrict
* public keys with CKA_ENCRYPT=FALSE. Thus we need to enforce the
* restriction here.
*/
rc = check_key_restriction(key_obj, CKA_ENCRYPT);
if (rc != CKR_OK) {
TRACE_ERROR("%s check_key_restriction rc=0x%lx\n", __func__, rc);
goto done;
}
RETRY_START
rc = dll_m_EncryptSingle(keyblob, keyblobsize, mech, input_data,
input_data_len, output_data, p_output_data_len,
ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
static CK_RV ep11_ende_crypt_init(STDLL_TokData_t * tokdata, SESSION * session,
CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE key,
int op)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc = CKR_OK;
CK_BYTE *blob;
size_t blob_len = 0;
OBJECT *key_obj = NULL;
size_t ep11_state_l = MAX_CRYPT_STATE_BYTES;
CK_BYTE *ep11_state;
ep11_state = malloc(ep11_state_l); /* freed by encr/decr_mgr.c */
if (!ep11_state) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
rc = h_opaque_2_blob(tokdata, key, &blob, &blob_len, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s no blob rc=0x%lx\n", __func__, rc);
goto error;
}
if (op == DECRYPT) {
ENCR_DECR_CONTEXT *ctx = &session->decr_ctx;
RETRY_START
rc = dll_m_DecryptInit(ep11_state, &ep11_state_l, mech, blob,
blob_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
ctx->key = key;
ctx->active = TRUE;
ctx->context = ep11_state;
ctx->context_len = ep11_state_l;
if (rc != CKR_OK) {
decr_mgr_cleanup(ctx);
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s m_DecryptInit rc=0x%lx blob_len=0x%zx "
"mech=0x%lx\n", __func__, rc, blob_len,
mech->mechanism);
} else {
TRACE_INFO("%s m_DecryptInit rc=0x%lx blob_len=0x%zx "
"mech=0x%lx\n", __func__, rc, blob_len, mech->mechanism);
}
} else {
ENCR_DECR_CONTEXT *ctx = &session->encr_ctx;
/*
* Enforce key usage restrictions. EP11 does not allow to restrict
* public keys with CKA_ENCRYPT=FALSE. Thus we need to enforce the
* restriction here.
*/
rc = check_key_restriction(key_obj, CKA_ENCRYPT);
if (rc != CKR_OK) {
TRACE_ERROR("%s check_key_restriction rc=0x%lx\n", __func__, rc);
goto error;
}
RETRY_START
rc = dll_m_EncryptInit(ep11_state, &ep11_state_l, mech, blob,
blob_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
ctx->key = key;
ctx->active = TRUE;
ctx->context = ep11_state;
ctx->context_len = ep11_state_l;
if (rc != CKR_OK) {
encr_mgr_cleanup(ctx);
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s m_EncryptInit rc=0x%lx blob_len=0x%zx "
"mech=0x%lx\n", __func__, rc, blob_len,
mech->mechanism);
} else {
TRACE_INFO("%s m_EncryptInit rc=0x%lx blob_len=0x%zx "
"mech=0x%lx\n", __func__, rc, blob_len, mech->mechanism);
}
}
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
error:
if (ep11_state != NULL)
free(ep11_state);
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV ep11tok_encrypt_init(STDLL_TokData_t * tokdata, SESSION * session,
CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE key)
{
CK_RV rc;
TRACE_INFO("%s key=0x%lx\n", __func__, key);
rc = ep11_ende_crypt_init(tokdata, session, mech, key, ENCRYPT);
if (rc != CKR_OK) {
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_decrypt_init(STDLL_TokData_t * tokdata, SESSION * session,
CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE key)
{
CK_RV rc;
TRACE_INFO("%s key=0x%lx mech=0x%lx\n", __func__, key, mech->mechanism);
rc = ep11_ende_crypt_init(tokdata, session, mech, key, DECRYPT);
if (rc != CKR_OK) {
TRACE_ERROR("%s rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx\n", __func__, rc);
}
return rc;
}
CK_RV ep11tok_wrap_key(STDLL_TokData_t * tokdata, SESSION * session,
CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE wrapping_key,
CK_OBJECT_HANDLE key, CK_BYTE_PTR wrapped_key,
CK_ULONG_PTR p_wrapped_key_len)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE *wrapping_blob;
size_t wrapping_blob_len;
CK_BYTE *wrap_target_blob;
size_t wrap_target_blob_len;
int size_query = 0;
OBJECT *key_obj = NULL, *wrap_key_obj = NULL;
CK_ATTRIBUTE *attr;
/* ep11 weakness:
* it does not set *p_wrapped_key_len if wrapped_key == NULL
* (that is with a size query)
*/
if (wrapped_key == NULL) {
size_query = 1;
*p_wrapped_key_len = MAX_BLOBSIZE;
wrapped_key = malloc(MAX_BLOBSIZE);
if (!wrapped_key) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
}
/* the key that encrypts */
rc = h_opaque_2_blob(tokdata, wrapping_key, &wrapping_blob,
&wrapping_blob_len, &wrap_key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s h_opaque_2_blob(wrapping_key) failed with rc=0x%lx\n",
__func__, rc);
if (size_query)
free(wrapped_key);
return rc;
}
/* the key to be wrapped */
rc = h_opaque_2_blob(tokdata, key, &wrap_target_blob,
&wrap_target_blob_len, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s h_opaque_2_blob(key) failed with rc=0x%lx\n", __func__,
rc);
if (size_query)
free(wrapped_key);
goto done;
}
/* check if wrap mechanism is allowed for the key to be wrapped.
* AES_ECB and AES_CBC is only allowed to wrap secret keys.
*/
if (!template_attribute_find(key_obj->template, CKA_CLASS, &attr)) {
TRACE_ERROR("%s No CKA_CLASS attribute found in key template\n",
__func__);
rc = CKR_TEMPLATE_INCOMPLETE;
goto done;
}
if ((*(CK_OBJECT_CLASS *) attr->pValue != CKO_SECRET_KEY) &&
((mech->mechanism == CKM_AES_ECB) ||
(mech->mechanism == CKM_AES_CBC))) {
TRACE_ERROR("%s Wrap mechanism does not match to target key type\n",
__func__);
rc = CKR_KEY_NOT_WRAPPABLE;
goto done;
}
/* debug */
TRACE_INFO("%s start wrapKey: mech=0x%lx wr_key=0x%lx\n",
__func__, mech->mechanism, wrapping_key);
/* The key to be wrapped is extracted from its blob by the card.
* A standard BER encoding is built and encrypted by the wrapping key
* (wrapping blob). The wrapped key can be processed by any PKCS11
* implementation.
*/
RETRY_START
rc =
dll_m_WrapKey(wrap_target_blob, wrap_target_blob_len, wrapping_blob,
wrapping_blob_len, NULL, ~0, mech, wrapped_key,
p_wrapped_key_len, ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
TRACE_ERROR("%s m_WrapKey failed with rc=0x%lx\n", __func__, rc);
} else {
TRACE_INFO("%s rc=0x%lx wr_key=%p wr_key_len=0x%lx\n",
__func__, rc, (void *)wrapped_key, *p_wrapped_key_len);
}
if (size_query)
free(wrapped_key);
done:
object_put(tokdata, wrap_key_obj, TRUE);
wrap_key_obj = NULL;
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV ep11tok_unwrap_key(STDLL_TokData_t * tokdata, SESSION * session,
CK_MECHANISM_PTR mech, CK_ATTRIBUTE_PTR attrs,
CK_ULONG attrs_len, CK_BYTE_PTR wrapped_key,
CK_ULONG wrapped_key_len,
CK_OBJECT_HANDLE wrapping_key,
CK_OBJECT_HANDLE_PTR p_key)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_BYTE *wrapping_blob;
size_t wrapping_blob_len;
CK_BYTE csum[MAX_BLOBSIZE];
CK_ULONG cslen = sizeof(csum);
OBJECT *key_obj = NULL;
CK_BYTE keyblob[MAX_BLOBSIZE];
size_t keyblobsize = sizeof(keyblob);
CK_ATTRIBUTE *attr = NULL;
CK_ULONG i;
CK_ULONG ktype;
CK_ULONG class;
CK_ULONG len;
CK_ATTRIBUTE_PTR new_attrs = NULL;
CK_ULONG new_attrs_len = 0;
OBJECT *kobj = NULL;
unsigned char *ep11_pin_blob = NULL;
CK_ULONG ep11_pin_blob_len = 0;
ep11_session_t *ep11_session = (ep11_session_t *) session->private_data;
/* get wrapping key blob */
rc = h_opaque_2_blob(tokdata, wrapping_key, &wrapping_blob,
&wrapping_blob_len, &kobj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("%s h_opaque_2_blob(wrapping_key) failed with rc=0x%lx\n",
__func__, rc);
return rc;
}
TRACE_DEVEL("%s start unwrapKey: mech=0x%lx attrs_len=0x%lx "
"wr_key=0x%lx\n", __func__, mech->mechanism, attrs_len,
wrapping_key);
for (i = 0; i < attrs_len; i++) {
TRACE_DEVEL(" attribute attrs.type=0x%lx\n", attrs[i].type);
}
memset(keyblob, 0, sizeof(keyblob));
/*get key type of unwrapped key */
CK_ATTRIBUTE_PTR cla_attr =
get_attribute_by_type(attrs, attrs_len, CKA_CLASS);
CK_ATTRIBUTE_PTR keytype_attr =
get_attribute_by_type(attrs, attrs_len, CKA_KEY_TYPE);
if (!cla_attr || !keytype_attr) {
TRACE_ERROR("%s CKA_CLASS or CKA_KEY_CLASS attributes not found\n",
__func__);
rc = CKR_TEMPLATE_INCONSISTENT;
goto error;
}
switch (*(CK_OBJECT_CLASS *) cla_attr->pValue) {
case CKO_SECRET_KEY:
rc = check_key_attributes(tokdata,
*(CK_KEY_TYPE *) keytype_attr->pValue,
CKO_SECRET_KEY, attrs,
attrs_len, &new_attrs, &new_attrs_len, -1);
break;
case CKO_PUBLIC_KEY:
rc = check_key_attributes(tokdata,
*(CK_KEY_TYPE *) keytype_attr->pValue,
CKO_PUBLIC_KEY, attrs, attrs_len,
&new_attrs, &new_attrs_len, -1);
break;
case CKO_PRIVATE_KEY:
rc = check_key_attributes(tokdata,
*(CK_KEY_TYPE *) keytype_attr->pValue,
CKO_PRIVATE_KEY, attrs, attrs_len,
&new_attrs, &new_attrs_len, -1);
break;
default:
TRACE_ERROR("%s Missing CKA_CLASS type of wrapped key\n", __func__);
rc = CKR_TEMPLATE_INCOMPLETE;
goto error;
}
if (rc != CKR_OK) {
TRACE_ERROR("%s check key attributes failed: rc=0x%lx\n", __func__, rc);
goto error;
}
/* check if unwrap mechanism is allowed for the key to be unwrapped.
* AES_ECB and AES_CBC only allowed to unwrap secret keys.
*/
if ((*(CK_OBJECT_CLASS *) cla_attr->pValue != CKO_SECRET_KEY) &&
((mech->mechanism == CKM_AES_ECB) ||
(mech->mechanism == CKM_AES_CBC))) {
rc = CKR_ARGUMENTS_BAD;
goto error;
}
ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len),
&ep11_pin_blob, &ep11_pin_blob_len);
/* we need a blob for the new key created by unwrapping,
* the wrapped key comes in BER
*/
RETRY_START
rc = dll_m_UnwrapKey(wrapped_key, wrapped_key_len, wrapping_blob,
wrapping_blob_len, NULL, ~0, ep11_pin_blob,
ep11_pin_blob_len, mech, new_attrs, new_attrs_len,
keyblob, &keyblobsize, csum, &cslen,
ep11_data->target);
RETRY_END(rc, tokdata, session)
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s m_UnwrapKey rc=0x%lx blobsize=0x%zx mech=0x%lx\n",
__func__, rc, keyblobsize, mech->mechanism);
goto error;
}
TRACE_INFO("%s m_UnwrapKey rc=0x%lx blobsize=0x%zx mech=0x%lx\n",
__func__, rc, keyblobsize, mech->mechanism);
/* Get the keytype to use when creating the key object */
rc = ep11_get_keytype(new_attrs, new_attrs_len, mech, &ktype, &class);
if (rc != CKR_OK) {
TRACE_ERROR("%s get_subclass failed with rc=0x%lx\n", __func__, rc);
goto error;
}
/* Start creating the key object */
rc = object_mgr_create_skel(tokdata, session, new_attrs, new_attrs_len,
MODE_UNWRAP, class, ktype, &key_obj);
if (rc != CKR_OK) {
TRACE_ERROR("%s object_mgr_create_skel failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = build_attribute(CKA_IBM_OPAQUE, keyblob, keyblobsize, &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n", __func__, rc);
goto error;
}
rc = template_update_attribute(key_obj->template, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
switch (*(CK_OBJECT_CLASS *) cla_attr->pValue) {
case CKO_SECRET_KEY:
/* card provides bit length in csum last 4 bytes big endian */
if (cslen < 4) {
rc = CKR_FUNCTION_FAILED;
TRACE_ERROR("%s Invalid csum length cslen=%lu\n", __func__, cslen);
goto error;
}
len = csum[cslen - 1] + 256 * csum[cslen - 2] +
256 * 256 * csum[cslen - 3] + 256 * 256 * 256 * csum[cslen - 4];
len = len / 8; /* comes in bits */
TRACE_INFO("%s m_UnwrapKey length %lu 0x%lx\n", __func__, len, len);
switch (*(CK_KEY_TYPE *) keytype_attr->pValue) {
case CKK_AES:
case CKK_GENERIC_SECRET:
rc = build_attribute(CKA_VALUE_LEN, (CK_BYTE *)&len,
sizeof(CK_ULONG), &attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s build_attribute failed with rc=0x%lx\n",
__func__, rc);
goto error;
}
rc = template_update_attribute(key_obj->template, attr);
if (rc != CKR_OK) {
TRACE_ERROR("%s template_update_attribute failed with "
"rc=0x%lx\n", __func__, rc);
goto error;
}
break;
}
break;
case CKO_PRIVATE_KEY:
/*
* In case of unwrapping a private key (CKA_CLASS == CKO_PRIVATE_KEY),
* the public key attributes needs to be added to the new template.
*/
switch (*(CK_KEY_TYPE *) keytype_attr->pValue) {
case CKK_EC:
rc = ecdsa_priv_unwrap_get_data(key_obj->template, csum, cslen);
break;
case CKK_RSA:
rc = rsa_priv_unwrap_get_data(key_obj->template, csum, cslen);
break;
case CKK_DSA:
rc = dsa_priv_unwrap_get_data(key_obj->template, csum, cslen);
break;
case CKK_DH:
rc = dh_priv_unwrap_get_data(key_obj->template, csum, cslen);
break;
case CKK_IBM_PQC_DILITHIUM:
rc = ibm_dilithium_priv_unwrap_get_data(key_obj->template, csum, cslen);
break;
}
if (rc != 0) {
TRACE_ERROR("%s xxx_priv_unwrap_get_data rc=0x%lx\n",
__func__, rc);
goto error;
}
break;
}
/* key should be fully constructed.
* Assign an object handle and store key.
*/
rc = object_mgr_create_final(tokdata, session, key_obj, p_key);
if (rc != CKR_OK) {
TRACE_ERROR("%s object_mgr_create_final with rc=0x%lx\n", __func__, rc);
goto error;
}
goto done;
error:
if (key_obj)
object_free(key_obj);
*p_key = 0;
done:
if (new_attrs)
free_attribute_array(new_attrs, new_attrs_len);
object_put(tokdata, kobj, TRUE);
kobj = NULL;
return rc;
}
static const CK_MECHANISM_TYPE ep11_supported_mech_list[] = {
CKM_AES_CBC,
CKM_AES_CBC_PAD,
CKM_AES_CMAC,
CKM_AES_ECB,
CKM_AES_KEY_GEN,
CKM_DES2_KEY_GEN,
CKM_DES3_CBC,
CKM_DES3_CBC_PAD,
CKM_DES3_CMAC,
CKM_DES3_ECB,
CKM_DES3_KEY_GEN,
CKM_DH_PKCS_DERIVE,
CKM_DH_PKCS_KEY_PAIR_GEN,
CKM_DH_PKCS_PARAMETER_GEN,
CKM_DSA,
CKM_DSA_KEY_PAIR_GEN,
CKM_DSA_PARAMETER_GEN,
CKM_DSA_SHA1,
CKM_EC_KEY_PAIR_GEN,
CKM_ECDH1_DERIVE,
CKM_ECDSA,
CKM_ECDSA_SHA1,
CKM_ECDSA_SHA224,
CKM_ECDSA_SHA256,
CKM_ECDSA_SHA384,
CKM_ECDSA_SHA512,
CKM_IBM_CMAC,
CKM_IBM_DILITHIUM,
CKM_IBM_EC_X25519,
CKM_IBM_EC_X448,
CKM_IBM_ED25519_SHA512,
CKM_IBM_ED448_SHA3,
CKM_IBM_SHA3_224,
CKM_IBM_SHA3_224_HMAC,
CKM_IBM_SHA3_256,
CKM_IBM_SHA3_256_HMAC,
CKM_IBM_SHA3_384,
CKM_IBM_SHA3_384_HMAC,
CKM_IBM_SHA3_512,
CKM_IBM_SHA3_512_HMAC,
CKM_PBE_SHA1_DES3_EDE_CBC,
CKM_RSA_PKCS,
CKM_RSA_PKCS_KEY_PAIR_GEN,
CKM_RSA_PKCS_OAEP,
CKM_RSA_PKCS_PSS,
CKM_RSA_X9_31,
CKM_RSA_X9_31_KEY_PAIR_GEN,
CKM_SHA1_KEY_DERIVATION,
CKM_SHA1_RSA_PKCS,
CKM_SHA1_RSA_PKCS_PSS,
CKM_SHA1_RSA_X9_31,
CKM_SHA224,
CKM_SHA224_HMAC,
CKM_SHA224_KEY_DERIVATION,
CKM_SHA224_RSA_PKCS,
CKM_SHA224_RSA_PKCS_PSS,
CKM_SHA256,
CKM_SHA256_HMAC,
CKM_SHA256_KEY_DERIVATION,
CKM_SHA256_RSA_PKCS,
CKM_SHA256_RSA_PKCS_PSS,
CKM_SHA384,
CKM_SHA384_HMAC,
CKM_SHA384_KEY_DERIVATION,
CKM_SHA384_RSA_PKCS,
CKM_SHA384_RSA_PKCS_PSS,
CKM_SHA512,
CKM_SHA512_224,
CKM_SHA512_224_HMAC,
CKM_SHA512_256,
CKM_SHA512_256_HMAC,
CKM_SHA512_HMAC,
CKM_SHA512_KEY_DERIVATION,
CKM_SHA512_RSA_PKCS,
CKM_SHA512_RSA_PKCS_PSS,
CKM_SHA_1,
CKM_SHA_1_HMAC,
};
static const CK_ULONG supported_mech_list_len =
(sizeof(ep11_supported_mech_list) / sizeof(CK_MECHANISM_TYPE));
/* filtering out some mechanisms we do not want to provide
* makes it complicated
*/
CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata,
CK_MECHANISM_TYPE_PTR pMechanismList,
CK_ULONG_PTR pulCount)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc = 0;
CK_ULONG counter = 0, size = 0;
CK_MECHANISM_TYPE_PTR mlist = NULL;
CK_ULONG i;
/* size querry */
if (pMechanismList == NULL) {
rc = dll_m_GetMechanismList(0, pMechanismList, pulCount,
ep11_data->target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #1\n",
__func__, rc);
return rc;
}
/* adjust the size according to the ban list,
* for this we need to know what the card provides
*/
counter = *pulCount;
/*
* For mixed card levels, the size query call and the call to obtain the
* list may run on different cards. When the size query call runs on a
* card with less mechanisms than the second call, return code
* CKR_BUFFER_TOO_SMALL may be encountered, when the card where the
* second call runs supports more mechanisms than the one where the
* size query was run. Repeat the call to obtain the list with the
* larger list.
*/
do {
mlist = (CK_MECHANISM_TYPE *) malloc(
sizeof(CK_MECHANISM_TYPE) * counter);
if (!mlist) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
rc = dll_m_GetMechanismList(0, mlist, &counter, ep11_data->target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #2\n",
__func__, rc);
free(mlist);
if (rc != CKR_BUFFER_TOO_SMALL)
return rc;
}
} while (rc == CKR_BUFFER_TOO_SMALL);
for (i = 0; i < counter; i++) {
if (ep11tok_is_mechanism_supported(tokdata, mlist[i]) != CKR_OK) {
/* banned mech found,
* decrement reported list size
*/
*pulCount = *pulCount - 1;
}
}
} else {
/* 2. call, content request */
size = *pulCount;
/* find out size ep11 will report, cannot use the size
* that comes as parameter, this is a 'reduced size',
* ep11 would complain about insufficient list size
*/
rc = dll_m_GetMechanismList(0, mlist, &counter, ep11_data->target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #3\n",
__func__, rc);
return rc;
}
/*
* For mixed card levels, the size query call and the call to obtain the
* list may run on different cards. When the size query call runs on a
* card with less mechanisms than the second call, return code
* CKR_BUFFER_TOO_SMALL may be encountered, when the card where the
* second call runs supports more mechanisms than the one where the
* size query was run. Repeat the call to obtain the list with the
* larger list.
*/
do {
mlist = (CK_MECHANISM_TYPE *) malloc(
sizeof(CK_MECHANISM_TYPE) * counter);
if (!mlist) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
/* all the card has */
rc = dll_m_GetMechanismList(0, mlist, &counter, ep11_data->target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #4\n",
__func__, rc);
free(mlist);
if (rc != CKR_BUFFER_TOO_SMALL)
return rc;
}
} while (rc == CKR_BUFFER_TOO_SMALL);
for (i = 0; i < counter; i++)
TRACE_INFO("%s raw mech list entry '%s'\n",
__func__, ep11_get_ckm(mlist[i]));
/* copy only mechanisms not banned */
*pulCount = 0;
for (i = 0; i < counter; i++) {
if (ep11tok_is_mechanism_supported(tokdata, mlist[i]) == CKR_OK) {
if (*pulCount < size)
pMechanismList[*pulCount] = mlist[i];
*pulCount = *pulCount + 1;
}
}
if (*pulCount > size)
rc = CKR_BUFFER_TOO_SMALL;
}
if (mlist)
free(mlist);
return rc;
}
CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata,
CK_MECHANISM_TYPE type)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_VERSION ver1_3 = { .major = 1, .minor = 3 };
CK_VERSION ver3 = { .major = 3, .minor = 0 };
CK_BBOOL found = FALSE;
CK_ULONG i;
int status;
for (i = 0; i < supported_mech_list_len; i++) {
if (type == ep11_supported_mech_list[i]) {
found = TRUE;
break;
}
}
if (!found) {
TRACE_INFO("%s Mech '%s' not suppported\n", __func__,
ep11_get_ckm(type));
return CKR_MECHANISM_INVALID;
}
if (check_cps_for_mechanism(ep11_data->cp_config,
type, ep11_data->control_points,
ep11_data->control_points_len,
ep11_data->max_control_point_index) != CKR_OK) {
TRACE_INFO("%s Mech '%s' banned due to control point\n",
__func__, ep11_get_ckm(type));
return CKR_MECHANISM_INVALID;
}
switch(type) {
case CKM_SHA_1_HMAC:
case CKM_SHA_1_HMAC_GENERAL:
case CKM_SHA224_HMAC:
case CKM_SHA224_HMAC_GENERAL:
case CKM_SHA256_HMAC:
case CKM_SHA256_HMAC_GENERAL:
case CKM_SHA384_HMAC:
case CKM_SHA384_HMAC_GENERAL:
case CKM_SHA512_HMAC:
case CKM_SHA512_HMAC_GENERAL:
case CKM_SHA512_224_HMAC:
case CKM_SHA512_224_HMAC_GENERAL:
case CKM_SHA512_256_HMAC:
case CKM_SHA512_256_HMAC_GENERAL:
/*
* Older levels of the EP11 firmware report ulMinKeySize in bytes,
* but ulMaxKeySize in bits for HMAC mechanisms. Newer levels of the
* EP11 firmware report both ulMinKeySize and ulMaxKeySize in bytes.
* HMAC mechanisms are only supported when all configured EP11
* crypto adapters either have the fix, or all don't have the fix.
*/
status = check_required_versions(tokdata, hmac_req_versions,
NUM_HMAC_REQ);
if (status == -1) {
TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n",
__func__, ep11_get_ckm(type));
return CKR_MECHANISM_INVALID;
}
break;
case CKM_RSA_PKCS_OAEP:
/* CKM_RSA_PKCS_OAEP is not supported with EP11 host library <= 1.3 */
if (compare_ck_version(&ep11_data->ep11_lib_version, &ver1_3) <= 0)
return CKR_MECHANISM_INVALID;
break;
case CKM_IBM_SHA3_224:
case CKM_IBM_SHA3_256:
case CKM_IBM_SHA3_384:
case CKM_IBM_SHA3_512:
case CKM_IBM_SHA3_224_HMAC:
case CKM_IBM_SHA3_256_HMAC:
case CKM_IBM_SHA3_384_HMAC:
case CKM_IBM_SHA3_512_HMAC:
status = check_required_versions(tokdata, ibm_sha3_req_versions,
NUM_IBM_SHA3_REQ);
if (status != 1) {
TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n",
__func__, ep11_get_ckm(type));
return CKR_MECHANISM_INVALID;
}
break;
case CKM_DES3_CMAC:
case CKM_DES3_CMAC_GENERAL:
case CKM_AES_CMAC:
case CKM_AES_CMAC_GENERAL:
status = check_required_versions(tokdata, cmac_req_versions,
NUM_CMAC_REQ);
if (status != 1) {
TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n",
__func__, ep11_get_ckm(type));
return CKR_MECHANISM_INVALID;
}
break;
case CKM_IBM_EC_C25519:
case CKM_IBM_ED25519_SHA512:
case CKM_IBM_EC_C448:
case CKM_IBM_ED448_SHA3:
if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3) < 0) {
TRACE_INFO("%s Mech '%s' banned due to host library version\n",
__func__, ep11_get_ckm(type));
return CKR_MECHANISM_INVALID;
}
status = check_required_versions(tokdata, edwards_req_versions,
NUM_EDWARDS_REQ);
if (status != 1) {
TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n",
__func__, ep11_get_ckm(type));
return CKR_MECHANISM_INVALID;
}
break;
case CKM_IBM_DILITHIUM:
if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3) <= 0) {
TRACE_INFO("%s Mech '%s' banned due to host library version\n",
__func__, ep11_get_ckm(type));
return CKR_MECHANISM_INVALID;
}
status = check_required_versions(tokdata, ibm_dilithium_req_versions,
NUM_DILITHIUM_REQ);
if (status != 1) {
TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n",
__func__, ep11_get_ckm(type));
return CKR_MECHANISM_INVALID;
}
break;
}
return CKR_OK;
}
CK_RV ep11tok_is_mechanism_supported_ex(STDLL_TokData_t *tokdata,
CK_MECHANISM_PTR mech)
{
CK_RSA_PKCS_OAEP_PARAMS *params;
int status;
CK_RV rc;
rc = ep11tok_is_mechanism_supported(tokdata, mech->mechanism);
if (rc != CKR_OK)
return rc;
switch (mech->mechanism) {
case CKM_RSA_PKCS_OAEP:
if (mech->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS) ||
mech->pParameter == NULL)
return CKR_MECHANISM_PARAM_INVALID;
params = (CK_RSA_PKCS_OAEP_PARAMS *)mech->pParameter;
status = check_required_versions(tokdata, oaep_sha2_req_versions,
NUM_OAEP_SHA2_REQ);
if (status == 1)
return CKR_OK;
/*
* Not all APQNs have the required firmware level, restrict to SHA1
* for hashing algorithm and MGF.
*/
if (params->hashAlg == CKM_SHA_1 && params->mgf == CKG_MGF1_SHA1)
return CKR_OK;
TRACE_INFO("%s RSA-OAEP supports SHA1 only due to mixed firmware "
" versions\n", __func__);
return CKR_MECHANISM_PARAM_INVALID;
}
return CKR_OK;
}
CK_RV ep11tok_get_mechanism_info(STDLL_TokData_t * tokdata,
CK_MECHANISM_TYPE type,
CK_MECHANISM_INFO_PTR pInfo)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
int status;
rc = ep11tok_is_mechanism_supported(tokdata, type);
if (rc != CKR_OK) {
TRACE_DEBUG("%s rc=0x%lx unsupported '%s'\n", __func__, rc,
ep11_get_ckm(type));
return rc;
}
rc = dll_m_GetMechanismInfo(0, type, pInfo, ep11_data->target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s m_GetMechanismInfo(0x%lx) failed with rc=0x%lx\n",
__func__, type, rc);
return rc;
}
/* The card operates always in a FISP mode that requires stronger
* key sizes, but, in theory, can also operate with weaker key sizes.
* Customers are not interested in theory but in what mechanism
* they can use (mechanisms that are not rejected by the card).
*/
#ifdef DEFENSIVE_MECHLIST
switch (type) {
case CKM_RSA_PKCS:
case CKM_RSA_PKCS_KEY_PAIR_GEN:
case CKM_RSA_X9_31_KEY_PAIR_GEN:
case CKM_RSA_PKCS_PSS:
case CKM_RSA_PKCS_OAEP:
case CKM_SHA1_RSA_X9_31:
case CKM_SHA1_RSA_PKCS:
case CKM_SHA1_RSA_PKCS_PSS:
case CKM_SHA256_RSA_PKCS:
case CKM_SHA256_RSA_PKCS_PSS:
case CKM_SHA224_RSA_PKCS:
case CKM_SHA224_RSA_PKCS_PSS:
case CKM_SHA384_RSA_PKCS:
case CKM_SHA384_RSA_PKCS_PSS:
case CKM_SHA512_RSA_PKCS:
case CKM_SHA512_RSA_PKCS_PSS:
case CKM_RSA_X_509:
case CKM_RSA_X9_31:
/* EP11 card always in a FIPS mode rejecting
* lower key sizes
*/
pInfo->ulMinKeySize = 1024;
break;
case CKM_SHA_1_HMAC:
case CKM_SHA_1_HMAC_GENERAL:
case CKM_SHA224_HMAC:
case CKM_SHA224_HMAC_GENERAL:
case CKM_SHA256_HMAC:
case CKM_SHA256_HMAC_GENERAL:
case CKM_SHA384_HMAC:
case CKM_SHA384_HMAC_GENERAL:
case CKM_SHA512_HMAC:
case CKM_SHA512_HMAC_GENERAL:
case CKM_SHA512_224_HMAC:
case CKM_SHA512_224_HMAC_GENERAL:
case CKM_SHA512_256_HMAC:
case CKM_SHA512_256_HMAC_GENERAL:
case CKM_IBM_SHA3_224_HMAC:
case CKM_IBM_SHA3_256_HMAC:
case CKM_IBM_SHA3_384_HMAC:
case CKM_IBM_SHA3_512_HMAC:
/*
* Older levels of the EP11 firmware report ulMinKeySize in bytes,
* but ulMaxKeySize in bits for HMAC mechanisms. Adjust ulMinKeySize
* so that both are in bits, as required by the PKCS#11 standard.
* Newer levels of the EP11 firmware report both ulMinKeySize and
* ulMaxKeySize in bytes. Adjust both, so that both are in bits, as
* required by the PKCS#11 standard.
*/
status = check_required_versions(tokdata, hmac_req_versions,
NUM_HMAC_REQ);
if (status == -1)
return CKR_MECHANISM_INVALID;
pInfo->ulMinKeySize *= 8;
if (status == 1)
pInfo->ulMaxKeySize *= 8;
break;
case CKM_DES3_ECB:
case CKM_DES3_CBC:
case CKM_DES3_CBC_PAD:
/* EP11 card always in a FIPS mode rejecting
* lower key sizes < 80 bits.
*/
if (pInfo->ulMinKeySize == 8)
pInfo->ulMinKeySize = 16;
break;
default:
; /* do not touch */
}
#endif /* DEFENSIVE_MECHLIST */
return CKR_OK;
}
/* used for reading in the adapter config file,
* converts a 'token' to a number, returns 0 with success
*/
static inline short check_n(ep11_target_t * target, char *nptr, int *apqn_i)
{
int num;
if (sscanf(nptr, "%i", &num) != 1) {
TRACE_ERROR("%s invalid number '%s'\n", __func__, nptr);
return -1;
}
if (num < 0 || num > 255) {
TRACE_ERROR("%s invalid number '%s' %d\n", __func__, nptr, num);
return -1;
} else if (*apqn_i < 0 || *apqn_i >= MAX_APQN * 2) {
TRACE_ERROR("%s invalid amount of numbers %d\n", __func__, num);
return -1;
} else {
/* insert number into target variable */
target->apqns[*apqn_i] = (short) num;
/* how many APQNs numbers so far */
*apqn_i = *apqn_i + 1;
return 0;
}
}
static int read_adapter_config_file(STDLL_TokData_t * tokdata,
const char *conf_name)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
FILE *ap_fp = NULL; /* file pointer adapter config file */
int i, ap_file_size = 0; /* size adapter config file */
char *token, *str;
char filebuf[EP11_CFG_FILE_SIZE];
char line[1024];
int whitemode = 0;
int anymode = 0;
int apqn_i = 0; /* how many APQN numbers */
/* Since the ep11 token config contains the path to libica that
* will later be dlopen()ed, we cannot use a token config
* directory from an untrusted environment.
*/
char *conf_dir = secure_getenv("OCK_EP11_TOKEN_DIR");
char fname[PATH_MAX];
int rc = 0;
char *cfg_dir;
char cfgname[2*PATH_MAX + 1];
if (tokdata->initialized)
return 0;
memset(fname, 0, PATH_MAX);
/* via envrionment variable it is possible to overwrite the
* directory where the ep11 token config file is searched.
*/
if (conf_dir) {
if (conf_name && strlen(conf_name) > 0) {
/* extract filename part from conf_name */
for (i = strlen(conf_name) - 1; i >= 0 && conf_name[i] != '/'; i--);
snprintf(fname, sizeof(fname), "%s/%s", conf_dir,
conf_name + i + 1);
fname[sizeof(fname) - 1] = '\0';
ap_fp = fopen(fname, "r");
if (!ap_fp)
TRACE_DEVEL("%s fopen('%s') failed with errno %d\n",
__func__, fname, errno);
}
if (!ap_fp) {
snprintf(fname, sizeof(fname), "%s/%s", conf_dir,
EP11_DEFAULT_CFG_FILE);
fname[sizeof(fname) - 1] = '\0';
ap_fp = fopen(fname, "r");
if (!ap_fp)
TRACE_DEVEL("%s fopen('%s') failed with errno %d\n",
__func__, fname, errno);
}
} else {
if (conf_name && strlen(conf_name) > 0) {
strncpy(fname, conf_name, sizeof(fname) - 1);
fname[sizeof(fname) - 1] = '\0';
ap_fp = fopen(fname, "r");
if (!ap_fp) {
TRACE_DEVEL("%s fopen('%s') failed with errno %d\n",
__func__, fname, errno);
snprintf(fname, sizeof(fname), "%s/%s", OCK_CONFDIR, conf_name);
fname[sizeof(fname) - 1] = '\0';
ap_fp = fopen(fname, "r");
if (!ap_fp)
TRACE_DEVEL("%s fopen('%s') failed with errno %d\n",
__func__, fname, errno);
}
} else {
snprintf(fname, sizeof(fname), "%s/%s", OCK_CONFDIR,
EP11_DEFAULT_CFG_FILE);
fname[sizeof(fname) - 1] = '\0';
ap_fp = fopen(fname, "r");
if (!ap_fp)
TRACE_DEVEL("%s fopen('%s') failed with errno %d\n",
__func__, fname, errno);
}
}
/* now we should really have an open ep11 token config file */
if (!ap_fp) {
TRACE_ERROR("%s no valid EP 11 config file found\n", __func__);
OCK_SYSLOG(LOG_ERR, "%s: Error: EP 11 config file '%s' not found\n",
__func__, fname);
return APQN_FILE_INV;
}
TRACE_INFO("%s EP 11 token config file is '%s'\n", __func__, fname);
/* read config file line by line,
* ignore empty and # and copy rest into file buf
*/
memset(filebuf, 0, EP11_CFG_FILE_SIZE);
while (fgets((char *) line, sizeof(line), ap_fp)) {
char *p;
int len;
/* skip over leading spaces */
for (p = line; *p == ' ' || *p == '\t'; p++);
/* if line is empty or starts with # skip line */
len = strlen(p);
if (*p != '#' && *p != '\n' && len > 0) {
/* store line in buffer */
if (ap_file_size + len < EP11_CFG_FILE_SIZE) {
memcpy(filebuf + ap_file_size, p, len);
ap_file_size += len;
} else {
TRACE_ERROR("%s EP 11 config file '%s' is too large\n",
__func__, fname);
fclose(ap_fp);
OCK_SYSLOG(LOG_ERR,
"%s: Error: EP 11 config file '%s' is too large\n",
__func__, fname);
return APQN_FILE_INV_FILE_SIZE;
}
}
}
fclose(ap_fp);
ep11_data->target_list.length = 0;
/* Default to use default libica library for digests */
ep11_data->digest_libica = 1;
strcpy(ep11_data->digest_libica_path, "");
/* parse the file buf
* please note, we still accept the LOGLEVEL entry
* for compatibility reasons but just ignore it.
*/
for (i = 0, str = filebuf; rc == 0; str = NULL) {
/* strtok tokenizes the string,
* delimiters are newline and whitespace.
*/
token = strtok(str, "\n\t ");
if (i == 0) {
/* expecting APQN_WHITELIST or APQN_ANY or LOGLEVEL or eof */
if (token == NULL)
break;
if (strncmp(token, "APQN_WHITELIST", 14) == 0) {
whitemode = 1;
i = 1;
} else if (strncmp(token, "APQN_ANY", 8) == 0) {
anymode = 1;
i = 0;
} else if (strncmp(token, "LOGLEVEL", 8) == 0) {
i = 3;
} else if (strncmp(token, "FORCE_SENSITIVE", 15) == 0) {
i = 0;
ep11_data->cka_sensitive_default_true = 1;
} else if (strncmp(token, "CPFILTER", 8) == 0) {
i = 4;
} else if (strncmp(token, "STRICT_MODE", 11) == 0) {
i = 0;
ep11_data->strict_mode = 1;
} else if (strncmp(token, "VHSM_MODE", 11) == 0) {
i = 0;
ep11_data->vhsm_mode = 1;
} else if (strncmp(token, "OPTIMIZE_SINGLE_PART_OPERATIONS",
31) == 0) {
i = 0;
ep11_data->optimize_single_ops = 1;
} else if (strncmp(token, "DIGEST_LIBICA", 13) == 0) {
i = 5;
} else if (strncmp(token, "USE_PRANDOM", 11) == 0) {
i = 0;
token_specific.t_rng = NULL;
} else {
/* syntax error */
TRACE_ERROR("%s Expected APQN_WHITELIST,"
" APQN_ANY, LOGLEVEL, FORCE_SENSITIVE, CPFILTER,"
" STRICT_MODE, VHSM_MODE, "
" OPTIMIZE_SINGLE_PART_OPERATIONS, DIGEST_LIBICA, "
"or USE_PRANDOM keyword, found '%s' in config file "
"'%s'\n", __func__,
token, fname);
OCK_SYSLOG(LOG_ERR, "%s: Error: Expected APQN_WHITELIST,"
" APQN_ANY, LOGLEVEL, FORCE_SENSITIVE, CPFILTER,"
" STRICT_MODE, VHSM_MODE,"
" OPTIMIZE_SINGLE_PART_OPERATIONS, DIGEST_LIBICA, "
"or USE_PRANDOM keyword, found '%s' in config file "
"'%s'\n",
__func__, token, fname);
rc = APQN_FILE_SYNTAX_ERROR_0;
break;
}
} else if (i == 1) {
/* expecting END or first number of a number
* pair (number range 0...255)
*/
if (token == NULL) {
rc = APQN_FILE_UNEXPECTED_END_OF_FILE;
OCK_SYSLOG(LOG_ERR, "%s: Error: Unexpected end of file found"
" in config file '%s', expected 'END' or adapter"
" number\n",
__func__, fname);
break;
}
if (strncmp(token, "END", 3) == 0) {
i = 0;
} else {
if (check_n(&ep11_data->target_list, token, &apqn_i) < 0) {
rc = APQN_FILE_SYNTAX_ERROR_1;
OCK_SYSLOG(LOG_ERR, "%s: Error: Expected valid adapter"
" number, found '%s' in config file '%s'\n",
__func__, token, fname);
break;
}
i = 2;
}
} else if (i == 2) {
/* expecting second number of a number pair
* (number range 0...255)
*/
if (token == NULL) {
rc = APQN_FILE_UNEXPECTED_END_OF_FILE;
OCK_SYSLOG(LOG_ERR, "%s: Error: Unexpected end of file found"
" in config file '%s', expected domain number"
" (2nd number)\n", __func__, fname);
break;
}
if (strncmp(token, "END", 3) == 0) {
TRACE_ERROR("%s Expected 2nd number, found '%s' in config "
"file\n", __func__, token);
OCK_SYSLOG(LOG_ERR,
"%s: Error: Expected valid domain"
" number (2nd number), found '%s' in config file"
" '%s'\n", __func__, token, fname);
rc = APQN_FILE_SYNTAX_ERROR_2;
break;
}
if (check_n(&ep11_data->target_list, token, &apqn_i) < 0) {
OCK_SYSLOG(LOG_ERR, "%s: Error: Expected valid domain"
" number (2nd number), found '%s' in config file"
" '%s'\n", __func__, token, fname);
rc = APQN_FILE_SYNTAX_ERROR_3;
break;
}
ep11_data->target_list.length++;
if (ep11_data->target_list.length > MAX_APQN) {
TRACE_ERROR("%s Too many APQNs in config file (max %d)\n",
__func__, (int) MAX_APQN);
OCK_SYSLOG(LOG_ERR,
"%s: Error: Too many APQNs in config file '%s'\n",
__func__, fname);
rc = APQN_FILE_SYNTAX_ERROR_4;
break;
}
i = 1;
} else if (i == 3) {
/* expecting log level value
* (a number in the range 0...9)
*/
if (token == NULL) {
rc = APQN_FILE_UNEXPECTED_END_OF_FILE;
OCK_SYSLOG(LOG_ERR, "%s: Error: Unexpected end of file found"
" in config file '%s', expected LOGLEVEL value\n",
__func__, fname);
break;
}
char *endptr;
int loglevel = strtol(token, &endptr, 10);
if (*endptr != '\0' || loglevel < 0 || loglevel > 9) {
TRACE_ERROR("%s Invalid loglevel value '%s' in config file\n",
__func__, token);
OCK_SYSLOG(LOG_ERR,
"%s: Error: Invalid LOGLEVEL value '%s' in config "
"file '%s'\n",
__func__, token, fname);
rc = APQN_FILE_SYNTAX_ERROR_5;
break;
}
TRACE_WARNING("%s LOGLEVEL setting is not supported any more !\n",
__func__);
TRACE_WARNING
("%s Use opencryptoki logging/tracing facilities instead.\n",
__func__);
OCK_SYSLOG(LOG_WARNING,
"%s: Warning: LOGLEVEL setting is not supported any "
"more. Use opencryptoki logging/tracing facilities "
"instead.\n", __func__);
i = 0;
} else if (i == 4) {
/* expecting CP-filter config file name */
if (token == NULL) {
rc = APQN_FILE_UNEXPECTED_END_OF_FILE;
OCK_SYSLOG(LOG_ERR, "%s: Error: Unexpected end of file found"
" in config file '%s', expected CP-Filter file "
"name\n", __func__, fname);
break;
}
if (strlen(token) >
sizeof(ep11_data->cp_filter_config_filename) - 1) {
TRACE_ERROR("%s CP-Filter config file name is too long: '%s'\n",
__func__, token);
OCK_SYSLOG(LOG_ERR,
"%s: Error: CP-Filter config file name '%s' is too "
"long in config file '%s'\n",
__func__, token, fname);
rc = APQN_FILE_SYNTAX_ERROR_6;
break;
}
strncpy(ep11_data->cp_filter_config_filename, token,
sizeof(ep11_data->cp_filter_config_filename) - 1);
ep11_data->cp_filter_config_filename[
sizeof(ep11_data->cp_filter_config_filename) - 1] = '\0';
i = 0;
} else if (i == 5) {
/* expecting libica path, 'DEFAULT', or 'OFF' */
if (token == NULL) {
rc = APQN_FILE_UNEXPECTED_END_OF_FILE;
OCK_SYSLOG(LOG_ERR,"%s: Error: Unexpected end of file found"
" in config file '%s', expected libica path, "
"'DEFAULT', or 'OFF'\n",
__func__, fname);
break;
}
if (strcmp(token, "OFF") == 0) {
ep11_data->digest_libica = 0;
} else if (strcmp(token, "DEFAULT") == 0) {
ep11_data->digest_libica = 1;
strcpy(ep11_data->digest_libica_path, "");
} else {
if (strlen(token) > sizeof(ep11_data->digest_libica_path)-1) {
TRACE_ERROR("%s libica path is too long: '%s'\n",
__func__, token);
OCK_SYSLOG(LOG_ERR,"%s: Error: libica path '%s' is too long"
" in config file '%s'\n",
__func__, token, fname);
rc = APQN_FILE_SYNTAX_ERROR_6;
break;
}
ep11_data->digest_libica = 1;
strncpy(ep11_data->digest_libica_path, token,
sizeof(ep11_data->digest_libica_path)-1);
ep11_data->digest_libica_path[sizeof(ep11_data->digest_libica_path)-1] = '\0';
}
i = 0;
}
}
/* do some checks: */
if (rc == 0) {
if (!(whitemode || anymode)) {
TRACE_ERROR("%s At least one APQN mode needs to be present in "
"config file: APQN_WHITEMODE or APQN_ANY\n", __func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: At least one APQN mode needs to be present "
" in config file '%s': APQN_WHITEMODE or APQN_ANY\n",
__func__, fname);
rc = APQN_FILE_NO_APQN_MODE;
} else if (whitemode && anymode) {
TRACE_ERROR("%s Only one APQN mode can be present in config file:"
" APQN_WHITEMODE or APQN_ANY\n", __func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: Only one APQN mode can be present in"
" config file '%s': APQN_WHITEMODE or APQN_ANY\n",
__func__, fname);
rc = APQN_FILE_NO_APQN_MODE;
} else if (whitemode) {
/* at least one APQN needs to be defined */
if (ep11_data->target_list.length < 1) {
TRACE_ERROR("%s At least one APQN needs to be defined in the "
"config file\n", __func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: At least one APQN needs to be defined in"
" config file '%s'\n", __func__, fname);
rc = APQN_FILE_NO_APQN_GIVEN;
}
}
}
/* log the whitelist of APQNs */
if (rc == 0 && whitemode) {
TRACE_INFO("%s whitelist with %d APQNs defined:\n",
__func__, ep11_data->target_list.length);
for (i = 0; i < ep11_data->target_list.length; i++) {
TRACE_INFO(" APQN entry %d: adapter=%d domain=%d\n", i,
ep11_data->target_list.apqns[2 * i],
ep11_data->target_list.apqns[2 * i + 1]);
}
}
/* read CP-filter config file */
if (rc == 0) {
cfg_dir = dirname(fname);
if (strlen(ep11_data->cp_filter_config_filename) == 0) {
snprintf(ep11_data->cp_filter_config_filename,
sizeof(ep11_data->cp_filter_config_filename) - 1,
"%s/%s", cfg_dir, EP11_DEFAULT_CPFILTER_FILE);
ep11_data->cp_filter_config_filename[
sizeof(ep11_data->cp_filter_config_filename) - 1] = '\0';
}
if (strchr(ep11_data->cp_filter_config_filename, '/') == NULL) {
cfgname[0] = '\0';
if (strlen(cfg_dir) + 1
+ strlen(ep11_data->cp_filter_config_filename)
<= sizeof(cfgname) - 1) {
strcpy(cfgname, cfg_dir);
cfgname[strlen(cfg_dir)] = '/';
strcpy(cfgname + strlen(cfg_dir) + 1,
ep11_data->cp_filter_config_filename);
}
if (strlen(cfgname) < sizeof(ep11_data->cp_filter_config_filename))
strcpy(ep11_data->cp_filter_config_filename, cfgname);
ep11_data->cp_filter_config_filename[
sizeof(ep11_data->cp_filter_config_filename) - 1] = '\0';
}
rc = read_cp_filter_config_file(ep11_data->cp_filter_config_filename,
&ep11_data->cp_config);
}
tokdata->initialized = TRUE;
return rc;
}
#define UNKNOWN_CP 0xFFFFFFFF
#define CP_BYTE_NO(cp) ((cp) / 8)
#define CP_BIT_IN_BYTE(cp) ((cp) % 8)
#define CP_BIT_MASK(cp) (0x80 >> CP_BIT_IN_BYTE(cp))
static int read_cp_filter_config_file(const char *conf_name,
cp_config_t ** cp_config)
{
int rc = 0;
FILE *fp = NULL;
char line[1024];
char *tok;
unsigned long int val;
char *endp;
cp_config_t *cp;
cp_config_t *last_cp = NULL;
cp_mech_config_t *mech;
cp_mech_config_t *last_mech;
TRACE_INFO("%s EP 11 CP-filter config file is '%s'\n", __func__, conf_name);
fp = fopen(conf_name, "r");
if (fp == NULL) {
TRACE_ERROR("%s no valid EP 11 CP-filter config file found\n",
__func__);
OCK_SYSLOG(LOG_WARNING,
"%s: Warning: EP 11 CP-filter config file '%s'"
" does not exist, no filtering will be used\n", __func__,
conf_name);
/* this is not an error condition. When no CP-filter file is available,
* then the mechanisms are not filtered. */
return 0;
}
while (fgets((char *) line, sizeof(line), fp)) {
tok = strtok(line, ": \t\n");
if (tok == NULL)
continue;
if (*tok == '#')
continue;
val = strtoul(tok, &endp, 0);
if (*endp != '\0') {
val = ep11_get_cp_by_name(tok);
if (val == UNKNOWN_CP) {
TRACE_ERROR("%s Syntax error in EP 11 CP-filter config file "
"found. \n", __func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: Expected valid control point name or "
"number, found '%s' in CP-filter config file '%s'\n",
__func__, tok, conf_name);
rc = APQN_FILE_SYNTAX_ERROR_7;
goto out_fclose;
}
}
cp = (cp_config_t *) malloc(sizeof(cp_config_t));
if (cp == NULL) {
TRACE_ERROR("%s Out of memory.\n", __func__);
rc = APQN_OUT_OF_MEMORY;
goto out_fclose;
}
cp->cp = val;
cp->mech = NULL;
cp->next = NULL;
last_mech = NULL;
while ((tok = strtok(NULL, ", \t\n")) != NULL) {
if (*tok == '#')
break;
val = strtoul(tok, &endp, 0);
if (*endp != '\0') {
val = ep11_get_mechanisms_by_name(tok);
if (val == UNKNOWN_MECHANISM) {
TRACE_ERROR("%s Syntax error in EP 11 CP-filter config file"
" found. \n", __func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: Expected valid mechanism name or "
"number, found '%s' in CP-filter config file "
"'%s'\n", __func__, tok, conf_name);
rc = APQN_FILE_SYNTAX_ERROR_8;
free_cp_config(cp);
goto out_fclose;
}
}
mech = (cp_mech_config_t *) malloc(sizeof(cp_mech_config_t));
if (mech == NULL) {
TRACE_ERROR("%s Out of memory.\n", __func__);
OCK_SYSLOG(LOG_ERR, "%s: Error: Out of memory while parsing the"
" CP-filter config file '%s'\n",
__func__, conf_name);
rc = APQN_OUT_OF_MEMORY;
free_cp_config(cp);
goto out_fclose;
}
mech->mech = val;
mech->next = NULL;
if (last_mech == NULL)
cp->mech = mech;
else
last_mech->next = mech;
last_mech = mech;
}
if (cp->mech == NULL) {
/* empty CP, skip this one */
free(cp);
continue;
}
if (last_cp == NULL)
*cp_config = cp;
else
last_cp->next = cp;
last_cp = cp;
}
#ifdef DEBUG
/* print CP filter config */
TRACE_INFO("%s CP-Filter defined:\n", __func__);
cp = *cp_config;
while (cp != NULL) {
TRACE_INFO(" CP %lu (%s):\n", cp->cp, ep11_get_cp(cp->cp));
mech = cp->mech;
while (mech != NULL) {
TRACE_INFO(" Mechanism 0x%08lx (%s)\n", mech->mech,
ep11_get_ckm(mech->mech));
mech = mech->next;
}
cp = cp->next;
}
#endif
out_fclose:
fclose(fp);
return rc;
}
static void free_cp_config(cp_config_t * cp)
{
cp_config_t *next_cp = cp;
cp_mech_config_t *mech;
cp_mech_config_t *next_mech;
TRACE_INFO("%s running\n", __func__);
while (cp != NULL) {
mech = cp->mech;
while (mech != NULL) {
next_mech = mech->next;
free(mech);
mech = next_mech;
}
next_cp = cp->next;
free(cp);
cp = next_cp;
}
}
static const_info_t ep11_cps[] = {
CONSTINFO(XCP_CPB_ADD_CPBS),
CONSTINFO(XCP_CPB_DELETE_CPBS),
CONSTINFO(XCP_CPB_SIGN_ASYMM),
CONSTINFO(XCP_CPB_SIGN_SYMM),
CONSTINFO(XCP_CPB_SIGVERIFY_SYMM),
CONSTINFO(XCP_CPB_ENCRYPT_SYMM),
CONSTINFO(XCP_CPB_DECRYPT_ASYMM),
CONSTINFO(XCP_CPB_DECRYPT_SYMM),
CONSTINFO(XCP_CPB_WRAP_ASYMM),
CONSTINFO(XCP_CPB_WRAP_SYMM),
CONSTINFO(XCP_CPB_UNWRAP_ASYMM),
CONSTINFO(XCP_CPB_UNWRAP_SYMM),
CONSTINFO(XCP_CPB_KEYGEN_ASYMM),
CONSTINFO(XCP_CPB_KEYGEN_SYMM),
CONSTINFO(XCP_CPB_RETAINKEYS),
CONSTINFO(XCP_CPB_SKIP_KEYTESTS),
CONSTINFO(XCP_CPB_NON_ATTRBOUND),
CONSTINFO(XCP_CPB_MODIFY_OBJECTS),
CONSTINFO(XCP_CPB_RNG_SEED),
CONSTINFO(XCP_CPB_ALG_RAW_RSA),
CONSTINFO(XCP_CPB_ALG_NFIPS2009),
CONSTINFO(XCP_CPB_ALG_NBSI2009),
CONSTINFO(XCP_CPB_KEYSZ_HMAC_ANY),
CONSTINFO(XCP_CPB_KEYSZ_BELOW80BIT),
CONSTINFO(XCP_CPB_KEYSZ_80BIT),
CONSTINFO(XCP_CPB_KEYSZ_112BIT),
CONSTINFO(XCP_CPB_KEYSZ_128BIT),
CONSTINFO(XCP_CPB_KEYSZ_192BIT),
CONSTINFO(XCP_CPB_KEYSZ_256BIT),
CONSTINFO(XCP_CPB_KEYSZ_RSA65536),
CONSTINFO(XCP_CPB_ALG_RSA),
CONSTINFO(XCP_CPB_ALG_DSA),
CONSTINFO(XCP_CPB_ALG_EC),
CONSTINFO(XCP_CPB_ALG_EC_BPOOLCRV),
CONSTINFO(XCP_CPB_ALG_EC_NISTCRV),
CONSTINFO(XCP_CPB_ALG_NFIPS2011),
CONSTINFO(XCP_CPB_ALG_NBSI2011),
CONSTINFO(XCP_CPB_USER_SET_TRUSTED),
CONSTINFO(XCP_CPB_ALG_SKIP_CROSSCHK),
CONSTINFO(XCP_CPB_WRAP_CRYPT_KEYS),
CONSTINFO(XCP_CPB_SIGN_CRYPT_KEYS),
CONSTINFO(XCP_CPB_WRAP_SIGN_KEYS),
CONSTINFO(XCP_CPB_USER_SET_ATTRBOUND),
CONSTINFO(XCP_CPB_ALLOW_PASSPHRASE),
CONSTINFO(XCP_CPB_WRAP_STRONGER_KEY),
CONSTINFO(XCP_CPB_WRAP_WITH_RAW_SPKI),
CONSTINFO(XCP_CPB_ALG_DH),
CONSTINFO(XCP_CPB_DERIVE),
CONSTINFO(XCP_CPB_ALG_EC_25519),
CONSTINFO(XCP_CPB_ALG_NBSI2017),
CONSTINFO(XCP_CPB_CPACF_PK),
CONSTINFO(XCP_CPB_ALG_PQC_DILITHIUM),
};
#ifdef DEBUG
static const char *ep11_get_cp(unsigned int cp)
{
unsigned int i;
for (i = 0; i < (sizeof(ep11_cps) / sizeof(ep11_cps[0])); i++) {
if (ep11_cps[i].code == cp)
return ep11_cps[i].name;
}
TRACE_WARNING("%s unknown control point %u\n", __func__, cp);
return "UNKNOWN";
}
#endif
static CK_ULONG ep11_get_cp_by_name(const char *name)
{
unsigned int i;
for (i = 0; i < (sizeof(ep11_cps) / sizeof(ep11_cps[0])); i++) {
if (strcmp(ep11_cps[i].name, name) == 0)
return ep11_cps[i].code;
}
TRACE_WARNING("%s unknown control point name '%s'\n", __func__, name);
return UNKNOWN_CP;
}
static CK_RV check_cps_for_mechanism(cp_config_t * cp_config,
CK_MECHANISM_TYPE mech,
unsigned char *cp, size_t cp_len,
size_t max_cp_index)
{
cp_config_t *cp_cfg = cp_config;
cp_mech_config_t *mech_cfg;
TRACE_DEBUG("%s Check mechanism 0x%08lx ('%s')\n", __func__, mech,
ep11_get_ckm(mech));
while (cp_cfg != NULL) {
if (CP_BYTE_NO(cp_cfg->cp) < cp_len &&
cp_cfg->cp <= max_cp_index &&
(cp[CP_BYTE_NO(cp_cfg->cp)] & CP_BIT_MASK(cp_cfg->cp)) == 0) {
/* CP is off, check if the current mechanism is
* associated with it */
mech_cfg = cp_cfg->mech;
while (mech_cfg != NULL) {
if (mech_cfg->mech == mech) {
TRACE_DEBUG("%s mechanism 0x%08lx ('%s') not enabled\n",
__func__, mech, ep11_get_ckm(mech));
return CKR_MECHANISM_INVALID;
}
mech_cfg = mech_cfg->next;
}
}
cp_cfg = cp_cfg->next;
}
return CKR_OK;
}
#define SYSFS_DEVICES_AP "/sys/devices/ap/"
#define REGEX_CARD_PATTERN "card[0-9a-fA-F]+"
#define REGEX_SUB_CARD_PATTERN "[0-9a-fA-F]+\\.[0-9a-fA-F]+"
#define MASK_EP11 0x04000000
typedef CK_RV(*adapter_handler_t) (uint_32 adapter, uint_32 domain,
void *handler_data);
static CK_RV file_fgets(const char *fname, char *buf, size_t buflen)
{
FILE *fp;
char *end;
CK_RV rc = CKR_OK;
buf[0] = '\0';
fp = fopen(fname, "r");
if (fp == NULL) {
TRACE_ERROR("Failed to open file '%s'\n", fname);
return CKR_FUNCTION_FAILED;
}
if (fgets(buf, buflen, fp) == NULL) {
TRACE_ERROR("Failed to read from file '%s'\n", fname);
rc = CKR_FUNCTION_FAILED;
goto out_fclose;
}
end = memchr(buf, '\n', buflen);
if (end)
*end = 0;
else
buf[buflen - 1] = 0;
if (strlen(buf) == 0) {
rc = CKR_FUNCTION_FAILED;
goto out_fclose;
}
out_fclose:
fclose(fp);
return rc;
}
static CK_RV is_card_ep11_and_online(const char *name)
{
char fname[290];
char buf[250];
CK_RV rc;
unsigned long val;
#ifdef EP11_HSMSIM
return CKR_OK;
#endif
sprintf(fname, "%s%s/online", SYSFS_DEVICES_AP, name);
rc = file_fgets(fname, buf, sizeof(buf));
if (rc != CKR_OK)
return rc;
if (strcmp(buf, "1") != 0)
return CKR_FUNCTION_FAILED;
sprintf(fname, "%s%s/ap_functions", SYSFS_DEVICES_AP, name);
rc = file_fgets(fname, buf, sizeof(buf));
if (rc != CKR_OK)
return rc;
if (sscanf(buf, "%lx", &val) != 1)
val = 0x00000000;
if ((val & MASK_EP11) == 0)
return CKR_FUNCTION_FAILED;
return CKR_OK;
}
static CK_RV scan_for_card_domains(const char *name, adapter_handler_t handler,
void *handler_data)
{
char fname[290];
regex_t reg_buf;
regmatch_t pmatch[1];
DIR *d;
struct dirent *de;
char *tok;
uint_32 adapter, domain;
#ifdef EP11_HSMSIM
return handler(0, 0, handler_data);
#endif
if (regcomp(®_buf, REGEX_SUB_CARD_PATTERN, REG_EXTENDED) != 0) {
TRACE_ERROR("Failed to compile regular expression '%s'\n",
REGEX_SUB_CARD_PATTERN);
return CKR_FUNCTION_FAILED;
}
sprintf(fname, "%s%s/", SYSFS_DEVICES_AP, name);
d = opendir(fname);
if (d == NULL) {
TRACE_ERROR("Directory %s is not available\n", fname);
regfree(®_buf);
// ignore this error, card may have been removed in the meantime
return CKR_OK;
}
while ((de = readdir(d)) != NULL) {
if (regexec(®_buf, de->d_name, (size_t) 1, pmatch, 0) == 0) {
tok = strtok(de->d_name, ".");
if (tok == NULL)
continue;
if (sscanf(tok, "%x", &adapter) != 1)
continue;
tok = strtok(NULL, ",");
if (tok == NULL)
continue;
if (sscanf(tok, "%x", &domain) != 1)
continue;
if (handler(adapter, domain, handler_data) != CKR_OK)
break;
}
}
closedir(d);
regfree(®_buf);
return CKR_OK;
}
/*
* Iterate over all cards in the sysfs directorys /sys/device/ap/cardxxx
* and check if the card is online. Calls the handler function for all
* online EP11 cards.
*/
static CK_RV scan_for_ep11_cards(adapter_handler_t handler, void *handler_data)
{
DIR *d;
struct dirent *de;
regex_t reg_buf;
regmatch_t pmatch[1];
if (handler == NULL)
return CKR_ARGUMENTS_BAD;
#ifdef EP11_HSMSIM
return handler(0, 0, handler_data);
#endif
if (regcomp(®_buf, REGEX_CARD_PATTERN, REG_EXTENDED) != 0) {
TRACE_ERROR("Failed to compile regular expression '%s'\n",
REGEX_CARD_PATTERN);
return CKR_FUNCTION_FAILED;
}
d = opendir(SYSFS_DEVICES_AP);
if (d == NULL) {
TRACE_ERROR("Directory %s is not available\n", SYSFS_DEVICES_AP);
regfree(®_buf);
return CKR_FUNCTION_FAILED;
}
while ((de = readdir(d)) != NULL) {
if (regexec(®_buf, de->d_name, (size_t) 1, pmatch, 0) == 0) {
if (is_card_ep11_and_online(de->d_name) != CKR_OK)
continue;
if (scan_for_card_domains(de->d_name, handler, handler_data) !=
CKR_OK)
break;
}
}
closedir(d);
regfree(®_buf);
return CKR_OK;
}
static CK_RV handle_all_ep11_cards(ep11_target_t * ep11_targets,
adapter_handler_t handler,
void *handler_data)
{
int i;
CK_RV rc;
if (ep11_targets->length > 0) {
/* APQN_WHITELIST is specified */
for (i = 0; i < ep11_targets->length; i++) {
rc = handler(ep11_targets->apqns[2 * i],
ep11_targets->apqns[2 * i + 1], handler_data);
if (rc != CKR_OK)
return rc;
}
} else {
/* APQN_ANY used, scan sysfs for available cards */
return scan_for_ep11_cards(handler, handler_data);
}
return CKR_OK;
}
static CK_RV get_control_points_for_adapter(uint_32 adapter, uint_32 domain,
unsigned char *cp, size_t * cp_len,
size_t *max_cp_index)
{
unsigned char rsp[200];
unsigned char cmd[100];
struct XCPadmresp rb;
size_t rlen, clen;
long rc;
CK_RV rv = 0;
target_t target;
CK_IBM_XCP_INFO xcp_info;
CK_ULONG xcp_info_len = sizeof(xcp_info);
rc = get_ep11_target_for_apqn(adapter, domain, &target);
if (rc != CKR_OK)
return rc;
memset(cmd, 0, sizeof(cmd));
rc = dll_xcpa_queryblock(cmd, sizeof(cmd), XCP_ADMQ_DOM_CTRLPOINTS,
(uint64_t) adapter << 32 | domain, NULL, 0);
if (rc < 0) {
TRACE_ERROR("%s xcpa_queryblock failed: rc=%ld\n", __func__, rc);
rc = CKR_DEVICE_ERROR;
goto out;
}
clen = rc;
memset(rsp, 0, sizeof(rsp));
rlen = sizeof(rsp);
rc = dll_m_admin(rsp, &rlen, NULL, NULL, cmd, clen, NULL, 0, target);
if (rc < 0) {
TRACE_ERROR("%s m_admin rc=%ld\n", __func__, rc);
rc = CKR_DEVICE_ERROR;
goto out;
}
memset(&rb, 0, sizeof(rb));
rc = dll_xcpa_internal_rv(rsp, rlen, &rb, &rv);
if (rc < 0 || rv != 0) {
TRACE_ERROR("%s xcpa_internal_rv failed: rc=%ld rv=%ld\n",
__func__, rc, rv);
rc = CKR_DEVICE_ERROR;
goto out;
}
if (*cp_len < rb.pllen) {
TRACE_ERROR("%s Cp_len is too small. cp_len=%lu required=%lu\n",
__func__, *cp_len, rb.pllen);
*cp_len = rb.pllen;
rc = CKR_ARGUMENTS_BAD;
goto out;
}
memcpy(cp, rb.payload, rb.pllen);
*cp_len = rb.pllen;
rc = dll_m_get_xcp_info(&xcp_info, &xcp_info_len, CK_IBM_XCPQ_MODULE, 0,
target);
if (rc != CKR_OK) {
TRACE_ERROR("%s Failed to query xcp info from adapter %02X.%04X\n",
__func__, adapter, domain);
rc = CKR_DEVICE_ERROR;
goto out;
}
*max_cp_index = xcp_info.controlPoints;
out:
free_ep11_target_for_apqn(target);
return rc;
}
typedef struct cp_handler_data {
unsigned char combined_cp[XCP_CP_BYTES];
unsigned char first_cp[XCP_CP_BYTES];
uint32_t first_adapter;
uint32_t first_domain;
int first;
size_t max_cp_index;
} cp_handler_data_t;
static CK_RV control_point_handler(uint_32 adapter, uint_32 domain,
void *handler_data)
{
CK_RV rc;
cp_handler_data_t *data = (cp_handler_data_t *) handler_data;
unsigned char cp[XCP_CP_BYTES];
size_t cp_len = sizeof(cp);
size_t max_cp_index;
CK_ULONG i;
TRACE_INFO("Getting control points for adapter %02X.%04X\n", adapter,
domain);
memset(cp, 0, sizeof(cp));
rc = get_control_points_for_adapter(adapter, domain, cp, &cp_len,
&max_cp_index);
if (rc != CKR_OK) {
TRACE_ERROR("%s Failed to get CPS from adapter %02X.%04X\n",
__func__, adapter, domain);
// card may no longer be online, so ignore this error situation
return CKR_OK;
}
#ifdef DEBUG
TRACE_DEBUG("Control points from adapter %02X.%04X\n", adapter, domain);
TRACE_DEBUG_DUMP(cp, cp_len);
#endif
if (data->first) {
data->first_adapter = adapter;
data->first_domain = domain;
memcpy(data->first_cp, cp, cp_len);
memcpy(data->combined_cp, cp, cp_len);
data->max_cp_index = max_cp_index;
data->first = 0;
} else {
// check if subsequent adapters have the same CPs
if (memcmp(cp, data->first_cp, sizeof(cp)) != 0) {
TRACE_WARNING("%s Adapter %02X.%04X has different control points "
"than adapter %02X.%04X, using minimum.\n",
__func__, adapter, domain, data->first_adapter,
data->first_domain);
OCK_SYSLOG(LOG_WARNING,
"Warning: Adapter %02X.%04X has different control points"
" than adapter %02X.%04X, using minimum\n",
adapter, domain, data->first_adapter,
data->first_domain);
}
for (i = 0; i < cp_len; i++) {
data->combined_cp[i] &= cp[i];
}
if (max_cp_index != data->max_cp_index) {
TRACE_WARNING("%s Adapter %02X.%04X has a different number of "
"control points than adapter %02X.%04X, using "
"maximum.\n", __func__, adapter, domain,
data->first_adapter, data->first_domain);
OCK_SYSLOG(LOG_WARNING,
"Warning: Adapter %02X.%04X has a different number of "
"control points than adapter %02X.%04X, using maximum\n",
adapter, domain, data->first_adapter,
data->first_domain);
data->max_cp_index = MAX(max_cp_index, data->max_cp_index);
}
}
return CKR_OK;
}
#ifdef DEBUG
static void print_control_points(unsigned char *cp, size_t cp_len,
size_t max_cp_index)
{
unsigned int i;
for (i = 0; i <= max_cp_index && CP_BYTE_NO(i) < cp_len; i++) {
if ((cp[CP_BYTE_NO(i)] & CP_BIT_MASK(i)) == 0)
TRACE_INFO("CP %u (%s)is off\n", i, ep11_get_cp(i));
else
TRACE_INFO("CP %u (%s) is on\n", i, ep11_get_cp(i));
}
}
#endif
static CK_RV get_control_points(STDLL_TokData_t * tokdata,
unsigned char *cp, size_t * cp_len,
size_t *max_cp_index)
{
CK_RV rc;
cp_handler_data_t data;
ep11_private_data_t *ep11_data = tokdata->private_data;
memset(&data, 0, sizeof(data));
data.first = 1;
rc = handle_all_ep11_cards(&ep11_data->target_list, control_point_handler,
&data);
if (rc != CKR_OK)
return rc;
*cp_len = MIN(*cp_len, sizeof(data.combined_cp));
memcpy(cp, data.combined_cp, *cp_len);
*max_cp_index = data.max_cp_index;
#ifdef DEBUG
TRACE_DEBUG("Combined control points from all cards (%lu CPs):\n",
data.max_cp_index);
TRACE_DEBUG_DUMP(cp, *cp_len);
print_control_points(cp, *cp_len, data.max_cp_index);
#endif
return CKR_OK;
}
CK_RV SC_CreateObject(STDLL_TokData_t * tokdata,
ST_SESSION_HANDLE * sSession, CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject);
CK_RV SC_DestroyObject(STDLL_TokData_t * tokdata,
ST_SESSION_HANDLE * sSession, CK_OBJECT_HANDLE hObject);
CK_RV SC_FindObjectsInit(STDLL_TokData_t * tokdata,
ST_SESSION_HANDLE * sSession,
CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount);
CK_RV SC_FindObjects(STDLL_TokData_t * tokdata,
ST_SESSION_HANDLE * sSession,
CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount,
CK_ULONG_PTR pulObjectCount);
CK_RV SC_FindObjectsFinal(STDLL_TokData_t * tokdata,
ST_SESSION_HANDLE * sSession);
CK_RV SC_GetAttributeValue(STDLL_TokData_t * tokdata,
ST_SESSION_HANDLE * sSession,
CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount);
CK_RV SC_OpenSession(STDLL_TokData_t * tokdata, CK_SLOT_ID sid, CK_FLAGS flags,
CK_SESSION_HANDLE_PTR phSession);
CK_RV SC_CloseSession(STDLL_TokData_t * tokdata, ST_SESSION_HANDLE * sSession);
static CK_RV generate_ep11_session_id(STDLL_TokData_t * tokdata,
SESSION * session,
ep11_session_t * ep11_session)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
struct {
CK_SESSION_HANDLE handle;
struct timeval timeofday;
clock_t clock;
pid_t pid;
} session_id_data;
CK_MECHANISM mech;
CK_ULONG len;
libica_sha_context_t ctx;
session_id_data.handle = session->handle;
gettimeofday(&session_id_data.timeofday, NULL);
session_id_data.clock = clock();
session_id_data.pid = getpid();
mech.mechanism = CKM_SHA256;
mech.pParameter = NULL;
mech.ulParameterLen = 0;
len = sizeof(ep11_session->session_id);
if (ep11tok_libica_digest_available(ep11_data, mech.mechanism))
rc = ep11tok_libica_digest(ep11_data, mech.mechanism, &ctx,
(CK_BYTE_PTR)&session_id_data,
sizeof(session_id_data),
ep11_session->session_id, &len,
SHA_MSG_PART_ONLY);
else
rc = dll_m_DigestSingle(&mech, (CK_BYTE_PTR)&session_id_data,
sizeof(session_id_data),
ep11_session->session_id, &len,
ep11_data->target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, session);
TRACE_ERROR("%s Digest failed: 0x%lx\n", __func__, rc);
return rc;
}
return CKR_OK;
}
static CK_RV create_ep11_object(STDLL_TokData_t * tokdata,
ST_SESSION_HANDLE * handle,
ep11_session_t * ep11_session,
CK_BYTE * pin_blob, CK_ULONG pin_blob_len,
CK_OBJECT_HANDLE * obj)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_RV rc;
CK_OBJECT_CLASS class = CKO_HW_FEATURE;
CK_HW_FEATURE_TYPE type = CKH_IBM_EP11_SESSION;
CK_BYTE subject[] = "EP11 Session Object";
pid_t pid;
CK_DATE date;
CK_BYTE cktrue = TRUE;
time_t t;
struct tm *tm;
char tmp[40];
CK_ATTRIBUTE attrs[] = {
{CKA_CLASS, &class, sizeof(class)}
,
{CKA_TOKEN, &cktrue, sizeof(cktrue)}
,
{CKA_PRIVATE, &cktrue, sizeof(cktrue)}
,
{CKA_HIDDEN, &cktrue, sizeof(cktrue)}
,
{CKA_HW_FEATURE_TYPE, &type, sizeof(type)}
,
{CKA_SUBJECT, &subject, sizeof(subject)}
,
{CKA_VALUE, pin_blob, pin_blob_len}
,
{CKA_ID, ep11_session->session_id, PUBLIC_SESSION_ID_LENGTH}
,
{CKA_APPLICATION, &ep11_data->target_list, sizeof(ep11_target_t)}
,
{CKA_OWNER, &pid, sizeof(pid)}
,
{CKA_START_DATE, &date, sizeof(date)}
};
pid = getpid();
time(&t);
tm = localtime(&t);
sprintf(tmp, "%4d%2d%2d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
memcpy(date.year, tmp, 4);
memcpy(date.month, tmp + 4, 2);
memcpy(date.day, tmp + 4 + 2, 2);
rc = SC_CreateObject(tokdata, handle,
attrs, sizeof(attrs) / sizeof(CK_ATTRIBUTE), obj);
if (rc != CKR_OK) {
TRACE_ERROR("%s SC_CreateObject failed: 0x%lx\n", __func__, rc);
return rc;
}
return CKR_OK;
}
static CK_RV get_vhsmpin(STDLL_TokData_t * tokdata,
SESSION * session, ep11_session_t * ep11_session)
{
CK_RV rc;
ST_SESSION_HANDLE handle = {.slotID =
session->session_info.slotID,.sessionh = session->handle
};
CK_OBJECT_HANDLE obj_store[16];
CK_ULONG objs_found = 0;
CK_OBJECT_CLASS class = CKO_HW_FEATURE;
CK_HW_FEATURE_TYPE type = CKH_IBM_EP11_VHSMPIN;
CK_BYTE cktrue = TRUE;
CK_ATTRIBUTE vhsmpin_template[] = {
{CKA_CLASS, &class, sizeof(class)}
,
{CKA_TOKEN, &cktrue, sizeof(cktrue)}
,
{CKA_PRIVATE, &cktrue, sizeof(cktrue)}
,
{CKA_HIDDEN, &cktrue, sizeof(cktrue)}
,
{CKA_HW_FEATURE_TYPE, &type, sizeof(type)}
,
};
CK_ATTRIBUTE attrs[] = {
{CKA_VALUE, ep11_session->vhsm_pin, sizeof(ep11_session->vhsm_pin)}
,
};
rc = SC_FindObjectsInit(tokdata, &handle,
vhsmpin_template,
sizeof(vhsmpin_template) / sizeof(CK_ATTRIBUTE));
if (rc != CKR_OK) {
TRACE_ERROR("%s SC_FindObjectsInit failed: 0x%lx\n", __func__, rc);
goto out;
}
rc = SC_FindObjects(tokdata, &handle, obj_store, 16, &objs_found);
if (rc != CKR_OK) {
TRACE_ERROR("%s SC_FindObjects failed: 0x%lx\n", __func__, rc);
goto out;
}
if (objs_found == 0) {
rc = CKR_FUNCTION_FAILED;
TRACE_ERROR("%s No VHSMPIN object found\n", __func__);
goto out;
}
rc = SC_GetAttributeValue(tokdata, &handle, obj_store[0],
attrs, sizeof(attrs) / sizeof(CK_ATTRIBUTE));
if (rc != CKR_OK) {
TRACE_ERROR("%s SC_GetAttributeValue failed: 0x%lx\n", __func__, rc);
goto out;
}
ep11_session->flags |= EP11_VHSMPIN_VALID;
out:
SC_FindObjectsFinal(tokdata, &handle);
return rc;
}
static CK_RV ep11_login_handler(uint_32 adapter, uint_32 domain,
void *handler_data)
{
ep11_session_t *ep11_session = (ep11_session_t *) handler_data;
target_t target;
CK_RV rc;
CK_BYTE pin_blob[XCP_PINBLOB_BYTES];
CK_ULONG pin_blob_len = XCP_PINBLOB_BYTES;
CK_BYTE *pin = (CK_BYTE *)DEFAULT_EP11_PIN;
CK_ULONG pin_len = strlen(DEFAULT_EP11_PIN);
CK_BYTE *nonce = NULL;
CK_ULONG nonce_len = 0;
TRACE_INFO("Logging in adapter %02X.%04X\n", adapter, domain);
rc = get_ep11_target_for_apqn(adapter, domain, &target);
if (rc != CKR_OK)
return rc;
if (ep11_session->flags & EP11_VHSM_MODE) {
pin = ep11_session->vhsm_pin;
pin_len = sizeof(ep11_session->vhsm_pin);
rc = dll_m_Login(pin, pin_len, nonce, nonce_len,
pin_blob, &pin_blob_len, target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s dll_m_Login failed: 0x%lx\n", __func__, rc);
/* ignore the error here, the adapter may not be able to perform
* m_Login at this moment */
goto strict_mode;
}
#ifdef DEBUG
TRACE_DEBUG("EP11 VHSM Pin blob (size: %lu):\n", XCP_PINBLOB_BYTES);
TRACE_DEBUG_DUMP(pin_blob, XCP_PINBLOB_BYTES);
#endif
if (ep11_session->flags & EP11_VHSM_PINBLOB_VALID) {
/* First part of pin-blob (keypart and session) must be equal */
if (memcmp(ep11_session->vhsm_pin_blob, pin_blob, XCP_WK_BYTES) !=
0) {
TRACE_ERROR("%s VHSM-Pin blob not equal to previous one\n",
__func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: VHSM-Pin blob of adapter %02X.%04X is "
"not equal to other adapters for same session\n",
__func__, adapter, domain);
rc = CKR_DEVICE_ERROR;
goto out;
}
} else {
memcpy(ep11_session->vhsm_pin_blob, pin_blob, XCP_PINBLOB_BYTES);
ep11_session->flags |= EP11_VHSM_PINBLOB_VALID;
}
}
strict_mode:
if (ep11_session->flags & EP11_STRICT_MODE) {
nonce = ep11_session->session_id;
nonce_len = sizeof(ep11_session->session_id);
/* pin is already set to default pin or vhsm pin (if VHSM mode) */
rc = dll_m_Login(pin, pin_len, nonce, nonce_len,
pin_blob, &pin_blob_len, target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s dll_m_Login failed: 0x%lx\n", __func__, rc);
/* ignore the error here, the adapter may not be able to perform
* m_Login at this moment */
rc = CKR_OK;
goto out;
}
#ifdef DEBUG
TRACE_DEBUG("EP11 Session Pin blob (size: %lu):\n", XCP_PINBLOB_BYTES);
TRACE_DEBUG_DUMP(pin_blob, XCP_PINBLOB_BYTES);
#endif
if (ep11_session->flags & EP11_SESS_PINBLOB_VALID) {
/* First part of pin-blob (keypart and session) must be equal */
if (memcmp(ep11_session->session_pin_blob, pin_blob, XCP_WK_BYTES)
!= 0) {
TRACE_ERROR("%s Pin blob not equal to previous one\n",
__func__);
OCK_SYSLOG(LOG_ERR,
"%s: Error: Pin blob of adapter %02X.%04X is not "
"equal to other adapters for same session\n",
__func__, adapter, domain);
rc = CKR_DEVICE_ERROR;
goto out;
}
} else {
memcpy(ep11_session->session_pin_blob, pin_blob, XCP_PINBLOB_BYTES);
ep11_session->flags |= EP11_SESS_PINBLOB_VALID;
}
}
out:
free_ep11_target_for_apqn(target);
return rc;
}
static CK_RV ep11_logout_handler(uint_32 adapter, uint_32 domain,
void *handler_data)
{
ep11_session_t *ep11_session = (ep11_session_t *) handler_data;
target_t target;
CK_RV rc;
TRACE_INFO("Logging out adapter %02X.%04X\n", adapter, domain);
rc = get_ep11_target_for_apqn(adapter, domain, &target);
if (rc != CKR_OK)
return rc;
if (ep11_session->flags & EP11_SESS_PINBLOB_VALID) {
#ifdef DEBUG
TRACE_DEBUG("EP11 Session Pin blob (size: %lu):\n", XCP_PINBLOB_BYTES);
TRACE_DEBUG_DUMP(ep11_session->session_pin_blob, XCP_PINBLOB_BYTES);
#endif
rc = dll_m_Logout(ep11_session->session_pin_blob, XCP_PINBLOB_BYTES,
target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s dll_m_Logout failed: 0x%lx\n", __func__, rc);
/* ignore any errors during m_logout */
}
}
if (ep11_session->flags & EP11_VHSM_PINBLOB_VALID) {
#ifdef DEBUG
TRACE_DEBUG("EP11 VHSM Pin blob (size: %lu):\n", XCP_PINBLOB_BYTES);
TRACE_DEBUG_DUMP(ep11_session->vhsm_pin_blob, XCP_PINBLOB_BYTES);
#endif
rc = dll_m_Logout(ep11_session->vhsm_pin_blob, XCP_PINBLOB_BYTES,
target);
if (rc != CKR_OK) {
rc = ep11_error_to_pkcs11_error(rc, NULL);
TRACE_ERROR("%s dll_m_Logout failed: 0x%lx\n", __func__, rc);
/* ignore any errors during m_logout */
}
}
free_ep11_target_for_apqn(target);
return CKR_OK;
}
CK_RV ep11tok_login_session(STDLL_TokData_t * tokdata, SESSION * session)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
ep11_session_t *ep11_session;
CK_RV rc;
CK_RV rc2;
ST_SESSION_HANDLE handle = {.slotID =
session->session_info.slotID,.sessionh = session->handle
};
CK_SESSION_HANDLE helper_session = CK_INVALID_HANDLE;
TRACE_INFO("%s session=%lu\n", __func__, session->handle);
if (!ep11_data->strict_mode && !ep11_data->vhsm_mode)
return CKR_OK;
if (session->session_info.flags & CKF_EP11_HELPER_SESSION)
return CKR_OK;
switch (session->session_info.state) {
case CKS_RW_SO_FUNCTIONS:
case CKS_RO_PUBLIC_SESSION:
case CKS_RW_PUBLIC_SESSION:
TRACE_INFO("%s Public or SO session\n", __func__);
return CKR_OK;
case CKS_RO_USER_FUNCTIONS:
rc = ep11_open_helper_session(tokdata, session, &helper_session);
if (rc != CKR_OK)
return rc;
handle.sessionh = helper_session;
break;
default:
break;
}
if (session->private_data != NULL) {
TRACE_INFO("%s Session already logged in\n", __func__);
return CKR_USER_ALREADY_LOGGED_IN;
}
ep11_session = (ep11_session_t *) calloc(1, sizeof(ep11_session_t));
if (ep11_session == NULL) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
return CKR_HOST_MEMORY;
}
ep11_session->session = session;
ep11_session->session_object = CK_INVALID_HANDLE;
ep11_session->vhsm_object = CK_INVALID_HANDLE;
if (ep11_data->strict_mode)
ep11_session->flags |= EP11_STRICT_MODE;
if (ep11_data->vhsm_mode)
ep11_session->flags |= EP11_VHSM_MODE;
session->private_data = ep11_session;
rc = generate_ep11_session_id(tokdata, session, ep11_session);
if (rc != CKR_OK) {
TRACE_ERROR("%s _generate_ep11_session_id failed: 0x%lx\n", __func__,
rc);
goto done;
}
#ifdef DEBUG
TRACE_DEBUG("EP11 Session-ID for PKCS#11 session %lu:\n", session->handle);
TRACE_DEBUG_DUMP(ep11_session->session_id,
sizeof(ep11_session->session_id));
#endif
if (ep11_data->vhsm_mode) {
rc = get_vhsmpin(tokdata, session, ep11_session);
if (rc != CKR_OK) {
TRACE_ERROR("%s get_vhsmpin failed: 0x%lx\n", __func__, rc);
OCK_SYSLOG(LOG_ERR,
"%s: Error: A VHSM-PIN is required for VHSM_MODE.\n",
__func__);
goto done;
}
}
rc = handle_all_ep11_cards(&ep11_data->target_list, ep11_login_handler,
ep11_session);
if (rc != CKR_OK) {
TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc);
goto done;
}
if (ep11_data->strict_mode) {
if ((ep11_session->flags & EP11_SESS_PINBLOB_VALID) == 0) {
rc = CKR_DEVICE_ERROR;
TRACE_ERROR("%s no pinblob available\n", __func__);
goto done;
}
rc = create_ep11_object(tokdata, &handle, ep11_session,
ep11_session->session_pin_blob,
sizeof(ep11_session->session_pin_blob),
&ep11_session->session_object);
if (rc != CKR_OK) {
TRACE_ERROR("%s _create_ep11_object failed: 0x%lx\n", __func__, rc);
goto done;
}
}
if (ep11_data->vhsm_mode) {
if ((ep11_session->flags & EP11_VHSM_PINBLOB_VALID) == 0) {
rc = CKR_DEVICE_ERROR;
TRACE_ERROR("%s no VHSM pinblob available\n", __func__);
goto done;
}
rc = create_ep11_object(tokdata, &handle, ep11_session,
ep11_session->vhsm_pin_blob,
sizeof(ep11_session->vhsm_pin_blob),
&ep11_session->vhsm_object);
if (rc != CKR_OK) {
TRACE_ERROR("%s _create_ep11_object failed: 0x%lx\n", __func__, rc);
goto done;
}
}
done:
if (rc != CKR_OK) {
if (ep11_session->flags &
(EP11_SESS_PINBLOB_VALID | EP11_VHSM_PINBLOB_VALID)) {
rc2 =
handle_all_ep11_cards(&ep11_data->target_list,
ep11_logout_handler, ep11_session);
if (rc2 != CKR_OK)
TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n",
__func__, rc2);
}
if (ep11_session->session_object != CK_INVALID_HANDLE) {
rc2 =
SC_DestroyObject(tokdata, &handle,
ep11_session->session_object);
if (rc2 != CKR_OK)
TRACE_ERROR("%s SC_DestroyObject failed: 0x%lx\n", __func__,
rc2);
}
if (ep11_session->vhsm_object != CK_INVALID_HANDLE) {
rc2 = SC_DestroyObject(tokdata, &handle, ep11_session->vhsm_object);
if (rc2 != CKR_OK)
TRACE_ERROR("%s SC_DestroyObject failed: 0x%lx\n", __func__,
rc2);
}
free(ep11_session);
session->private_data = NULL;
TRACE_ERROR("%s: failed: 0x%lx\n", __func__, rc);
}
if (helper_session != CK_INVALID_HANDLE) {
rc2 = ep11_close_helper_session(tokdata, &handle);
if (rc2 != CKR_OK)
TRACE_ERROR("%s ep11_close_helper_session failed: 0x%lx\n",
__func__, rc2);
}
return rc;
}
static CK_RV ep11tok_relogin_session(STDLL_TokData_t * tokdata,
SESSION * session)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
ep11_session_t *ep11_session = (ep11_session_t *) session->private_data;
CK_RV rc;
TRACE_INFO("%s session=%lu\n", __func__, session->handle);
if (ep11_session == NULL) {
TRACE_INFO("%s Session not yet logged in\n", __func__);
return CKR_USER_NOT_LOGGED_IN;
}
rc = handle_all_ep11_cards(&ep11_data->target_list, ep11_login_handler,
ep11_session);
if (rc != CKR_OK)
TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc);
return CKR_OK;
}
CK_RV ep11tok_logout_session(STDLL_TokData_t * tokdata, SESSION * session)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
ep11_session_t *ep11_session = (ep11_session_t *) session->private_data;
CK_RV rc, rc2;
ST_SESSION_HANDLE handle = {.slotID =
session->session_info.slotID,.sessionh = session->handle
};
CK_SESSION_HANDLE helper_session = CK_INVALID_HANDLE;
TRACE_INFO("%s session=%lu\n", __func__, session->handle);
if (!ep11_data->strict_mode && !ep11_data->vhsm_mode)
return CKR_OK;
if (session->session_info.flags & CKF_EP11_HELPER_SESSION)
return CKR_OK;
switch (session->session_info.state) {
case CKS_RW_SO_FUNCTIONS:
case CKS_RO_PUBLIC_SESSION:
case CKS_RW_PUBLIC_SESSION:
TRACE_INFO("%s Public or SO session\n", __func__);
return CKR_OK;
case CKS_RO_USER_FUNCTIONS:
rc = ep11_open_helper_session(tokdata, session, &helper_session);
if (rc != CKR_OK)
return rc;
handle.sessionh = helper_session;
break;
default:
break;
}
if (ep11_session == NULL) {
TRACE_INFO("%s CKR_USER_NOT_LOGGED_IN\n", __func__);
return CKR_USER_NOT_LOGGED_IN;
}
rc = handle_all_ep11_cards(&ep11_data->target_list, ep11_logout_handler,
ep11_session);
if (rc != CKR_OK)
TRACE_ERROR("%s handle_all_ep11_cards failed: 0x%lx\n", __func__, rc);
if (ep11_session->session_object != CK_INVALID_HANDLE) {
rc = SC_DestroyObject(tokdata, &handle, ep11_session->session_object);
if (rc != CKR_OK)
TRACE_ERROR("%s SC_DestroyObject failed: 0x%lx\n", __func__, rc);
}
if (ep11_session->vhsm_object != CK_INVALID_HANDLE) {
rc = SC_DestroyObject(tokdata, &handle, ep11_session->vhsm_object);
if (rc != CKR_OK)
TRACE_ERROR("%s SC_DestroyObject failed: 0x%lx\n", __func__, rc);
}
free(ep11_session);
session->private_data = NULL;
if (helper_session != CK_INVALID_HANDLE) {
rc2 = ep11_close_helper_session(tokdata, &handle);
if (rc2 != CKR_OK)
TRACE_ERROR("%s ep11_close_helper_session failed: 0x%lx\n",
__func__, rc2);
}
return rc;
}
static CK_BOOL ep11_is_session_object(CK_ATTRIBUTE_PTR attrs, CK_ULONG attrs_len)
{
CK_ATTRIBUTE_PTR attr;
attr = get_attribute_by_type(attrs, attrs_len, CKA_TOKEN);
if (attr == NULL)
return TRUE;
if (attr->pValue == NULL)
return TRUE;
if (*((CK_BBOOL *) attr->pValue) == FALSE)
return TRUE;
return FALSE;
}
static void ep11_get_pin_blob(ep11_session_t * ep11_session, CK_BOOL is_session_obj,
CK_BYTE ** pin_blob, CK_ULONG * pin_blob_len)
{
if (ep11_session != NULL &&
(ep11_session->flags & EP11_STRICT_MODE) && is_session_obj) {
*pin_blob = ep11_session->session_pin_blob;
*pin_blob_len = sizeof(ep11_session->session_pin_blob);
TRACE_DEVEL
("%s Strict mode and CKA_TOKEN=FALSE -> pass session pin_blob\n",
__func__);
} else if (ep11_session != NULL && (ep11_session->flags & EP11_VHSM_MODE)) {
*pin_blob = ep11_session->vhsm_pin_blob;
*pin_blob_len = sizeof(ep11_session->vhsm_pin_blob);
TRACE_DEVEL("%s vHSM mode -> pass VHSM pin_blob\n", __func__);
} else {
*pin_blob = NULL;
*pin_blob_len = 0;
}
}
static CK_RV ep11_open_helper_session(STDLL_TokData_t * tokdata, SESSION * sess,
CK_SESSION_HANDLE_PTR phSession)
{
CK_RV rc;
TRACE_INFO("%s\n", __func__);
rc = SC_OpenSession(tokdata, sess->session_info.slotID,
CKF_RW_SESSION | CKF_SERIAL_SESSION |
CKF_EP11_HELPER_SESSION, phSession);
if (rc != CKR_OK)
TRACE_ERROR("%s SC_OpenSession failed: 0x%lx\n", __func__, rc);
return rc;
}
static CK_RV ep11_close_helper_session(STDLL_TokData_t * tokdata,
ST_SESSION_HANDLE * sSession)
{
CK_RV rc;
TRACE_INFO("%s\n", __func__);
rc = SC_CloseSession(tokdata, sSession);
if (rc != CKR_OK)
TRACE_ERROR("%s SC_CloseSession failed: 0x%lx\n", __func__, rc);
return rc;
}
CK_BBOOL ep11tok_optimize_single_ops(STDLL_TokData_t *tokdata)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
return ep11_data->optimize_single_ops ? CK_TRUE : CK_FALSE;
}
/* return -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2 */
static int compare_ck_version(const CK_VERSION *v1, const CK_VERSION *v2)
{
if (v1->major < v2->major)
return -1;
if (v1->major > v2->major)
return 1;
if (v1->minor < v2->minor)
return -1;
if (v1->minor > v2->minor)
return 1;
return 0;
}
static CK_RV get_card_type(uint_32 adapter, CK_ULONG *type)
{
char fname[PATH_MAX];
char buf[250];
CK_RV rc;
CK_ULONG hwtype, rawtype;
#ifdef EP11_HSMSIM
#ifdef EP11_HSMSIM_CARD_TYPE
*type = EP11_HSMSIM_CARD_TYPE;
#else
*type = 7;
#endif
return CKR_OK;
#endif
sprintf(fname, "%scard%02x/type", SYSFS_DEVICES_AP, adapter);
rc = file_fgets(fname, buf, sizeof(buf));
if (rc != CKR_OK)
return rc;
if (sscanf(buf, "CEX%luP", type) != 1)
return CKR_FUNCTION_FAILED;
sprintf(fname, "%scard%02x/hwtype", SYSFS_DEVICES_AP, adapter);
rc = file_fgets(fname, buf, sizeof(buf));
if (rc != CKR_OK)
return rc;
if (sscanf(buf, "%lu", &hwtype) != 1)
return CKR_FUNCTION_FAILED;
sprintf(fname, "%scard%02x/raw_hwtype", SYSFS_DEVICES_AP, adapter);
rc = file_fgets(fname, buf, sizeof(buf));
if (rc != CKR_OK)
return rc;
if (sscanf(buf, "%lu", &rawtype) != 1)
return CKR_FUNCTION_FAILED;
if (rawtype > hwtype) {
TRACE_DEVEL("%s adapter: %u hwtype: %lu raw_hwtype: %lu\n",
__func__, adapter, hwtype, rawtype);
/* Tolerated new card level: report calculated type */
*type += (rawtype - hwtype);
}
return CKR_OK;
}
typedef struct query_version
{
ep11_private_data_t *ep11_data;
CK_CHAR serialNumber[16];
CK_BBOOL first;
CK_BBOOL error;
} query_version_t;
static CK_RV version_query_handler(uint_32 adapter, uint_32 domain,
void *handler_data)
{
query_version_t *qv = (query_version_t *)handler_data;
CK_IBM_XCP_INFO xcp_info;
CK_ULONG xcp_info_len = sizeof(xcp_info);
CK_RV rc;
target_t target;
CK_ULONG card_type;
ep11_card_version_t *card_version;
rc = get_ep11_target_for_apqn(adapter, domain, &target);
if (rc != CKR_OK)
return rc;
rc = dll_m_get_xcp_info(&xcp_info, &xcp_info_len, CK_IBM_XCPQ_MODULE, 0,
target);
if (rc != CKR_OK) {
TRACE_ERROR("%s Failed to query module version from adapter %02X.%04X\n",
__func__, adapter, domain);
/* card may no longer be online, so ignore this error situation */
rc = CKR_OK;
goto out;
}
rc = get_card_type(adapter, &card_type);
if (rc != CKR_OK) {
TRACE_ERROR("%s Failed to get card type for adapter %02X.%04X\n",
__func__, adapter, domain);
/* card may no longer be online, so ignore this error situation */
rc = CKR_OK;
goto out;
}
/* Try to find existing version info for this card type */
card_version = qv->ep11_data->card_versions;
while (card_version != NULL) {
if (card_version->card_type == card_type)
break;
card_version = card_version->next;
}
if (card_version == NULL) {
/*
* No version info for this card type found, create new entry and add
* it to the list
*/
card_version = calloc(1, sizeof(ep11_card_version_t));
if (card_version == NULL) {
TRACE_ERROR("%s Memory allocation failed\n", __func__);
qv->error = TRUE;
rc = CKR_HOST_MEMORY;
goto out;
}
card_version->card_type = card_type;
#ifdef EP11_HSMSIM
#ifdef EP11_HSMSIM_FW_API
card_version->firmware_API_version = EP11_HSMSIM_FW_API;
#else
card_version->firmware_API_version = xcp_info.firmwareApi;
#endif
#else
card_version->firmware_API_version = xcp_info.firmwareApi;
#endif
#ifdef EP11_HSMSIM
#ifdef EP11_HSMSIM_FW_VER_MAJOR
card_version->firmware_version.major = EP11_HSMSIM_FW_VER_MAJOR;
#ifdef EP11_HSMSIM_FW_VER_MINOR
card_version->firmware_version.minor = EP11_HSMSIM_FW_VER_MINOR;
#else
card_version->firmware_version.minor = 0;
#endif
#else
card_version->firmware_version = xcp_info.firmwareVersion;
#endif
#else
card_version->firmware_version = xcp_info.firmwareVersion;
#endif
card_version->next = qv->ep11_data->card_versions;
qv->ep11_data->card_versions = card_version;
} else {
/*
* Version info for this card type is already available, so check this
* card against the existing info
*/
if (card_version->firmware_API_version != xcp_info.firmwareApi) {
TRACE_ERROR("%s Adapter %02X.%04X has a different API version "
"than the previous CEX%luP adapters: %lu\n", __func__,
adapter, domain, card_version->card_type,
xcp_info.firmwareApi);
OCK_SYSLOG(LOG_ERR,
"Warning: Adapter %02X.%04X has a different API version "
"than the previous CEX%luP adapters: %lu\n",
adapter, domain, card_version->card_type,
xcp_info.firmwareApi);
qv->error = TRUE;
rc = CKR_OK;
goto out;
}
if (compare_ck_version(&card_version->firmware_version,
&xcp_info.firmwareVersion) != 0) {
TRACE_ERROR("%s Adapter %02X.%04X has a different firmware version "
"than the previous CEX%luP adapters: %d.%d\n", __func__,
adapter, domain, card_version->card_type,
xcp_info.firmwareVersion.major,
xcp_info.firmwareVersion.minor);
OCK_SYSLOG(LOG_ERR,
"Warning: Adapter %02X.%04X has a different firmware "
"version than the previous CEX%luP adapters: %d.%d\n",
adapter, domain, card_version->card_type,
xcp_info.firmwareVersion.major,
xcp_info.firmwareVersion.minor);
qv->error = TRUE;
rc = CKR_OK;
goto out;
}
}
if (qv->first)
memcpy(qv->serialNumber, xcp_info.serialNumber,
sizeof(qv->serialNumber));
qv->first = FALSE;
out:
free_ep11_target_for_apqn(target);
return rc;
}
static CK_RV ep11tok_get_ep11_library_version(CK_VERSION *lib_version)
{
unsigned int host_version;
CK_ULONG version_len = sizeof(host_version);
CK_RV rc;
if (dll_m_get_xcp_info == NULL) {
TRACE_ERROR("%s Function dll_m_get_xcp_info is not available\n",
__func__);
return CKR_FUNCTION_FAILED;
}
rc = dll_m_get_xcp_info(&host_version, &version_len,
CK_IBM_XCPHQ_VERSION, 0, 0);
if (rc != CKR_OK) {
TRACE_ERROR("%s dll_m_get_xcp_info (HOST) failed: rc=0x%lx\n", __func__,
rc);
return rc;
}
lib_version->major = (host_version & 0x00FF0000) >> 16;
lib_version->minor = host_version & 0x000000FF;
/*
* EP11 host library < v2.0 returns an invalid version (i.e. 0x100). This
* can safely be treated as version 1.0
*/
if (lib_version->major == 0) {
lib_version->major = 1;
lib_version->minor = 0;
}
return CKR_OK;
}
static CK_RV ep11tok_get_ep11_version(STDLL_TokData_t *tokdata)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
ep11_card_version_t *card_version;
query_version_t qv;
CK_RV rc;
rc = ep11tok_get_ep11_library_version(&ep11_data->ep11_lib_version);
if (rc != CKR_OK)
return rc;
TRACE_INFO("%s Host library version: %d.%d\n", __func__,
ep11_data->ep11_lib_version.major,
ep11_data->ep11_lib_version.minor);
memset(&qv, 0, sizeof(qv));
qv.ep11_data = ep11_data;
qv.first = TRUE;
rc = handle_all_ep11_cards(&ep11_data->target_list, version_query_handler,
&qv);
if (rc != CKR_OK) {
TRACE_ERROR("%s handle_all_ep11_cards failed: rc=0x%lx\n",
__func__, rc);
return rc;
}
if (qv.first) {
TRACE_ERROR("%s No EP11 adapters are online or configured\n", __func__);
return CKR_DEVICE_ERROR;
}
if (qv.error) {
TRACE_ERROR("%s Failed to query version of EP11 adapters\n", __func__);
return CKR_DEVICE_ERROR;
}
memcpy(ep11_data->serialNumber, qv.serialNumber,
sizeof(ep11_data->serialNumber));
TRACE_INFO("%s Serial number: %.16s\n", __func__, ep11_data->serialNumber);
/* EP11 host lib version <= 2 only support API version 2 */
if (ep11_data->ep11_lib_version.major <= 2)
ep11_data->used_firmware_API_version = 2;
else
ep11_data->used_firmware_API_version = 0;
card_version = ep11_data->card_versions;
while (card_version != NULL) {
TRACE_INFO("%s Card type: CEX%luP\n", __func__,
card_version->card_type);
TRACE_INFO("%s Firmware API: %lu\n", __func__,
card_version->firmware_API_version);
TRACE_INFO("%s Firmware Version: %d.%d\n", __func__,
card_version->firmware_version.major,
card_version->firmware_version.minor);
if (ep11_data->used_firmware_API_version == 0)
ep11_data->used_firmware_API_version =
card_version->firmware_API_version;
else
ep11_data->used_firmware_API_version =
MIN(ep11_data->used_firmware_API_version,
card_version->firmware_API_version);
card_version = card_version->next;
}
TRACE_INFO("%s Used Firmware API: %lu\n", __func__,
ep11_data->used_firmware_API_version);
return CKR_OK;
}
static void free_card_versions(ep11_card_version_t *card_version)
{
ep11_card_version_t *next_card_version;
TRACE_INFO("%s running\n", __func__);
while (card_version != NULL) {
next_card_version = card_version->next;
free(card_version);
card_version = next_card_version;
}
}
void ep11tok_copy_firmware_info(STDLL_TokData_t *tokdata,
CK_TOKEN_INFO_PTR pInfo)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
/*
* report the EP11 firmware version as hardware version, and
* the EP11 host library version as firmware version
*/
if (ep11_data->card_versions != NULL)
pInfo->hardwareVersion = ep11_data->card_versions->firmware_version;
pInfo->firmwareVersion = ep11_data->ep11_lib_version;
memcpy(pInfo->serialNumber, ep11_data->serialNumber,
sizeof(pInfo->serialNumber));
}
/**
* Returns 1 if all APQNs that are present are at least at the required
* versions. If non of the APQNs are at the required versions, 0 is returned.
* If the APQN versions are inconsistent, -1 is returned.
* Card types > the highest card type contained in the requirements array are
* assumed to fulfill the minimum version requirements.
*/
static int check_required_versions(STDLL_TokData_t *tokdata,
const version_req_t req[],
CK_ULONG num_req)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
CK_ULONG i, max_card_type = 0, min_card_type = 0xFFFFFFFF;
CK_BBOOL req_not_fullfilled = CK_FALSE;
CK_BBOOL req_fullfilled = CK_FALSE;
ep11_card_version_t *card_version;
int status;
for (i = 0; i < num_req; i++) {
status = check_card_version(tokdata, req[i].card_type,
req[i].min_lib_version,
req[i].min_firmware_version,
req[i].min_firmware_API_version);
if (status == 0)
req_not_fullfilled = CK_TRUE;
if (status == 1)
req_fullfilled = CK_TRUE;
max_card_type = MAX(max_card_type, req[i].card_type);
min_card_type = MIN(min_card_type, req[i].card_type);
}
/* Are card types < min_card_type present? */
card_version = ep11_data->card_versions;
while (card_version != NULL) {
if (card_version->card_type < min_card_type)
req_not_fullfilled = CK_TRUE;
card_version = card_version->next;
}
/* Are card types > max_card_type present? */
card_version = ep11_data->card_versions;
while (card_version != NULL) {
if (card_version->card_type > max_card_type) {
/*
* Card types > the highest card type contained in the requirements
* array are assumed to fulfill the minimum version requirements.
* So all others must also meet the version requirements or be
* not present.
*/
if (req_not_fullfilled == CK_TRUE)
return -1;
return 1;
}
card_version = card_version->next;
}
/* No newer cards then max_card_type are present */
if (req_not_fullfilled == CK_TRUE) {
/*
* At least one don't meet the requirements, so all other must not
* fulfill the requirements, too, or are not present.
*/
if (req_fullfilled == CK_TRUE)
return -1;
return 0;
} else {
/* All of the cards that are present fulfill the requirements */
return 1;
}
}
/**
* returns 1 if all APQNs of the specified card type are at least at the
* specified versions, 0 otherwise. If no APQN of that card type is online,
* then -1 is returned.
* Those parameters that are NULL are not checked.
*/
static int check_card_version(STDLL_TokData_t *tokdata, CK_ULONG card_type,
const CK_VERSION *ep11_lib_version,
const CK_VERSION *firmware_version,
const CK_ULONG *firmware_API_version)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
ep11_card_version_t *card_version;
TRACE_DEBUG("%s checking versions for CEX%luP cards.\n", __func__, card_type);
if (ep11_lib_version != NULL) {
if (compare_ck_version(&ep11_data->ep11_lib_version,
ep11_lib_version) < 0) {
TRACE_DEBUG("%s ep11_lib_version is less than required\n", __func__);
return 0;
}
}
card_version = ep11_data->card_versions;
while (card_version != NULL) {
if (card_version->card_type == card_type)
break;
card_version = card_version->next;
}
if (card_version == NULL)
return -1;
if (firmware_version != NULL) {
if (compare_ck_version(&card_version->firmware_version,
firmware_version) < 0) {
TRACE_DEBUG("%s firmware_version is less than required\n", __func__);
return 0;
}
}
if (firmware_API_version != NULL) {
if (card_version->firmware_API_version < *firmware_API_version) {
TRACE_DEBUG("%s firmware_API_version is less than required\n",
__func__);
return 0;
}
}
return 1;
}
static CK_RV ep11tok_setup_target(STDLL_TokData_t *tokdata)
{
ep11_private_data_t *ep11_data = tokdata->private_data;
struct XCP_Module module;
CK_RV rc;
short i;
if (dll_m_add_module == NULL) {
TRACE_WARNING("%s Function dll_m_add_module is not available, falling "
"back to old target handling\n", __func__);
if (ep11_data->used_firmware_API_version > 2) {
TRACE_ERROR("%s selecting an API version is not possible with old "
"target handling\n", __func__);
return CKR_FUNCTION_FAILED;
}
ep11_data->target = (target_t)&ep11_data->target_list;
return CKR_OK;
}
if (ep11_data->used_firmware_API_version > 2 &&
ep11_data->ep11_lib_version.major < 3) {
TRACE_ERROR("%s selecting an API version is not possible with an EP11"
" host library version < 3.0\n", __func__);
return CKR_FUNCTION_FAILED;
}
ep11_data->target = XCP_TGT_INIT;
memset(&module, 0, sizeof(module));
module.version = ep11_data->ep11_lib_version.major >= 3 ? XCP_MOD_VERSION_2
: XCP_MOD_VERSION_1;
module.flags = XCP_MFL_VIRTUAL | XCP_MFL_MODULE;
module.api = ep11_data->used_firmware_API_version;
TRACE_DEVEL("%s XCP_MOD_VERSION: %u\n", __func__, module.version);
if (ep11_data->target_list.length == 0) {
/* APQN_ANY: Create an empty module group */
rc = dll_m_add_module(&module, &ep11_data->target);
if (rc != CKR_OK) {
TRACE_ERROR("%s dll_m_add_module (ANY) failed: rc=%ld\n",
__func__, rc);
return CKR_FUNCTION_FAILED;
}
return CKR_OK;
}
for (i = 0; i < ep11_data->target_list.length; i++) {
module.module_nr = ep11_data->target_list.apqns[2 * i];
memset(module.domainmask, 0, sizeof(module.domainmask));
XCPTGTMASK_SET_DOM(module.domainmask,
ep11_data->target_list.apqns[2 * i + 1]);
rc = dll_m_add_module(&module, &ep11_data->target);
if (rc != CKR_OK) {
TRACE_ERROR("%s dll_m_add_module (%02x.%04x) failed: rc=%ld\n",
__func__, ep11_data->target_list.apqns[2 * i],
ep11_data->target_list.apqns[2 * i + 1], rc);
return CKR_FUNCTION_FAILED;
}
}
return CKR_OK;
}
static CK_RV get_ep11_target_for_apqn(uint_32 adapter, uint_32 domain,
target_t *target)
{
ep11_target_t *target_list;
struct XCP_Module module;
CK_VERSION lib_version;
CK_RV rc;
*target = XCP_TGT_INIT;
rc = ep11tok_get_ep11_library_version(&lib_version);
if (rc != CKR_OK)
return rc;
if (dll_m_add_module != NULL) {
memset(&module, 0, sizeof(module));
module.version = lib_version.major >= 3 ? XCP_MOD_VERSION_2
: XCP_MOD_VERSION_1;
module.flags = XCP_MFL_MODULE;
module.module_nr = adapter;
XCPTGTMASK_SET_DOM(module.domainmask, domain);
rc = dll_m_add_module(&module, target);
if (rc != 0) {
TRACE_ERROR("%s dll_m_add_module (%02x.%04x) failed: rc=%ld\n",
__func__, adapter, domain, rc);
return CKR_FUNCTION_FAILED;
}
} else {
/* Fall back to old target handling */
target_list = (ep11_target_t *)calloc(1, sizeof(ep11_target_t));
if (target_list == NULL)
return CKR_HOST_MEMORY;
target_list->length = 1;
target_list->apqns[0] = adapter;
target_list->apqns[1] = domain;
*target = (target_t)target_list;
}
return CKR_OK;
}
static void free_ep11_target_for_apqn(target_t target)
{
CK_RV rc;
if (dll_m_rm_module != NULL) {
rc = dll_m_rm_module(NULL, target);
if (rc != 0) {
TRACE_DEBUG("%s dll_m_rm_module failed: rc=%ld\n", __func__, rc);
}
} else {
/* With the old target handling, target is a pointer to ep11_target_t */
free((ep11_target_t *)target);
}
}