/* * COPYRIGHT (c) International Business Machines Corp. 2006-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 */ #include #include #include #include #include "pkcs11types.h" #include "regress.h" #include "platform.h" #include "ec_curves.h" #define UNUSED(var) ((void)(var)) CK_FUNCTION_LIST *funcs; CK_FUNCTION_LIST_3_0 *funcs3; CK_FUNCTION_LIST_3_2 *funcs3_2; CK_INTERFACE *ifs; CK_SLOT_ID SLOT_ID; CK_BBOOL skip_token_obj; CK_BBOOL no_stop; CK_BBOOL no_init; CK_BBOOL securekey; /* * The pkey flag controls whether tests shall exploit the protected key * option. To allow easy integration into the CI, this is not provided as * a cmdline option, but affected tests are run twice, with and without * pkey option. */ CK_BBOOL pkey = CK_FALSE; CK_BBOOL combined_extract = CK_FALSE; CK_BBOOL rsa8k = CK_FALSE; CK_ULONG t_total = 0; // total test assertions CK_ULONG t_ran = 0; // number of assertions ran CK_ULONG t_passed = 0; // number of assertions passed CK_ULONG t_failed = 0; // number of assertions failed CK_ULONG t_skipped = 0; // number of assertions skipped CK_ULONG t_errors = 0; // number of errors #define MAX_MODEL 4 #define DES_KEY_SIZE 8 #define DES3_KEY_SIZE 24 static void *pkcs11lib = NULL; static void unload_pkcslib(void) { if (pkcs11lib != NULL) { #ifndef WITH_SANITIZER dlclose(pkcs11lib); #endif } } static void free_ifs(void) { free(ifs); ifs = NULL; } int mech_supported(CK_SLOT_ID slot_id, CK_ULONG mechanism) { CK_MECHANISM_INFO mech_info; int rc; rc = funcs->C_GetMechanismInfo(slot_id, mechanism, &mech_info); return (rc == CKR_OK); } int mech_supported_flags(CK_SLOT_ID slot_id, CK_ULONG mechanism, CK_FLAGS flags) { CK_MECHANISM_INFO mech_info; int rc; rc = funcs->C_GetMechanismInfo(slot_id, mechanism, &mech_info); if (rc != CKR_OK) return FALSE; if (mech_info.flags & flags) return TRUE; return FALSE; } /* * Check if the specified key size is in the supported range of the mechanism. * * ATTENTION: It is mechanism dependent if the key size is in bits or bytes. * The caller of this function must take care that the keylen parameter is * specified in the appropriate unit. */ int check_supp_keysize(CK_SLOT_ID slot_id, CK_ULONG mechanism, CK_ULONG keylen) { CK_MECHANISM_INFO mech_info; int rc; rc = funcs->C_GetMechanismInfo(slot_id, mechanism, &mech_info); if (rc != CKR_OK) return FALSE; /* min and max being zero indicate no key size limitation */ if (mech_info.ulMinKeySize == 0 && mech_info.ulMaxKeySize == 0) return TRUE; return ((mech_info.ulMinKeySize <= keylen) && (keylen <= mech_info.ulMaxKeySize)); } /** Returns true if and only if slot supports key wrapping with specified mechanism **/ int wrap_supported(CK_SLOT_ID slot_id, CK_MECHANISM mech) { CK_MECHANISM_INFO mech_info; CK_RV rc; // get mech info rc = funcs->C_GetMechanismInfo(slot_id, mech.mechanism, &mech_info); if (rc != CKR_OK) { testcase_error("C_GetMechanismInfo(), rc=%s.", p11_get_ckr(rc)); return -1; } rc = mech_info.flags & CKF_WRAP; return rc; } /** Returns true if and only if slot supports key unwrapping with specified mechanism **/ int unwrap_supported(CK_SLOT_ID slot_id, CK_MECHANISM mech) { CK_MECHANISM_INFO mech_info; CK_RV rc; // get mech info rc = funcs->C_GetMechanismInfo(slot_id, mech.mechanism, &mech_info); if (rc != CKR_OK) { testcase_error("C_GetMechanismInfo(), rc=%s.", p11_get_ckr(rc)); return -1; } rc = mech_info.flags & CKF_UNWRAP; return rc; } int encapsulate_supported(CK_SLOT_ID slot_id, CK_MECHANISM mech) { CK_MECHANISM_INFO mech_info; CK_RV rc; // get mech info rc = funcs->C_GetMechanismInfo(slot_id, mech.mechanism, &mech_info); if (rc != CKR_OK) { testcase_error("C_GetMechanismInfo(), rc=%s.", p11_get_ckr(rc)); return -1; } rc = mech_info.flags & CKF_ENCAPSULATE; return rc; } int decapsulate_supported(CK_SLOT_ID slot_id, CK_MECHANISM mech) { CK_MECHANISM_INFO mech_info; CK_RV rc; // get mech info rc = funcs->C_GetMechanismInfo(slot_id, mech.mechanism, &mech_info); if (rc != CKR_OK) { testcase_error("C_GetMechanismInfo(), rc=%s.", p11_get_ckr(rc)); return -1; } rc = mech_info.flags & CKF_DECAPSULATE; return rc; } /** * Check if the last CKR_FUNCTION__FAILED error was due to policy restrictions */ int is_rejected_by_policy(CK_RV ret_code, CK_SESSION_HANDLE session) { CK_SESSION_INFO info; CK_RV rc; if (ret_code != CKR_FUNCTION_FAILED) return 0; rc = funcs->C_GetSessionInfo(session, &info); if (rc != CKR_OK) { testcase_error("C_GetSessionInfo(), rc=%s.", p11_get_ckr(rc)); return 0; } if (info.ulDeviceError != 0 && info.ulDeviceError != CKR_POLICY_VIOLATION) { testcase_notice("CK_SESSION_INFO.ulDeviceError: 0x%lx", info.ulDeviceError); } return (info.ulDeviceError == CKR_POLICY_VIOLATION); } /** Create an AES key handle with given value **/ CK_RV create_AESKey(CK_SESSION_HANDLE session, CK_BBOOL extractable, unsigned char key[], unsigned char key_len, CK_KEY_TYPE keyType, CK_OBJECT_HANDLE * h_key) { CK_RV rc; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_BBOOL pkeyextractable = !extractable; CK_ATTRIBUTE keyTemplate[] = { {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_VALUE, key, key_len}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; CK_ULONG keyTemplate_len = sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; rc = funcs->C_CreateObject(session, keyTemplate, keyTemplate_len, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Generate an AES key handle **/ CK_RV generate_AESKey(CK_SESSION_HANDLE session, CK_ULONG key_len, CK_BBOOL extractable, CK_MECHANISM * mechkey, CK_OBJECT_HANDLE * h_key) { CK_BBOOL pkeyextractable = !extractable; CK_ATTRIBUTE key_gen_tmpl[] = { {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; CK_ULONG key_gen_tmpl_len = sizeof(key_gen_tmpl) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; CK_RV rc = funcs->C_GenerateKey(session, mechkey, key_gen_tmpl, key_gen_tmpl_len, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_GenerateKey rc=%s", p11_get_ckr(rc)); } return rc; } /** Create a DES key handle with given value **/ CK_RV create_DESKey(CK_SESSION_HANDLE session, unsigned char key[], unsigned char klen, CK_OBJECT_HANDLE * h_key) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES; CK_BYTE value[DES_KEY_SIZE]; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE keyTemplate[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_VALUE, value, klen} }; memset(value, 0, sizeof(value)); memcpy(value, key, klen); rc = funcs->C_CreateObject(session, keyTemplate, 5, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create DES2 key handle with given value **/ CK_RV create_DES2Key(CK_SESSION_HANDLE session, unsigned char key[], unsigned char klen, CK_OBJECT_HANDLE * h_key) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES2; CK_BYTE value[2 * DES_KEY_SIZE]; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE keyTemplate[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_VALUE, value, klen} }; memset(value, 0, sizeof(value)); memcpy(value, key, klen); rc = funcs->C_CreateObject(session, keyTemplate, 5, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create DES3 key handle with given value **/ CK_RV create_DES3Key(CK_SESSION_HANDLE session, unsigned char key[], unsigned char klen, CK_OBJECT_HANDLE * h_key) { CK_RV rc; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES3; CK_BYTE value[DES3_KEY_SIZE]; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_ATTRIBUTE keyTemplate[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_VALUE, value, klen} }; memset(value, 0, sizeof(value)); memcpy(value, key, klen); rc = funcs->C_CreateObject(session, keyTemplate, 5, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create Generic Secret key handle with given value **/ CK_RV create_GenericSecretKey(CK_SESSION_HANDLE session, CK_KEY_TYPE key_type, CK_BYTE key[], CK_ULONG key_len, CK_OBJECT_HANDLE * h_key) { CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; CK_BBOOL false = FALSE; CK_RV rc; CK_ATTRIBUTE key_attribs[] = { {CKA_CLASS, &key_class, sizeof(key_class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_VALUE, key, key_len} }; rc = funcs->C_CreateObject(session, key_attribs, 4, h_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an RSA private key using ctr (chinese remainder theorem) values **/ CK_RV create_RSAPrivateKey(CK_SESSION_HANDLE session, CK_BYTE modulus[], CK_BYTE publicExponent[], CK_BYTE privateExponent[], CK_BYTE prime1[], CK_BYTE prime2[], CK_BYTE exponent1[], CK_BYTE exponent2[], CK_BYTE coefficient[], CK_ULONG modulus_len, CK_ULONG publicExponent_len, CK_ULONG privateExponent_len, CK_ULONG prime1_len, CK_ULONG prime2_len, CK_ULONG exponent1_len, CK_ULONG exponent2_len, CK_ULONG coefficient_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_UTF8CHAR label[] = "An RSA private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label) - 1}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_MODULUS, modulus, modulus_len}, {CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len}, {CKA_PRIVATE_EXPONENT, privateExponent, privateExponent_len}, {CKA_PRIME_1, prime1, prime1_len}, {CKA_PRIME_2, prime2, prime2_len}, {CKA_EXPONENT_1, exponent1, exponent1_len}, {CKA_EXPONENT_2, exponent2, exponent2_len}, {CKA_COEFFICIENT, coefficient, coefficient_len} }; CK_ULONG template_len = sizeof(template) / sizeof(CK_ATTRIBUTE); if (prime1 == NULL || prime1_len == 0 || prime2 == NULL || prime2_len == 0 || exponent1 == NULL || exponent1_len == 0 || exponent2 == NULL || exponent2_len == 0 || coefficient == NULL || coefficient_len == 0) template_len -= 5; // create key rc = funcs->C_CreateObject(session, template, template_len, priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an RSA public key **/ CK_RV create_RSAPublicKey(CK_SESSION_HANDLE session, CK_BYTE modulus[], CK_BYTE publicExponent[], CK_ULONG modulus_len, CK_ULONG publicExponent_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_UTF8CHAR label[] = "An RSA public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label) - 1}, {CKA_WRAP, &true, sizeof(true)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_MODULUS, modulus, modulus_len}, {CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len} }; // create key rc = funcs->C_CreateObject(session, template, 8, publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Generate an RSA (PKCS) key pair **/ CK_RV generate_RSA_PKCS_KeyPair(CK_SESSION_HANDLE session, CK_MECHANISM_TYPE mech_type, CK_ULONG modulusBits, CK_BYTE publicExponent[], CK_ULONG publicExponent_len, CK_OBJECT_HANDLE * publ_key, CK_OBJECT_HANDLE * priv_key) { CK_RV rc; CK_MECHANISM mech = { mech_type, NULL, 0 }; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_WRAP, &true, sizeof(true)}, {CKA_ENCAPSULATE, &true, sizeof(true)}, {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)}, {CKA_PUBLIC_EXPONENT, publicExponent, publicExponent_len} }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_UNWRAP, &true, sizeof(true)}, {CKA_DECAPSULATE, &true, sizeof(true)}, }; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, 6, privateKeyTemplate, 9, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; // no error checking due to // ICA Token + public exponent values + CKR_TEMPLATE_INCONSISTENT // work around // see rsa_func.c } struct rsa_key_cache_entry { CK_SESSION_HANDLE session; CK_MECHANISM_TYPE keygen_mech_type; CK_ULONG modulusBits; CK_BYTE *publicExponent; CK_ULONG publicExponent_len; CK_OBJECT_HANDLE publ_key; CK_OBJECT_HANDLE priv_key; }; struct rsa_key_cache_entry *rsa_key_cache = NULL; CK_ULONG rsa_key_cache_size = 0; CK_RV generate_RSA_PKCS_KeyPair_cached(CK_SESSION_HANDLE session, CK_MECHANISM_TYPE mech_type, CK_ULONG modulusBits, CK_BYTE publicExponent[], CK_ULONG publicExponent_len, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key) { struct rsa_key_cache_entry *tmp, *free = NULL; CK_ULONG i; CK_RV rc; for (i = 0; i < rsa_key_cache_size; i++) { if (rsa_key_cache[i].session == session && rsa_key_cache[i].keygen_mech_type == mech_type && rsa_key_cache[i].modulusBits == modulusBits && rsa_key_cache[i].publicExponent_len == publicExponent_len && memcmp(rsa_key_cache[i].publicExponent, publicExponent, publicExponent_len) == 0) { *publ_key = rsa_key_cache[i].publ_key; *priv_key = rsa_key_cache[i].priv_key; return CKR_OK; } if (rsa_key_cache[i].session == CK_INVALID_HANDLE && free == NULL) free = &rsa_key_cache[i]; } rc = generate_RSA_PKCS_KeyPair(session, mech_type, modulusBits, publicExponent, publicExponent_len, publ_key, priv_key); if (rc != CKR_OK) return rc; if (free == NULL) { tmp = realloc(rsa_key_cache, (rsa_key_cache_size + 1) * sizeof(struct rsa_key_cache_entry)); if (tmp == NULL) { testcase_error("realloc failed to enlarge the RSA key cache"); return CKR_HOST_MEMORY; } free = &tmp[rsa_key_cache_size]; memset(free, 0, sizeof(*free)); rsa_key_cache = tmp; rsa_key_cache_size++; } free->session = session; free->keygen_mech_type = mech_type; free->modulusBits = modulusBits; free->publicExponent_len = publicExponent_len; free->publicExponent = malloc(publicExponent_len); if (free->publicExponent == NULL) { testcase_error("failed to allocate the public exponent cache entry"); return CKR_HOST_MEMORY; } memcpy(free->publicExponent, publicExponent, publicExponent_len); free->publ_key = *publ_key; free->priv_key = *priv_key; return CKR_OK; } void free_rsa_key_cache(CK_SESSION_HANDLE session) { CK_ULONG i; for (i = 0; i < rsa_key_cache_size; i++) { if (rsa_key_cache[i].session == CK_INVALID_HANDLE) continue; if (session != CK_INVALID_HANDLE && rsa_key_cache[i].session != session) continue; funcs->C_DestroyObject(rsa_key_cache[i].session, rsa_key_cache[i].publ_key); funcs->C_DestroyObject(rsa_key_cache[i].session, rsa_key_cache[i].priv_key); free(rsa_key_cache[i].publicExponent); /* mark as free */ memset(&rsa_key_cache[i], 0, sizeof(rsa_key_cache[i])); } if (session == CK_INVALID_HANDLE) { free(rsa_key_cache); rsa_key_cache = NULL; rsa_key_cache_size = 0; } } /** Generate an EC key pair **/ CK_RV generate_EC_KeyPair(CK_SESSION_HANDLE session, CK_MECHANISM_TYPE keygen_mech, CK_BYTE* ec_params, CK_ULONG ec_params_len, CK_OBJECT_HANDLE * publ_key, CK_OBJECT_HANDLE * priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { keygen_mech, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; const CK_BYTE bls12_381[] = OCK_BLS12_381; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_EC_PARAMS, ec_params, ec_params_len}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_DERIVE, (ec_params_len == sizeof(bls12_381) && memcmp(ec_params, bls12_381, sizeof(bls12_381)) == 0) ? &true : &false, sizeof(CK_BBOOL)}, }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an EC private key using private value 'd' and ec parameter values (alg id of curve) **/ CK_RV create_ECPrivateKey(CK_SESSION_HANDLE session, CK_KEY_TYPE key_type, CK_BYTE params[], CK_ULONG params_len, CK_BYTE privatekey[], CK_ULONG privatekey_len, CK_OBJECT_HANDLE * priv_key, CK_BBOOL extractable, CK_BBOOL derive) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_BBOOL pkeyextractable = !extractable; CK_UTF8CHAR label[] = "An EC private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &derive, sizeof(derive)}, {CKA_EC_PARAMS, params, params_len}, {CKA_VALUE, privatekey, privatekey_len}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; if (combined_extract) pkeyextractable = CK_TRUE; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an EC public key using ec params and point 'Q' **/ CK_RV create_ECPublicKey(CK_SESSION_HANDLE session, CK_KEY_TYPE key_type, CK_BYTE params[], CK_ULONG params_len, CK_BYTE pointq[], CK_ULONG pointq_len, CK_OBJECT_HANDLE * publ_key, CK_BBOOL extractable) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_BBOOL pkeyextractable = !extractable; CK_UTF8CHAR label[] = "An EC public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &key_type, sizeof(key_type)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_EC_PARAMS, params, params_len}, {CKA_EC_POINT, pointq, pointq_len}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, }; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Generate an EC key pair **/ CK_RV generate_Dilithium_KeyPair(CK_SESSION_HANDLE session, CK_ULONG keyform, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_IBM_DILITHIUM, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_IBM_DILITHIUM_KEYFORM, &keyform, sizeof(keyform)}, }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_IBM_DILITHIUM_KEYFORM, &keyform, sizeof(keyform)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an IBM Dilithium private key using private values **/ CK_RV create_DilithiumPrivateKey(CK_SESSION_HANDLE session, CK_BYTE pkcs8[], CK_ULONG pkcs8_len, CK_ULONG keyform, CK_BYTE rho[], CK_ULONG rho_len, CK_BYTE seed[], CK_ULONG seed_len, CK_BYTE tr[], CK_ULONG tr_len, CK_BYTE s1[], CK_ULONG s1_len, CK_BYTE s2[], CK_ULONG s2_len, CK_BYTE t0[], CK_ULONG t0_len, CK_BYTE t1[], CK_ULONG t1_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_IBM_PQC_DILITHIUM; CK_UTF8CHAR label[] = "A Dilithium private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_IBM_DILITHIUM_RHO, rho, rho_len}, {CKA_IBM_DILITHIUM_SEED, seed, seed_len}, {CKA_IBM_DILITHIUM_TR, tr, tr_len}, {CKA_IBM_DILITHIUM_S1, s1, s1_len}, {CKA_IBM_DILITHIUM_S2, s2, s2_len}, {CKA_IBM_DILITHIUM_T0, t0, t0_len}, {CKA_IBM_DILITHIUM_T1, t1, t1_len}, {CKA_IBM_DILITHIUM_KEYFORM, &keyform, sizeof(keyform)}, }; CK_ATTRIBUTE template_pkcs8[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_VALUE, pkcs8, pkcs8_len}, }; // create key if (pkcs8_len > 0) rc = funcs->C_CreateObject(session, template_pkcs8, sizeof(template_pkcs8) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an IBM Dilithium public key using (rho, t1) **/ CK_RV create_DilithiumPublicKey(CK_SESSION_HANDLE session, CK_BYTE spki[], CK_ULONG spki_len, CK_ULONG keyform, CK_BYTE rho[], CK_ULONG rho_len, CK_BYTE t1[], CK_ULONG t1_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_IBM_PQC_DILITHIUM; CK_UTF8CHAR label[] = "A Dilithium public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_IBM_DILITHIUM_RHO, rho, rho_len}, {CKA_IBM_DILITHIUM_T1, t1, t1_len}, {CKA_IBM_DILITHIUM_KEYFORM, &keyform, sizeof(keyform)}, }; CK_ATTRIBUTE template_spki[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_VALUE, spki, spki_len}, }; // create key if (spki_len > 0) rc = funcs->C_CreateObject(session, template_spki, sizeof(template_spki) / sizeof(CK_ATTRIBUTE), publ_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an IBM Kyber private key using private values **/ CK_RV create_KyberPrivateKey(CK_SESSION_HANDLE session, CK_BYTE pkcs8[], CK_ULONG pkcs8_len, CK_ULONG keyform, CK_BYTE sk[], CK_ULONG sk_len, CK_BYTE pk[], CK_ULONG pk_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_IBM_PQC_KYBER; CK_UTF8CHAR label[] = "A Kyber private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_KYBER_SK, sk, sk_len}, {CKA_IBM_KYBER_PK, pk, pk_len}, {CKA_IBM_KYBER_KEYFORM, &keyform, sizeof(keyform)}, }; CK_ATTRIBUTE template_pkcs8[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_VALUE, pkcs8, pkcs8_len}, }; // create key if (pkcs8_len > 0) rc = funcs->C_CreateObject(session, template_pkcs8, sizeof(template_pkcs8) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an IBM Kyber public key using public values **/ CK_RV create_KyberPublicKey(CK_SESSION_HANDLE session, CK_BYTE spki[], CK_ULONG spki_len, CK_ULONG keyform, CK_BYTE pk[], CK_ULONG pk_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_IBM_PQC_KYBER; CK_UTF8CHAR label[] = "A Kyber public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_KYBER_PK, pk, pk_len}, {CKA_IBM_KYBER_KEYFORM, &keyform, sizeof(keyform)}, }; CK_ATTRIBUTE template_spki[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_VALUE, spki, spki_len}, }; // create key if (spki_len > 0) rc = funcs->C_CreateObject(session, template_spki, sizeof(template_spki) / sizeof(CK_ATTRIBUTE), publ_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } CK_RV generate_IBM_ML_DSA_KeyPair(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_IBM_ML_DSA_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an IBM ML-DSA private key using private values **/ CK_RV create_IBM_ML_DSA_PrivateKey(CK_SESSION_HANDLE session, CK_BYTE pkcs8[], CK_ULONG pkcs8_len, CK_ULONG parameter_set, CK_BYTE rho[], CK_ULONG rho_len, CK_BYTE seed[], CK_ULONG seed_len, CK_BYTE tr[], CK_ULONG tr_len, CK_BYTE s1[], CK_ULONG s1_len, CK_BYTE s2[], CK_ULONG s2_len, CK_BYTE t0[], CK_ULONG t0_len, CK_BYTE t1[], CK_ULONG t1_len, CK_BYTE priv_seed[], CK_ULONG priv_seed_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_IBM_ML_DSA; CK_UTF8CHAR label[] = "A IBM ML-DSA private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_IBM_ML_DSA_RHO, rho, rho_len}, {CKA_IBM_ML_DSA_SEED, seed, seed_len}, {CKA_IBM_ML_DSA_TR, tr, tr_len}, {CKA_IBM_ML_DSA_S1, s1, s1_len}, {CKA_IBM_ML_DSA_S2, s2, s2_len}, {CKA_IBM_ML_DSA_T0, t0, t0_len}, {CKA_IBM_ML_DSA_T1, t1, t1_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_pkcs8[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_VALUE, pkcs8, pkcs8_len}, }; CK_ATTRIBUTE template_seed[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_IBM_ML_DSA_PRIVATE_SEED, priv_seed, priv_seed_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; // create key if (pkcs8_len > 0) rc = funcs->C_CreateObject(session, template_pkcs8, sizeof(template_pkcs8) / sizeof(CK_ATTRIBUTE), priv_key); else if (priv_seed_len > 0) rc = funcs->C_CreateObject(session, template_seed, sizeof(template_seed) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an IBM ML-DSA public key using (rho, t1) **/ CK_RV create_IBM_ML_DSA_PublicKey(CK_SESSION_HANDLE session, CK_BYTE spki[], CK_ULONG spki_len, CK_ULONG parameter_set, CK_BYTE rho[], CK_ULONG rho_len, CK_BYTE t1[], CK_ULONG t1_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_IBM_ML_DSA; CK_UTF8CHAR label[] = "A IBM ML-DSA public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_IBM_ML_DSA_RHO, rho, rho_len}, {CKA_IBM_ML_DSA_T1, t1, t1_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_spki[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_VALUE, spki, spki_len}, }; // create key if (spki_len > 0) rc = funcs->C_CreateObject(session, template_spki, sizeof(template_spki) / sizeof(CK_ATTRIBUTE), publ_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } CK_RV generate_IBM_ML_KEM_KeyPair(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_IBM_ML_KEM_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an IBM ML-KEM private key using private values **/ CK_RV create_IBM_ML_KEM_PrivateKey(CK_SESSION_HANDLE session, CK_BYTE pkcs8[], CK_ULONG pkcs8_len, CK_ULONG parameter_set, CK_BYTE sk[], CK_ULONG sk_len, CK_BYTE pk[], CK_ULONG pk_len, CK_BYTE priv_seed[], CK_ULONG priv_seed_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_IBM_ML_KEM; CK_UTF8CHAR label[] = "A IBM ML-KEM private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_ML_KEM_SK, sk, sk_len}, {CKA_IBM_ML_KEM_PK, pk, pk_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_pkcs8[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_VALUE, pkcs8, pkcs8_len}, }; CK_ATTRIBUTE template_seed[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_ML_KEM_PRIVATE_SEED, priv_seed, priv_seed_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; // create key if (pkcs8_len > 0) rc = funcs->C_CreateObject(session, template_pkcs8, sizeof(template_pkcs8) / sizeof(CK_ATTRIBUTE), priv_key); else if (priv_seed_len > 0) rc = funcs->C_CreateObject(session, template_seed, sizeof(template_seed) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an IBM ML-KEM public key using **/ CK_RV create_IBM_ML_KEM_PublicKey(CK_SESSION_HANDLE session, CK_BYTE spki[], CK_ULONG spki_len, CK_ULONG parameter_set, CK_BYTE pk[], CK_ULONG pk_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_IBM_ML_KEM; CK_UTF8CHAR label[] = "A IBM ML-KEM public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_IBM_ML_KEM_PK, pk, pk_len}, {CKA_IBM_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_spki[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_VALUE, spki, spki_len}, }; // create key if (spki_len > 0) rc = funcs->C_CreateObject(session, template_spki, sizeof(template_spki) / sizeof(CK_ATTRIBUTE), publ_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } CK_RV generate_ML_DSA_KeyPair(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_ML_DSA_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_VERIFY, &true, sizeof(true)}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an ML-DSA private key using private values **/ CK_RV create_ML_DSA_PrivateKey(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_BYTE value[], CK_ULONG value_len, CK_BYTE priv_seed[], CK_ULONG priv_seed_len, CK_OBJECT_HANDLE * priv_key, CK_BBOOL is_cca_token, CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE cca_ml_dsa_mode) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_ML_DSA; CK_UTF8CHAR label[] = "A ML-DSA private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_VALUE, value, value_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, {CKA_IBM_CCA_ML_DSA_KEY_MODE, &cca_ml_dsa_mode, sizeof(cca_ml_dsa_mode)}, }; CK_ULONG num_attrs = sizeof(template) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE template_seed[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_SEED, priv_seed, priv_seed_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, {CKA_IBM_CCA_ML_DSA_KEY_MODE, &cca_ml_dsa_mode, sizeof(cca_ml_dsa_mode)}, }; CK_ULONG num_seed_attrs = sizeof(template_seed) / sizeof(CK_ATTRIBUTE); if (!is_cca_token) { num_attrs--; num_seed_attrs--; } // create key if (priv_seed_len > 0) rc = funcs->C_CreateObject(session, template_seed, num_seed_attrs, priv_key); else rc = funcs->C_CreateObject(session, template, num_attrs, priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an ML-DSA public key **/ CK_RV create_ML_DSA_PublicKey(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_BYTE value[], CK_ULONG value_len, CK_OBJECT_HANDLE * publ_key, CK_BBOOL is_cca_token, CK_IBM_CCA_ML_DSA_KEY_MODE_TYPE cca_ml_dsa_mode) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_ML_DSA; CK_UTF8CHAR label[] = "A ML-DSA public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_VALUE, value, value_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, {CKA_IBM_CCA_ML_DSA_KEY_MODE, &cca_ml_dsa_mode, sizeof(cca_ml_dsa_mode)}, }; CK_ULONG num_attrs = sizeof(template) / sizeof(CK_ATTRIBUTE); if (!is_cca_token) num_attrs--; // create key rc = funcs->C_CreateObject(session, template, num_attrs, publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } CK_RV generate_ML_KEM_KeyPair(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_OBJECT_HANDLE *publ_key, CK_OBJECT_HANDLE *priv_key, CK_BBOOL extractable) { CK_RV rc; CK_MECHANISM mech = { CKM_ML_KEM_KEY_PAIR_GEN, NULL, 0 }; CK_BBOOL pkeyextractable = !extractable; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_ENCAPSULATE, &true, sizeof(true)}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECAPSULATE, &true, sizeof(true)}, {CKA_EXTRACTABLE, &extractable, sizeof(CK_BBOOL)}, {CKA_IBM_PROTKEY_EXTRACTABLE, &pkeyextractable, sizeof(CK_BBOOL)}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ULONG num_publ_attrs = sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE); CK_ULONG num_priv_attrs = sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE); if (combined_extract) pkeyextractable = CK_TRUE; // generate keys rc = funcs->C_GenerateKeyPair(session, &mech, publicKeyTemplate, num_publ_attrs, privateKeyTemplate, num_priv_attrs, publ_key, priv_key); if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; return rc; } /** Create an ML-KEM private key using private values **/ CK_RV create_ML_KEM_PrivateKey(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_BYTE value[], CK_ULONG value_len, CK_BYTE priv_seed[], CK_ULONG priv_seed_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_ML_KEM; CK_UTF8CHAR label[] = "A ML-KEM private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECAPSULATE, &true, sizeof(true)}, {CKA_VALUE, value, value_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; CK_ATTRIBUTE template_seed[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECAPSULATE, &true, sizeof(true)}, {CKA_SEED, priv_seed, priv_seed_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; // create key if (priv_seed_len > 0) rc = funcs->C_CreateObject(session, template_seed, sizeof(template_seed) / sizeof(CK_ATTRIBUTE), priv_key); else rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an ML-KEM public key **/ CK_RV create_ML_KEM_PublicKey(CK_SESSION_HANDLE session, CK_ULONG parameter_set, CK_BYTE value[], CK_ULONG value_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_ML_KEM; CK_UTF8CHAR label[] = "A ML-KEM public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_ENCAPSULATE, &true, sizeof(true)}, {CKA_VALUE, value, value_len}, {CKA_PARAMETER_SET, ¶meter_set, sizeof(parameter_set)}, }; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (rc == CKR_KEY_SIZE_RANGE) testcase_notice("C_CreateObject rc=%s", p11_get_ckr(rc)); else if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an DSA public key using the prime 'p', subprime 'q', base 'g' and private value 'y' **/ CK_RV create_DSAPrivateKey(CK_SESSION_HANDLE session, CK_BYTE prime[], CK_ULONG prime_len, CK_BYTE subprime[], CK_ULONG subprime_len, CK_BYTE base[], CK_ULONG base_len, CK_BYTE privatekey[], CK_ULONG privatekey_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_DSA; CK_UTF8CHAR label[] = "An DSA private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_PRIME, prime, prime_len}, {CKA_SUBPRIME, subprime, subprime_len}, {CKA_BASE, base, base_len}, {CKA_VALUE, privatekey, privatekey_len} }; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an DSA public key using the prime 'p', subprime 'q', base 'g' and public value 'x' **/ CK_RV create_DSAPublicKey(CK_SESSION_HANDLE session, CK_BYTE prime[], CK_ULONG prime_len, CK_BYTE subprime[], CK_ULONG subprime_len, CK_BYTE base[], CK_ULONG base_len, CK_BYTE publickey[], CK_ULONG publickey_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_DSA; CK_UTF8CHAR label[] = "An DSA public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_PRIME, prime, prime_len}, {CKA_SUBPRIME, subprime, subprime_len}, {CKA_BASE, base, base_len}, {CKA_VALUE, publickey, publickey_len} }; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /** Create an DH public key using the prime 'p', base 'g' and private value 'y' **/ CK_RV create_DHPrivateKey(CK_SESSION_HANDLE session, CK_BYTE prime[], CK_ULONG prime_len, CK_BYTE base[], CK_ULONG base_len, CK_BYTE privatekey[], CK_ULONG privatekey_len, CK_OBJECT_HANDLE * priv_key) { CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_DH; CK_UTF8CHAR label[] = "An DH private key object"; CK_BYTE subject[] = {0}; CK_BYTE id[] = { 123 }; CK_RV rc; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_SUBJECT, subject, 0}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_PRIME, prime, prime_len}, {CKA_BASE, base, base_len}, {CKA_VALUE, privatekey, privatekey_len} }; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), priv_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /* Create an DH public key using the prime 'p', base 'g' and public value 'x' */ CK_RV create_DHPublicKey(CK_SESSION_HANDLE session, CK_BYTE prime[], CK_ULONG prime_len, CK_BYTE base[], CK_ULONG base_len, CK_BYTE publickey[], CK_ULONG publickey_len, CK_OBJECT_HANDLE * publ_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_DH; CK_UTF8CHAR label[] = "An DH public key object"; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_PRIME, prime, prime_len}, {CKA_BASE, base, base_len}, {CKA_VALUE, publickey, publickey_len} }; // create key rc = funcs->C_CreateObject(session, template, sizeof(template) / sizeof(CK_ATTRIBUTE), publ_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_error("C_CreateObject rc=%s", p11_get_ckr(rc)); } return rc; } /* Generate a secret key */ CK_RV generate_SecretKey(CK_SESSION_HANDLE session, CK_ULONG keylen, CK_MECHANISM * mech, CK_OBJECT_HANDLE * secret_key) { CK_RV rc; CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_ATTRIBUTE secret_tmpl[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_VALUE_LEN, &keylen, sizeof(keylen)} }; rc = funcs->C_GenerateKey(session, mech, secret_tmpl, 2, secret_key); if (rc != CKR_OK) { if (is_rejected_by_policy(rc, session)) rc = CKR_POLICY_VIOLATION; else testcase_fail("C_GenerateKey, rc=%s", p11_get_ckr(rc)); } return rc; } int keysize_supported(CK_SLOT_ID slot_id, CK_ULONG mechanism, CK_ULONG size) { CK_MECHANISM_INFO mech_info; CK_RV rc; rc = funcs->C_GetMechanismInfo(slot_id, mechanism, &mech_info); if (size < mech_info.ulMinKeySize || size > mech_info.ulMaxKeySize) return 0; return (rc == CKR_OK); } /** Returns true if pubexp is valid for EP11 Tokens **/ int is_valid_ep11_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) { CK_ULONG i; /* everything > 0x10 valid */ if (pubexp[0] > 0x10) { return 1; } else { for (i = 1; i < pubexp_len + 1; i++) { if (pubexp[i] != 0) return 1; } } return 0; } /** Returns true if slot_id is an EP11 Token **/ int is_ep11_token(CK_SLOT_ID slot_id) { CK_RV rc; CK_TOKEN_INFO tokinfo; rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); if (rc != CKR_OK) return FALSE; return strstr((const char *) tokinfo.model, "EP11") != NULL; } /** Returns true if pubexp is valid for CCA Tokens **/ int is_valid_cca_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) { CK_BYTE exp3[] = { 0x03 }; // 3 CK_BYTE exp5[] = { 0x05 }; // 5 CK_BYTE exp17[] = { 0x11 }; // 17 CK_BYTE exp257[] = { 0x01, 0x01 }; // 257 CK_BYTE exp65537[] = { 0x01, 0x00, 0x01 }; // 65537 // trim any leading zero bytes while (pubexp_len > 1 && pubexp[0] == 0x00) { pubexp++; pubexp_len--; } return (pubexp_len == 1 && (!memcmp(pubexp, exp3, 1))) || (pubexp_len == 1 && (!memcmp(pubexp, exp5, 1))) || (pubexp_len == 1 && (!memcmp(pubexp, exp17, 1))) || (pubexp_len == 2 && (!memcmp(pubexp, exp257, 2))) || (pubexp_len == 3 && (!memcmp(pubexp, exp65537, 3))); } /** Returns true if pubexp is valid for Soft Tokens **/ int is_valid_soft_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) { UNUSED(pubexp); UNUSED(pubexp_len); return TRUE; } /** Returns true if slot_id is an ICSF token ** ICSF token info is not necessarily hard-coded like the other tokens ** so there is no single identifying attribute. So, instead just ** use logical deduction.... **/ int is_icsf_token(CK_SLOT_ID slot_id) { CK_RV rc; CK_TOKEN_INFO tokinfo; rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); if (rc != CKR_OK) return FALSE; if ((strstr((const char *) tokinfo.model, "ICA") == NULL) && (strstr((const char *) tokinfo.model, "EP11") == NULL) && (strstr((const char *) tokinfo.model, "CCA") == NULL) && (strstr((const char *) tokinfo.model, "Soft") == NULL) && (strstr((const char *) tokinfo.model, "TPM") == NULL)) return TRUE; return FALSE; } /** Returns true if pubexp is valid for ICSF token **/ int is_valid_icsf_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) { CK_BYTE exp65537[] = { 0x01, 0x00, 0x01 }; // 65537 return (pubexp_len == 3 && (!memcmp(pubexp, exp65537, 3))); } /** Returns true if slot_id is an ICA Token **/ int is_ica_token(CK_SLOT_ID slot_id) { CK_RV rc; CK_TOKEN_INFO tokinfo; rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); if (rc != CKR_OK) return FALSE; return strstr((const char *) tokinfo.model, "ICA") != NULL; } /** Returns true if slot_id is a CCA Token **/ int is_cca_token(CK_SLOT_ID slot_id) { CK_RV rc; CK_TOKEN_INFO tokinfo; rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); if (rc != CKR_OK) return FALSE; return strstr((const char *) tokinfo.model, "CCA") != NULL; } /** Returns true if slot_id is a Soft Token **/ int is_soft_token(CK_SLOT_ID slot_id) { CK_RV rc; CK_TOKEN_INFO tokinfo; rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); if (rc != CKR_OK) return FALSE; return strstr((const char *) tokinfo.model, "Soft") != NULL; } /** Returns true if slot_id is a TPM Token **/ int is_tpm_token(CK_SLOT_ID slot_id) { CK_RV rc; CK_TOKEN_INFO tokinfo; rc = funcs->C_GetTokenInfo(slot_id, &tokinfo); if (rc != CKR_OK) return FALSE; return strstr((const char *) tokinfo.model, "TPM") != NULL; } /** Returns true if pubexp is valid for CCA Tokens **/ int is_valid_tpm_pubexp(CK_BYTE pubexp[], CK_ULONG pubexp_len) { CK_BYTE exp65537[] = { 0x01, 0x00, 0x01 }; // 65537 return (pubexp_len == 3 && (!memcmp(pubexp, exp65537, 3))); } int is_valid_tpm_modbits(CK_ULONG modbits) { switch (modbits) { case 512: case 1024: case 2048: return 1; default: return 0; } } int get_so_pin(CK_BYTE * dest) { char *val; val = getenv(PKCS11_SO_PIN_ENV_VAR); if (val == NULL) { fprintf(stderr, "The environment variable %s must be set " "before this testcase is run.\n", PKCS11_SO_PIN_ENV_VAR); return -1; } if ((strlen(val) + 1) > PKCS11_MAX_PIN_LEN) { fprintf(stderr, "The environment variable %s must hold a " "value less than %d chars in length.\n", PKCS11_SO_PIN_ENV_VAR, (int) PKCS11_MAX_PIN_LEN); return -1; } memcpy(dest, val, strlen(val) + 1); return 0; } int get_user_pin(CK_BYTE * dest) { char *val; val = getenv(PKCS11_USER_PIN_ENV_VAR); if (val == NULL) { fprintf(stderr, "The environment variable %s must be set " "before this testcase is run.\n", PKCS11_USER_PIN_ENV_VAR); return -1; } if ((strlen(val) + 1) > PKCS11_MAX_PIN_LEN) { fprintf(stderr, "The environment variable %s must hold a " "value less than %d chars in length.\n", PKCS11_SO_PIN_ENV_VAR, (int) PKCS11_MAX_PIN_LEN); return -1; } memcpy(dest, val, strlen(val) + 1); return 0; } void process_time(SYSTEMTIME t1, SYSTEMTIME t2) { long ms = (t2.tv_usec - t1.tv_usec) / 1000; long s = t2.tv_sec - t1.tv_sec; while (ms < 0) { ms += 1000; s--; } ms += (s * 1000); printf("Time: %u msec\n", (unsigned int) ms); } // // void print_hex(CK_BYTE * buf, CK_ULONG len) { CK_ULONG i, j; i = 0; while (i < len) { for (j = 0; (j < 16) && (i < len); j++, i++) fprintf(stderr, "%02x ", buf[i]); fprintf(stderr, "\n"); } fprintf(stderr, "\n"); } void usage(char *fct) { printf("usage: %s [-securekey] [-noskip] [-noinit] [-combined-extract] " "[-rsa8k] [-h] -slot \n\n", fct); return; } int do_ParseArgs(int argc, char **argv) { int i; char *endp; skip_token_obj = TRUE; no_stop = FALSE; no_init = FALSE; securekey = FALSE; SLOT_ID = 1000; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { usage(argv[0]); return 0; } else if (strcmp(argv[i], "-noskip") == 0) { skip_token_obj = FALSE; } else if (strcmp(argv[i], "-slot") == 0) { if (argc <= i + 1) { printf("No slot number specified\n"); usage(argv[0]); return -1; } SLOT_ID = strtol(argv[i + 1], &endp, 10); if (*endp != '\0') { printf("Invalid slot number specified: %s\n", argv[i + 1]); usage(argv[0]); return -1; } i++; } else if (strcmp(argv[i], "-securekey") == 0) { securekey = TRUE; } else if (strcmp(argv[i], "-noinit") == 0) { no_init = TRUE; } else if (strcmp(argv[i], "-nostop") == 0) { no_stop = TRUE; } else if (strcmp(argv[i], "-combined-extract") == 0) { combined_extract = TRUE; } else if (strcmp(argv[i], "-rsa8k") == 0) { rsa8k = TRUE; } else { printf("Invalid argument passed as option: %s\n", argv[i]); usage(argv[0]); return -1; } } // error if slot has not been identified. if (SLOT_ID == 1000) { printf("Please specify the slot to be tested.\n"); usage(argv[0]); return -1; } return 1; } // // CK_BBOOL do_GetFunctionList(void) { CK_INTERFACE *interface; CK_VERSION version; CK_FLAGS flags; CK_BBOOL rv; CK_RV rc; CK_RV(*getfunclist)(CK_FUNCTION_LIST **funcs); CK_RV(*getinterfacelist)(CK_INTERFACE_PTR interfaces, CK_ULONG *count); CK_RV(*getinterface)(CK_UTF8CHAR_PTR name, CK_VERSION_PTR version, CK_INTERFACE_PTR_PTR interface, CK_FLAGS flags); char *e; char *f = OCK_API_LIBNAME; CK_ULONG nmemb = 0; rv = FALSE; e = getenv("PKCSLIB"); if (e == NULL) e = f; pkcs11lib = dlopen(e, DYNLIB_LDFLAGS); if (pkcs11lib == NULL) goto ret; *(void **)(&getfunclist) = dlsym(pkcs11lib, "C_GetFunctionList"); if (getfunclist == NULL) goto ret; rc = getfunclist(&funcs); if (rc != CKR_OK) { testcase_error("C_GetFunctionList rc=%s", p11_get_ckr(rc)); goto ret; } *(void **)(&getinterfacelist) = dlsym(pkcs11lib, "C_GetInterfaceList"); if (getinterfacelist == NULL) { goto ret; } rc = getinterfacelist(NULL, &nmemb); if (rc != CKR_OK) { testcase_error("C_GetInterfaceList rc=%s", p11_get_ckr(rc)); goto ret; } ifs = calloc(nmemb, sizeof(*ifs)); if (ifs == NULL) { goto ret; } rc = getinterfacelist(ifs, &nmemb); if (rc != CKR_OK) { testcase_error("C_GetInterfaceList rc=%s", p11_get_ckr(rc)); goto ret; } *(void **)(&getinterface) = dlsym(pkcs11lib, "C_GetInterface"); if (getinterface == NULL) { goto ret; } version.major = 0x03; version.minor = 0x00; flags = 0; rc = getinterface((CK_UTF8CHAR *)"PKCS 11", &version, &interface, flags); if (rc != CKR_OK) { testcase_error("C_GetInterface (v3.0) rc=%s", p11_get_ckr(rc)); goto ret; } funcs3 = interface->pFunctionList; version.major = 0x03; version.minor = 0x02; flags = 0; rc = getinterface((CK_UTF8CHAR *)"PKCS 11", &version, &interface, flags); if (rc != CKR_OK) { testcase_error("C_GetInterface (v3.2) rc=%s", p11_get_ckr(rc)); goto ret; } funcs3_2 = interface->pFunctionList; rv = TRUE; ret: if (rv == TRUE) { atexit(free_ifs); atexit(unload_pkcslib); } else { free(ifs); ifs = NULL; if (pkcs11lib != NULL) { #ifndef WITH_SANITIZER dlclose(pkcs11lib); #endif pkcs11lib = NULL; } } return rv; } /* * Unwraps wrapped_data under unwrapping_key with base_tmpl plus each * combination of CKA_SENSITIVE and CKA_EXTRACTABLE, and once with neither, and * checks every new key: * - CKA_SENSITIVE and CKA_EXTRACTABLE have the values the template asked for; * when it does not specify them, any value is accepted, since the defaults * are token specific (EP11 and CCA default CKA_SENSITIVE to TRUE for * private keys, and for secret keys with FORCE_SENSITIVE); * - when forced_sensitive or forced_extractable is not NULL, the unwrapping * key's CKA_UNWRAP_TEMPLATE sets that attribute to the value it points to: * a key unwrapped without the attribute gets that value, and a template * asking for the other value fails with CKR_TEMPLATE_INCONSISTENT; * - CKA_ALWAYS_SENSITIVE and CKA_NEVER_EXTRACTABLE are FALSE, as for any * unwrapped key (not checked on ICSF, which unwraps on the ICSF server and * takes these attributes from it); * - secret_attr (CKA_VALUE, or CKA_PRIVATE_EXPONENT for RSA) cannot be read * from a sensitive key. * base_tmpl must not contain CKA_SENSITIVE or CKA_EXTRACTABLE. Records one * assertion per combination. */ CK_RV check_unwrap_sensitive_extractable(CK_SESSION_HANDLE session, CK_MECHANISM *mech, CK_OBJECT_HANDLE unwrapping_key, CK_BYTE *wrapped_data, CK_ULONG wrapped_data_len, CK_ATTRIBUTE *base_tmpl, CK_ULONG base_count, CK_ATTRIBUTE_TYPE secret_attr, const CK_BBOOL *forced_sensitive, const CK_BBOOL *forced_extractable) { static const struct { CK_BBOOL given, sensitive, extractable; } cases[] = { { CK_FALSE, CK_FALSE, CK_FALSE }, /* not given: token defaults */ { CK_TRUE, CK_TRUE, CK_FALSE }, { CK_TRUE, CK_TRUE, CK_TRUE }, { CK_TRUE, CK_FALSE, CK_FALSE }, { CK_TRUE, CK_FALSE, CK_TRUE }, }; CK_ATTRIBUTE tmpl[32]; CK_ULONG i, count; CK_RV rc, rc2; if (base_count + 2 > sizeof(tmpl) / sizeof(tmpl[0])) return CKR_ARGUMENTS_BAD; for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { CK_BBOOL sensitive = cases[i].sensitive; CK_BBOOL extractable = cases[i].extractable; CK_BBOOL conflict = cases[i].given && ((forced_sensitive != NULL && sensitive != *forced_sensitive) || (forced_extractable != NULL && extractable != *forced_extractable)); /* without the attributes in the template, only a forced value is * checked */ CK_BBOOL check_sens = cases[i].given || forced_sensitive != NULL; CK_BBOOL check_extr = cases[i].given || forced_extractable != NULL; CK_BBOOL got_sens = 0xFF, got_extr = 0xFF; CK_BBOOL got_always_sens = 0xFF, got_never_extr = 0xFF; CK_ATTRIBUTE flags[] = { {CKA_SENSITIVE, &got_sens, sizeof(got_sens)}, {CKA_EXTRACTABLE, &got_extr, sizeof(got_extr)}, {CKA_ALWAYS_SENSITIVE, &got_always_sens, sizeof(got_always_sens)}, {CKA_NEVER_EXTRACTABLE, &got_never_extr, sizeof(got_never_extr)}, }; CK_ATTRIBUTE secret = {secret_attr, NULL, 0}; CK_OBJECT_HANDLE key = CK_INVALID_HANDLE; char desc[64]; memcpy(tmpl, base_tmpl, base_count * sizeof(CK_ATTRIBUTE)); count = base_count; if (cases[i].given) { tmpl[count].type = CKA_SENSITIVE; tmpl[count].pValue = &sensitive; tmpl[count++].ulValueLen = sizeof(sensitive); tmpl[count].type = CKA_EXTRACTABLE; tmpl[count].pValue = &extractable; tmpl[count++].ulValueLen = sizeof(extractable); snprintf(desc, sizeof(desc), "CKA_SENSITIVE=%s CKA_EXTRACTABLE=%s", sensitive ? "TRUE" : "FALSE", extractable ? "TRUE" : "FALSE"); } else { snprintf(desc, sizeof(desc), "neither attribute"); } if (forced_sensitive != NULL && !cases[i].given) sensitive = *forced_sensitive; if (forced_extractable != NULL && !cases[i].given) extractable = *forced_extractable; rc = funcs->C_UnwrapKey(session, mech, unwrapping_key, wrapped_data, wrapped_data_len, tmpl, count, &key); if (conflict) { testcase_new_assertion(); if (rc == CKR_TEMPLATE_INCONSISTENT) { testcase_pass("Unwrap template with %s conflicts with the " "unwrapping key's CKA_UNWRAP_TEMPLATE and was " "refused.", desc); continue; } testcase_fail("Unwrap template with %s conflicts with the " "unwrapping key's CKA_UNWRAP_TEMPLATE, but " "C_UnwrapKey returned %s, expected " "CKR_TEMPLATE_INCONSISTENT.", desc, p11_get_ckr(rc)); if (rc == CKR_OK) funcs->C_DestroyObject(session, key); return CKR_GENERAL_ERROR; } if (rc != CKR_OK) { testcase_new_assertion(); testcase_error("C_UnwrapKey with %s rc=%s", desc, p11_get_ckr(rc)); return rc; } testcase_new_assertion(); rc = funcs->C_GetAttributeValue(session, key, flags, 4); if (rc != CKR_OK) { testcase_error("C_GetAttributeValue rc=%s", p11_get_ckr(rc)); } else if ((got_sens != CK_TRUE && got_sens != CK_FALSE) || (got_extr != CK_TRUE && got_extr != CK_FALSE) || (check_sens && got_sens != sensitive) || (check_extr && got_extr != extractable)) { testcase_fail("Unwrap template with %s gave a key with " "CKA_SENSITIVE=%u CKA_EXTRACTABLE=%u, expected " "%s and %s.", desc, got_sens, got_extr, !check_sens ? "either" : sensitive ? "1" : "0", !check_extr ? "either" : extractable ? "1" : "0"); rc = CKR_GENERAL_ERROR; } else if (!is_icsf_token(SLOT_ID) && (got_always_sens != CK_FALSE || got_never_extr != CK_FALSE)) { testcase_fail("Unwrap template with %s gave a key with " "CKA_ALWAYS_SENSITIVE=%u CKA_NEVER_EXTRACTABLE=%u, " "expected FALSE for an unwrapped key.", desc, got_always_sens, got_never_extr); rc = CKR_GENERAL_ERROR; } else if (got_sens && (rc2 = funcs->C_GetAttributeValue(session, key, &secret, 1)) != CKR_ATTRIBUTE_SENSITIVE && (!is_icsf_token(SLOT_ID) || rc2 != CKR_ATTRIBUTE_TYPE_INVALID)) { testcase_fail("Unwrap template with %s: reading the key value " "returned %s, expected CKR_ATTRIBUTE_SENSITIVE.", desc, p11_get_ckr(rc2)); rc = CKR_GENERAL_ERROR; } else { testcase_pass("Unwrap template with %s gave a key with " "CKA_SENSITIVE=%u CKA_EXTRACTABLE=%u, as expected.", desc, got_sens, got_extr); } rc2 = funcs->C_DestroyObject(session, key); if (rc2 != CKR_OK) testcase_error("C_DestroyObject rc=%s.", p11_get_ckr(rc2)); if (rc != CKR_OK) return rc; } return CKR_OK; }