diff --git a/doc/dox_comments/header_files/pkcs11.h b/doc/dox_comments/header_files/pkcs11.h index 7871ab43317..ccc97ed5056 100644 --- a/doc/dox_comments/header_files/pkcs11.h +++ b/doc/dox_comments/header_files/pkcs11.h @@ -45,6 +45,34 @@ int wc_Pkcs11Token_Open(Pkcs11Token* token, int readWrite); */ void wc_Pkcs11Token_Close(Pkcs11Token* token); +/*! + \ingroup PKCS11 + + \brief Makes the crypto callback generate RSA, ECC, ML-DSA and ML-KEM + keys that have an id or label as token objects (CKA_TOKEN set). + + Use it for tokens that cannot make a session key persistent later with + wc_Pkcs11PersistKey. The public key is kept as a token object too. Key + generation fails with BAD_STATE_E when a token key of the type already + has the id or label. A key without a name, such as a TLS ephemeral key, + stays a session object, or is generated in software when no session + from wc_Pkcs11Token_Open is open. + + The private key gets CKA_PRIVATE, so the session must be logged in, and + a session from wc_Pkcs11Token_Open must be read/write. Without such a + session a token key is later found by its id or label. + + \return 0 on success. + \return BAD_FUNC_ARG when token is NULL. + + \param token Token used by the crypto callback. + \param persistent Generate token objects when non-zero. + + \sa wc_Pkcs11PersistKey + \sa wc_Pkcs11DeleteKey +*/ +int wc_Pkcs11Token_SetKeyGenPersistent(Pkcs11Token* token, int persistent); + /*! \ingroup PKCS11 @@ -59,7 +87,7 @@ void wc_Pkcs11Token_Close(Pkcs11Token* token); stored too. \return 0 on success. - \return BAD_FUNC_ARG when token is NULL. + \return BAD_FUNC_ARG when token or key is NULL. \return BAD_STATE_E when no session was opened with wc_Pkcs11Token_Open. \return MEMORY_E when memory allocation fails. \return NOT_COMPILED_IN when the key type is not supported, or the token @@ -77,6 +105,114 @@ void wc_Pkcs11Token_Close(Pkcs11Token* token); int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key); +/*! + \ingroup PKCS11 + + \brief Stores a private key on the token like wc_Pkcs11StoreKey. With + persistent set, the objects are created with CKA_TOKEN set and stay on + the token after the session closes; this needs a read/write session and + a logged in token, but not wc_Pkcs11Token_Open. A persistent private or + secret key also gets CKA_PRIVATE and CKA_SENSITIVE set and + CKA_EXTRACTABLE cleared, and needs an id or label that no token key of + the type has, or the call fails with BAD_FUNC_ARG or BAD_STATE_E. + + \return 0 on success. + \return BAD_FUNC_ARG when token or key is NULL, or a persistent key has + neither id nor label. + \return BAD_STATE_E when persistent is 0 and no session was opened with + wc_Pkcs11Token_Open, or a token key of the type already has the + persistent key's id or label. + \return MEMORY_E when a memory allocation fails. + \return NOT_COMPILED_IN when the key type or mechanism is not available. + \return WC_HW_E when a PKCS#11 call fails. + + \param token Token to store the key on. + \param type One of the PKCS11_KEY_TYPE_* values. + \param clear Clear the private key data from the software key. + \param key Key object of the type. + \param persistent Store the key as token objects when non-zero. + + \sa wc_Pkcs11StoreKey +*/ +int wc_Pkcs11StoreKey_ex(Pkcs11Token* token, int type, int clear, + void* key, int persistent); + +/*! + \ingroup PKCS11 + + \brief Makes a private or secret key that lives in a session object + persistent. The session object, from key generation or wc_Pkcs11StoreKey, + is copied with C_CopyObject to a token object with the key's id and label + and then destroyed. RSA, ECC, ML-DSA and ML-KEM keys that hold their + public key also get a token object with the public key, which for ECC, + ML-DSA and ML-KEM replaces any session public key with the same names. An + ECC, ML-DSA or ML-KEM key without its public key gets a token copy of that + session public key instead. As in wc_Pkcs11StoreKey_ex, an ECC public key + is stored only when the token has ECDSA, and is left out when it cannot be + created for a key that cannot sign. RSA, ECC, ML-DSA and ML-KEM keys refer + to the new private object through devCtx. Freeing the key does not remove + token objects. The token session must be read/write and logged in, and + stay open from key generation until this call. + + \return 0 on success. + \return BAD_FUNC_ARG when token or key is NULL, the key has neither an + id nor a label, or an Hmac has no hash type. + \return BAD_STATE_E when the token already holds a key with the same id + or label, or the key already refers to a token object. + \return NOT_COMPILED_IN when the key type is not supported. + \return WC_HW_E when no session object is found or a PKCS#11 call fails. + + \param token Token holding the key. + \param type PKCS11_KEY_TYPE_RSA, PKCS11_KEY_TYPE_EC, PKCS11_KEY_TYPE_MLDSA, + PKCS11_KEY_TYPE_MLKEM, PKCS11_KEY_TYPE_AES_GCM, PKCS11_KEY_TYPE_AES_CBC + or PKCS11_KEY_TYPE_HMAC. + \param key RsaKey, ecc_key, wc_MlDsaKey, MlKemKey, Aes or Hmac with an id + or label. An Hmac needs its hash type (macType), as wc_HmacSetKey sets. + + _Example_ + \code + ecc_key key; + wc_ecc_init_id(&key, id, idLen, NULL, devId); + wc_ecc_make_key_ex(&rng, 32, &key, ECC_SECP256R1); + // use the key, for example to sign a CSR, then keep it + wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key); + \endcode + + \sa wc_Pkcs11StoreKey_ex +*/ +int wc_Pkcs11PersistKey(Pkcs11Token* token, int type, void* key); + +/*! + \ingroup PKCS11 + + \brief Removes a key from the token: every token object of the key type + with the key's id and label is destroyed. The user must be logged in to + see private objects. For RSA, ECC, ML-DSA and ML-KEM keys a session + object in devCtx is destroyed as well and devCtx is cleared; when a + PKCS#11 call fails part way, devCtx is kept only while its object still + exists. An HMAC key is removed under its HMAC key type and as a generic + secret. Finding nothing to remove is not an error. A token key with only + the same id or only the same label is kept, and still keeps a new key + from using that id or label. + + \return 0 on success. + \return BAD_FUNC_ARG when token or key is NULL, the key has neither an + id nor a label, or an Hmac has no hash type. + \return BAD_STATE_E when the user is not logged in. + \return NOT_COMPILED_IN when the key type is not supported. + \return WC_HW_E when a PKCS#11 call fails. + + \param token Token holding the key. + \param type PKCS11_KEY_TYPE_RSA, PKCS11_KEY_TYPE_EC, PKCS11_KEY_TYPE_MLDSA, + PKCS11_KEY_TYPE_MLKEM, PKCS11_KEY_TYPE_AES_GCM, PKCS11_KEY_TYPE_AES_CBC + or PKCS11_KEY_TYPE_HMAC. + \param key RsaKey, ecc_key, wc_MlDsaKey, MlKemKey, Aes or Hmac with an id + or label. An Hmac needs its hash type (macType), as wc_HmacSetKey sets. + + \sa wc_Pkcs11PersistKey +*/ +int wc_Pkcs11DeleteKey(Pkcs11Token* token, int type, void* key); + /*! \ingroup PKCS11 */ diff --git a/tests/api/test_pkcs11.c b/tests/api/test_pkcs11.c index 09e54e79385..00a644b5339 100644 --- a/tests/api/test_pkcs11.c +++ b/tests/api/test_pkcs11.c @@ -279,6 +279,15 @@ int test_wc_Pkcs11_EcdsaSigDecode(void) defined(HAVE_ECC_KEY_EXPORT) && defined(HAVE_ECC_DHE) #define TEST_PKCS11_EC_KEYGEN #endif +#if defined(WOLFSSL_HAVE_MLDSA) && !defined(NO_PKCS11_MLDSA) && \ + !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && !defined(WOLFSSL_NO_ML_DSA_44) + #define TEST_PKCS11_MLDSA_44 +#endif +#if defined(WOLFSSL_HAVE_MLKEM) && !defined(NO_PKCS11_MLKEM) && \ + !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && !defined(WOLFSSL_NO_ML_KEM) && \ + !defined(WOLFSSL_NO_ML_KEM_768) + #define TEST_PKCS11_MLKEM_768 +#endif #define TEST_PKCS11_MAX_OBJS 8 #define TEST_PKCS11_MAX_ID_LEN 32 @@ -296,6 +305,9 @@ typedef struct TestPkcs11Obj { CK_BBOOL sign; CK_BBOOL derive; CK_BBOOL decrypt; + CK_BBOOL isPrivate; + CK_BBOOL sensitive; + CK_BBOOL extractable; } TestPkcs11Obj; static const byte test_pkcs11_modulus[256] = { 0xc0, 0x01 }; @@ -314,11 +326,22 @@ static int test_pkcs11_fail_pub_create = 0; static int test_pkcs11_no_ecdh = 0; static int test_pkcs11_no_ecdsa = 0; static int test_pkcs11_ecdsa_verify_only = 0; +static int test_pkcs11_no_hmac_type = 0; +static CK_OBJECT_HANDLE test_pkcs11_sign_key = 0; +static int test_pkcs11_fail_copy = 0; +static int test_pkcs11_fail_destroy = 0; +static int test_pkcs11_fail_destroy_at = 0; +static int test_pkcs11_fail_session_info = 0; +static byte test_pkcs11_pq_pub[2600]; +static CK_ULONG test_pkcs11_pq_pub_len = 0; +static CK_ULONG test_pkcs11_pq_param = 0; static int test_pkcs11_fail_modulus = 0; static int test_pkcs11_fail_keygen = 0; +static int test_pkcs11_session_no_point = 0; static byte test_pkcs11_ec_point[2 + 65]; static TestPkcs11Obj test_pkcs11_last_priv; static const byte test_pkcs11_secret[32] = { 0x5a, 0x5a }; +static CK_STATE test_pkcs11_session_state = CKS_RW_USER_FUNCTIONS; #define TEST_PKCS11_FIND_CLASS 0x01 #define TEST_PKCS11_FIND_TYPE 0x02 @@ -330,9 +353,11 @@ static void test_pkcs11_reset(void) { XMEMSET(test_pkcs11_objs, 0, sizeof(test_pkcs11_objs)); test_pkcs11_destroy_calls = 0; + test_pkcs11_fail_destroy_at = 0; test_pkcs11_fail_pub_create = 0; test_pkcs11_fail_modulus = 0; test_pkcs11_fail_keygen = 0; + test_pkcs11_session_no_point = 0; } static TestPkcs11Obj* test_pkcs11_obj(CK_OBJECT_HANDLE h) @@ -356,6 +381,26 @@ static int test_pkcs11_count(CK_BBOOL onToken) } #endif +/* 1 when every token private key carries the protecting attributes and no + * public key does. */ +static int test_pkcs11_token_keys_protected(void) +{ + int i; + const TestPkcs11Obj* o; + + for (i = 0; i < TEST_PKCS11_MAX_OBJS; i++) { + o = &test_pkcs11_objs[i]; + if (!o->used || !o->onToken) + continue; + if ((o->cls == CKO_PRIVATE_KEY || o->cls == CKO_SECRET_KEY) && + (!o->isPrivate || !o->sensitive || o->extractable)) + return 0; + if (o->cls == CKO_PUBLIC_KEY && o->isPrivate) + return 0; + } + return 1; +} + /* Applies the template to obj and returns a TEST_PKCS11_FIND_* mask. */ static CK_ULONG test_pkcs11_apply(TestPkcs11Obj* obj, CK_ATTRIBUTE_PTR tmpl, CK_ULONG cnt) @@ -391,6 +436,15 @@ static CK_ULONG test_pkcs11_apply(TestPkcs11Obj* obj, CK_ATTRIBUTE_PTR tmpl, else if (tmpl[i].type == CKA_DECRYPT) { obj->decrypt = *(CK_BBOOL*)tmpl[i].pValue; } + else if (tmpl[i].type == CKA_PRIVATE) { + obj->isPrivate = *(CK_BBOOL*)tmpl[i].pValue; + } + else if (tmpl[i].type == CKA_SENSITIVE) { + obj->sensitive = *(CK_BBOOL*)tmpl[i].pValue; + } + else if (tmpl[i].type == CKA_EXTRACTABLE) { + obj->extractable = *(CK_BBOOL*)tmpl[i].pValue; + } else if (tmpl[i].type == CKA_LABEL && tmpl[i].ulValueLen <= TEST_PKCS11_MAX_ID_LEN) { XMEMCPY(obj->label, tmpl[i].pValue, tmpl[i].ulValueLen); @@ -416,10 +470,16 @@ static CK_RV test_pkcs11_store_create(CK_SESSION_HANDLE session, return TEST_CKR_GENERAL_ERROR; XMEMSET(&test_pkcs11_objs[i], 0, sizeof(test_pkcs11_objs[i])); + /* Defaults as in SoftHSM2. */ + test_pkcs11_objs[i].extractable = CK_TRUE; + test_pkcs11_objs[i].isPrivate = CK_TRUE; (void)test_pkcs11_apply(&test_pkcs11_objs[i], tmpl, cnt); if (test_pkcs11_fail_pub_create && test_pkcs11_objs[i].cls == CKO_PUBLIC_KEY) return TEST_CKR_GENERAL_ERROR; + if (test_pkcs11_no_hmac_type && + test_pkcs11_objs[i].keyType == CKK_SHA256_HMAC) + return TEST_CKR_GENERAL_ERROR; test_pkcs11_objs[i].used = 1; if (test_pkcs11_objs[i].cls == CKO_PRIVATE_KEY) test_pkcs11_last_priv = test_pkcs11_objs[i]; @@ -435,7 +495,8 @@ static CK_RV test_pkcs11_store_destroy(CK_SESSION_HANDLE session, (void)session; test_pkcs11_destroy_calls++; - if (obj == NULL) + if (obj == NULL || test_pkcs11_fail_destroy || + test_pkcs11_destroy_calls == test_pkcs11_fail_destroy_at) return TEST_CKR_GENERAL_ERROR; obj->used = 0; return CKR_OK; @@ -449,8 +510,11 @@ static CK_RV test_pkcs11_store_get_attr(CK_SESSION_HANDLE session, (void)session; - if (obj == NULL) + if (obj == NULL || (obj->isPrivate && + (test_pkcs11_session_state == CKS_RO_PUBLIC_SESSION || + test_pkcs11_session_state == CKS_RW_PUBLIC_SESSION))) { return TEST_CKR_GENERAL_ERROR; + } for (i = 0; i < cnt; i++) { const byte* val = NULL; CK_ULONG len = 0; @@ -469,6 +533,10 @@ static CK_RV test_pkcs11_store_get_attr(CK_SESSION_HANDLE session, val = (const byte*)&obj->keyType; len = sizeof(obj->keyType); } + else if (tmpl[i].type == CKA_SIGN) { + val = &obj->sign; + len = sizeof(obj->sign); + } else if (tmpl[i].type == CKA_MODULUS && test_pkcs11_fail_modulus) { return TEST_CKR_GENERAL_ERROR; } @@ -482,7 +550,16 @@ static CK_RV test_pkcs11_store_get_attr(CK_SESSION_HANDLE session, } else if (tmpl[i].type == CKA_EC_POINT) { val = test_pkcs11_ec_point; - len = sizeof(test_pkcs11_ec_point); + if (!test_pkcs11_session_no_point || obj->onToken) + len = sizeof(test_pkcs11_ec_point); + } + else if (tmpl[i].type == CKA_VALUE && obj->cls == CKO_PUBLIC_KEY) { + val = test_pkcs11_pq_pub; + len = test_pkcs11_pq_pub_len; + } + else if (tmpl[i].type == CKA_PARAMETER_SET) { + val = (const byte*)&test_pkcs11_pq_param; + len = sizeof(test_pkcs11_pq_param); } else if (tmpl[i].type == CKA_VALUE) { val = test_pkcs11_secret; @@ -549,6 +626,23 @@ static CK_RV test_pkcs11_store_find_final(CK_SESSION_HANDLE session) return CKR_OK; } +static CK_RV test_pkcs11_store_copy(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR tmpl, CK_ULONG cnt, + CK_OBJECT_HANDLE_PTR newObject) +{ + TestPkcs11Obj* obj = test_pkcs11_obj(object); + CK_RV rv; + + if (obj == NULL || test_pkcs11_fail_copy) + return TEST_CKR_GENERAL_ERROR; + rv = test_pkcs11_store_create(session, NULL, 0, newObject); + if (rv == CKR_OK) { + test_pkcs11_objs[*newObject - 1] = *obj; + (void)test_pkcs11_apply(&test_pkcs11_objs[*newObject - 1], tmpl, cnt); + } + return rv; +} + static CK_RV test_pkcs11_store_mech_info(CK_SLOT_ID slotId, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR info) { @@ -556,13 +650,18 @@ static CK_RV test_pkcs11_store_mech_info(CK_SLOT_ID slotId, if (info == NULL || (type != CKM_ECDSA && type != CKM_RSA_X_509 && type != CKM_EC_KEY_PAIR_GEN && type != CKM_ECDH1_DERIVE && - type != CKM_RSA_PKCS_KEY_PAIR_GEN) || + type != CKM_RSA_PKCS_KEY_PAIR_GEN && type != CKM_AES_GCM && + type != CKM_AES_CBC && type != CKM_SHA256_HMAC && + type != CKM_ML_DSA && type != CKM_ML_KEM && + type != CKM_ML_DSA_KEY_PAIR_GEN && + type != CKM_ML_KEM_KEY_PAIR_GEN) || (type == CKM_ECDH1_DERIVE && test_pkcs11_no_ecdh) || (type == CKM_ECDSA && test_pkcs11_no_ecdsa)) return CKR_MECHANISM_INVALID; XMEMSET(info, 0, sizeof(*info)); info->flags = CKF_SIGN | CKF_VERIFY | CKF_DECRYPT; + info->ulMaxKeySize = 0x10000; /* Some modules leave CKF_DERIVE out for CKM_ECDH1_DERIVE. */ if (type == CKM_ECDH1_DERIVE) info->flags = 0; @@ -571,6 +670,28 @@ static CK_RV test_pkcs11_store_mech_info(CK_SLOT_ID slotId, return CKR_OK; } +static CK_RV test_pkcs11_store_session_info(CK_SESSION_HANDLE session, + CK_SESSION_INFO_PTR info) +{ + (void)session; + + if (test_pkcs11_fail_session_info) + return TEST_CKR_GENERAL_ERROR; + XMEMSET(info, 0, sizeof(*info)); + info->state = test_pkcs11_session_state; + return CKR_OK; +} + +static CK_RV test_pkcs11_store_sign_init(CK_SESSION_HANDLE session, + CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) +{ + (void)session; + (void)mechanism; + + test_pkcs11_sign_key = key; + return test_pkcs11_obj(key) != NULL ? CKR_OK : TEST_CKR_GENERAL_ERROR; +} + static CK_RV test_pkcs11_store_decrypt_init(CK_SESSION_HANDLE session, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) { @@ -631,6 +752,10 @@ static CK_RV test_pkcs11_store_keygen(CK_SESSION_HANDLE session, return TEST_CKR_GENERAL_ERROR; if (mechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN) keyType = CKK_RSA; + else if (mechanism->mechanism == CKM_ML_DSA_KEY_PAIR_GEN) + keyType = CKK_ML_DSA; + else if (mechanism->mechanism == CKM_ML_KEM_KEY_PAIR_GEN) + keyType = CKK_ML_KEM; for (i = 0; i < pubCnt; i++) { if (pubTmpl[i].type == CKA_PUBLIC_EXPONENT && pubTmpl[i].ulValueLen <= sizeof(test_pkcs11_keygen_exp)) { @@ -658,6 +783,7 @@ static void test_pkcs11_store_setup(Pkcs11Token* token, CK_FUNCTION_LIST* func) XMEMSET(func, 0, sizeof(*func)); func->C_GetMechanismInfo = test_pkcs11_store_mech_info; func->C_CreateObject = test_pkcs11_store_create; + func->C_CopyObject = test_pkcs11_store_copy; func->C_DestroyObject = test_pkcs11_store_destroy; func->C_GetAttributeValue = test_pkcs11_store_get_attr; func->C_FindObjectsInit = test_pkcs11_store_find_init; @@ -666,7 +792,8 @@ static void test_pkcs11_store_setup(Pkcs11Token* token, CK_FUNCTION_LIST* func) func->C_GenerateKeyPair = test_pkcs11_store_keygen; func->C_DecryptInit = test_pkcs11_store_decrypt_init; func->C_Decrypt = test_pkcs11_store_decrypt; - func->C_SignInit = test_pkcs11_store_decrypt_init; + func->C_GetSessionInfo = test_pkcs11_store_session_info; + func->C_SignInit = test_pkcs11_store_sign_init; func->C_Sign = test_pkcs11_store_sign; func->C_DeriveKey = test_pkcs11_store_derive; token->func = func; @@ -676,6 +803,14 @@ static void test_pkcs11_store_setup(Pkcs11Token* token, CK_FUNCTION_LIST* func) test_pkcs11_no_ecdh = 0; test_pkcs11_no_ecdsa = 0; test_pkcs11_ecdsa_verify_only = 0; + test_pkcs11_session_state = CKS_RW_USER_FUNCTIONS; + test_pkcs11_no_hmac_type = 0; + test_pkcs11_fail_copy = 0; + test_pkcs11_fail_destroy = 0; + test_pkcs11_fail_session_info = 0; + test_pkcs11_sign_key = 0; + test_pkcs11_pq_pub_len = 0; + test_pkcs11_pq_param = 0; test_pkcs11_reset(); } @@ -733,7 +868,6 @@ int test_wc_Pkcs11_FreeKeepsTokenKey(void) return EXPECT_RESULT(); } -#ifdef TEST_PKCS11_EC_KEYGEN static int test_pkcs11_make_ecc(ecc_key* key, WC_RNG* rng, const byte* id, int idLen) { @@ -747,9 +881,50 @@ static int test_pkcs11_make_ecc(ecc_key* key, WC_RNG* rng, const byte* id, #endif return ret; } -#endif -#if defined(TEST_PKCS11_EC_KEYGEN) && defined(HAVE_ECC_KEY_IMPORT) +int test_wc_Pkcs11_StoreKeyPersistent(void) +{ + static const byte id[] = { 0x01, 0x02, 0x03, 0x04 }; + Pkcs11Token token; + CK_FUNCTION_LIST func; + ecc_key key; + WC_RNG rng; + int i; + EXPECT_DECLS; + + test_pkcs11_store_setup(&token, &func); + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(test_pkcs11_make_ecc(&key, &rng, id, (int)sizeof(id)), 0); + + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 0), + 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 2); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + + test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + for (i = 0; i < TEST_PKCS11_MAX_OBJS; i++) { + if (test_pkcs11_objs[i].used) { + ExpectIntEQ(test_pkcs11_objs[i].idLen, sizeof(id)); + ExpectBufEQ(test_pkcs11_objs[i].id, id, sizeof(id)); + } + } + + test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_EC, 0, &key), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + + wc_ecc_free(&key); + DoExpectIntEQ(wc_FreeRng(&rng), 0); + + return EXPECT_RESULT(); +} + static CK_OBJECT_HANDLE test_pkcs11_find_obj(CK_OBJECT_CLASS cls, CK_BBOOL onToken) { @@ -762,7 +937,252 @@ static CK_OBJECT_HANDLE test_pkcs11_find_obj(CK_OBJECT_CLASS cls, } return 0; } -#endif + +int test_wc_Pkcs11_PersistKey(void) +{ + static const byte id[] = { 0x0a, 0x0b, 0x0c }; + static CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; + static CK_KEY_TYPE ecType = CKK_EC; + static CK_BBOOL canSign = CK_TRUE; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &ecType, sizeof(ecType) }, + { CKA_ID, (void*)id, sizeof(id) }, + { CKA_SIGN, &canSign, sizeof(canSign) } + }; + Pkcs11Token token; + CK_FUNCTION_LIST func; + CK_OBJECT_HANDLE sessObj = 0; + CK_OBJECT_HANDLE tokObj = 0; + TestPkcs11Obj* obj = NULL; + ecc_key key; + ecc_key noId; + ecc_key ref; + WC_RNG rng; + EXPECT_DECLS; + + test_pkcs11_store_setup(&token, &func); + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&noId, 0, sizeof(noId)); + XMEMSET(&ref, 0, sizeof(ref)); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(test_pkcs11_make_ecc(&key, &rng, id, (int)sizeof(id)), 0); + ExpectIntEQ(wc_ecc_init(&noId), 0); + + ExpectIntEQ(wc_Pkcs11PersistKey(NULL, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, NULL), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &noId), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(WC_HW_E)); + + /* Session object found by id, as left by an import. */ + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_EC, 0, &key), 0); + sessObj = test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_FALSE); + ExpectIntNE(sessObj, 0); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), 0); + tokObj = test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_TRUE); + ExpectIntNE(tokObj, 0); + ExpectNull(test_pkcs11_obj(sessObj)); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntNE(test_pkcs11_find_obj(CKO_PUBLIC_KEY, CK_TRUE), 0); + ExpectPtrEq(key.devCtx, (void*)(wc_ptr_t)tokObj); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(BAD_STATE_E)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + + ExpectIntEQ(test_pkcs11_free_ecc(&token, &key), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + + /* A reference without the public key keeps the session public key. */ + test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_EC, 0, &key), 0); + ExpectIntEQ(wc_ecc_init_id(&ref, (unsigned char*)id, (int)sizeof(id), + NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &ref), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntNE(test_pkcs11_find_obj(CKO_PUBLIC_KEY, CK_TRUE), 0); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + wc_ecc_free(&ref); + + /* Session object in devCtx, as left by keygen; the public key fails. */ + test_pkcs11_reset(); + ExpectIntEQ(test_pkcs11_store_create(0, tmpl, 4, &sessObj), CKR_OK); + key.devCtx = (void*)(wc_ptr_t)sessObj; + test_pkcs11_fail_pub_create = 1; + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(WC_HW_E)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + ExpectNotNull(test_pkcs11_obj(sessObj)); + ExpectPtrEq(key.devCtx, (void*)(wc_ptr_t)sessObj); + + test_pkcs11_fail_pub_create = 0; + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), 0); + ExpectNull(test_pkcs11_obj(sessObj)); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectPtrEq(key.devCtx, + (void*)(wc_ptr_t)test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_TRUE)); + + /* A key already on the token under other names is not copied again. */ + tokObj = (CK_OBJECT_HANDLE)(wc_ptr_t)key.devCtx; + key.id[0] = 0x0f; + key.idLen = 1; + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(BAD_STATE_E)); + ExpectNotNull(test_pkcs11_obj(tokObj)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + + /* A key that cannot sign does not need its public key on the token. */ + test_pkcs11_reset(); + XMEMCPY(key.id, id, sizeof(id)); + key.idLen = (int)sizeof(id); + ExpectIntEQ(test_pkcs11_store_create(0, tmpl, 3, &sessObj), CKR_OK); + key.devCtx = (void*)(wc_ptr_t)sessObj; + test_pkcs11_fail_pub_create = 1; + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), 0); + test_pkcs11_fail_pub_create = 0; + ExpectIntEQ(test_pkcs11_find_obj(CKO_PUBLIC_KEY, CK_TRUE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + + /* Without ECDSA no public key is stored, as in wc_Pkcs11StoreKey_ex. */ + test_pkcs11_reset(); + ExpectIntEQ(test_pkcs11_store_create(0, tmpl, 4, &sessObj), CKR_OK); + key.devCtx = (void*)(wc_ptr_t)sessObj; + test_pkcs11_no_ecdsa = 1; + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), 0); + test_pkcs11_no_ecdsa = 0; + ExpectIntEQ(test_pkcs11_find_obj(CKO_PUBLIC_KEY, CK_TRUE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + ExpectPtrEq(key.devCtx, + (void*)(wc_ptr_t)test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_TRUE)); + + /* A session object that cannot be destroyed is left to its session. */ + test_pkcs11_reset(); + XMEMCPY(key.id, id, sizeof(id)); + key.idLen = (int)sizeof(id); + ExpectIntEQ(test_pkcs11_store_create(0, tmpl, 3, &sessObj), CKR_OK); + key.devCtx = (void*)(wc_ptr_t)sessObj; + test_pkcs11_fail_destroy = 1; + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), 0); + test_pkcs11_fail_destroy = 0; + ExpectNotNull(test_pkcs11_obj(sessObj)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectPtrEq(key.devCtx, + (void*)(wc_ptr_t)test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_TRUE)); + + /* The token object gets the key's id and label. */ + test_pkcs11_reset(); + ExpectIntEQ(test_pkcs11_store_create(0, tmpl, 2, &sessObj), CKR_OK); + key.devCtx = (void*)(wc_ptr_t)sessObj; + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), 0); + ExpectNotNull(obj = test_pkcs11_obj(test_pkcs11_find_obj(CKO_PRIVATE_KEY, + CK_TRUE))); + if (obj != NULL) { + ExpectIntEQ(obj->idLen, sizeof(id)); + ExpectBufEQ(obj->id, id, sizeof(id)); + } + + key.devCtx = NULL; + wc_ecc_free(&key); + wc_ecc_free(&noId); + DoExpectIntEQ(wc_FreeRng(&rng), 0); + + return EXPECT_RESULT(); +} + +int test_wc_Pkcs11_DeleteKey(void) +{ + static const byte id[] = { 0x0d, 0x0e }; + static const byte otherId[] = { 0x0f }; + static CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; + static CK_KEY_TYPE ecType = CKK_EC; + static CK_BBOOL isToken = CK_TRUE; + CK_ATTRIBUTE other[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &ecType, sizeof(ecType) }, + { CKA_ID, (void*)otherId, sizeof(otherId) }, + { CKA_TOKEN, &isToken, sizeof(isToken) } + }; + CK_ATTRIBUTE sess[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &ecType, sizeof(ecType) }, + { CKA_ID, (void*)id, sizeof(id) } + }; + Pkcs11Token token; + CK_FUNCTION_LIST func; + CK_OBJECT_HANDLE otherObj = 0; + CK_OBJECT_HANDLE sessObj = 0; + ecc_key key; + ecc_key noId; + WC_RNG rng; + EXPECT_DECLS; + + test_pkcs11_store_setup(&token, &func); + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&noId, 0, sizeof(noId)); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(test_pkcs11_make_ecc(&key, &rng, id, (int)sizeof(id)), 0); + ExpectIntEQ(wc_ecc_init(&noId), 0); + + ExpectIntEQ(wc_Pkcs11DeleteKey(NULL, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_EC, &noId), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + ExpectIntEQ(test_pkcs11_store_create(0, other, 4, &otherObj), CKR_OK); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 3); + ExpectIntEQ(test_pkcs11_store_create(0, sess, 3, &sessObj), CKR_OK); + key.devCtx = (void*)(wc_ptr_t)sessObj; + + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_EC, &key), 0); + ExpectNull(key.devCtx); + ExpectNull(test_pkcs11_obj(sessObj)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + ExpectNotNull(test_pkcs11_obj(otherObj)); + + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_EC, &key), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + + /* Without a user login the private key is hidden from the search. */ + test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + 0); + key.devCtx = (void*)(wc_ptr_t)test_pkcs11_find_obj(CKO_PRIVATE_KEY, + CK_TRUE); + test_pkcs11_session_state = CKS_RW_PUBLIC_SESSION; + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(BAD_STATE_E)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectNotNull(key.devCtx); + test_pkcs11_session_state = CKS_RW_USER_FUNCTIONS; + + /* A delete that fails part way drops the object it destroyed. */ + test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + 0); + key.devCtx = (void*)(wc_ptr_t)test_pkcs11_find_obj(CKO_PRIVATE_KEY, + CK_TRUE); + test_pkcs11_fail_destroy_at = 2; + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(WC_HW_E)); + ExpectNull(key.devCtx); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + + wc_ecc_free(&key); + wc_ecc_free(&noId); + DoExpectIntEQ(wc_FreeRng(&rng), 0); + + return EXPECT_RESULT(); +} #if !defined(NO_RSA) && !defined(NO_PKCS11_RSA) && \ defined(HAVE_WOLF_BIGINT) && \ @@ -1221,6 +1641,11 @@ int test_wc_Pkcs11_KeyGenSessionClosed(void) ecc_key key; WC_RNG rng; word32 len = sizeof(test_pkcs11_ec_point) - 2; +#ifdef HAVE_ECC_SIGN + byte hash[32]; + byte sig[ECC_MAX_SIG_SIZE]; + word32 sigLen = sizeof(sig); +#endif #ifdef TEST_PKCS11_RSA_KEYGEN RsaKey rsa; wc_CryptoInfo info; @@ -1229,6 +1654,9 @@ int test_wc_Pkcs11_KeyGenSessionClosed(void) test_pkcs11_store_setup(&token, &func); func.C_OpenSession = test_pkcs11_open_session; func.C_CloseSession = test_pkcs11_close_session; +#ifdef HAVE_ECC_SIGN + XMEMSET(hash, 0x5a, sizeof(hash)); +#endif XMEMSET(&soft, 0, sizeof(soft)); ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(test_pkcs11_make_ecc(&soft, &rng, id, (int)sizeof(id)), 0); @@ -1255,6 +1683,12 @@ int test_wc_Pkcs11_KeyGenSessionClosed(void) ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_EC, 0, &soft), WC_NO_ERR_TRACE(BAD_STATE_E)); ExpectIntEQ(test_pkcs11_opens, 0); + /* A persistent store needs no open session. */ + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &soft, 1), + 0); + ExpectIntEQ(test_pkcs11_opens, 1); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + test_pkcs11_reset(); #ifdef TEST_PKCS11_RSA_KEYGEN ExpectIntEQ(wc_InitRsaKey_Id(&rsa, (unsigned char*)id, (int)sizeof(id), NULL, TEST_PKCS11_DEVID), 0); @@ -1288,8 +1722,29 @@ int test_wc_Pkcs11_KeyGenSessionClosed(void) #endif ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); - /* A session key made in the open session is kept. */ + /* A token key outlives the session and is then found by its id. */ + test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 1), 0); + ExpectIntEQ(wc_ecc_init_id(&key, (unsigned char*)id, (int)sizeof(id), + NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_ecc_make_key_ex2(&rng, 32, &key, ECC_SECP256R1, + WC_ECC_FLAG_NONE), 0); + ExpectNull(key.devCtx); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); +#ifdef HAVE_ECC_SIGN + test_pkcs11_sign_key = 0; + ExpectIntEQ(wc_ecc_sign_hash(hash, sizeof(hash), sig, &sigLen, &rng, &key), + 0); +#ifndef WC_PKCS11_FIND_WITH_ID_ONLY + ExpectIntEQ(test_pkcs11_sign_key, + test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_TRUE)); +#endif +#endif + wc_ecc_free(&key); + + /* So does a session key made in the open session. */ test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 0), 0); token.handle = 1; ExpectIntEQ(wc_ecc_init_id(&key, (unsigned char*)id, (int)sizeof(id), NULL, TEST_PKCS11_DEVID), 0); @@ -1305,13 +1760,14 @@ int test_wc_Pkcs11_KeyGenSessionClosed(void) return EXPECT_RESULT(); } -int test_wc_Pkcs11_RsaKeyGenExponent(void) +int test_wc_Pkcs11_RsaPersistDelete(void) { EXPECT_DECLS; #ifdef TEST_PKCS11_RSA_KEYGEN - static const byte exp65539[] = { 0x01, 0x00, 0x03 }; + static unsigned char id[] = { 0x81 }; Pkcs11Token token; CK_FUNCTION_LIST func; + CK_OBJECT_HANDLE sessObj = 0; RsaKey key; WC_RNG rng; @@ -1319,19 +1775,25 @@ int test_wc_Pkcs11_RsaKeyGenExponent(void) ExpectIntEQ(wc_InitRng(&rng), 0); ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_PKCS11_DEVID, wc_Pkcs11_CryptoDevCb, &token), 0); - - ExpectIntEQ(wc_InitRsaKey_ex(&key, NULL, TEST_PKCS11_DEVID), 0); - ExpectIntEQ(wc_MakeRsaKey(&key, 2048, 65539, &rng), 0); - ExpectIntEQ(test_pkcs11_keygen_exp_len, sizeof(exp65539)); - ExpectBufEQ(test_pkcs11_keygen_exp, exp65539, sizeof(exp65539)); - ExpectIntEQ(wc_FreeRsaKey(&key), 0); - - /* The next key gets the default exponent again. */ - ExpectIntEQ(wc_InitRsaKey_ex(&key, NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_InitRsaKey_Id(&key, id, (int)sizeof(id), NULL, + TEST_PKCS11_DEVID), 0); ExpectIntEQ(wc_MakeRsaKey(&key, 2048, WC_RSA_EXPONENT, &rng), 0); - ExpectIntEQ(test_pkcs11_keygen_exp_len, sizeof(test_pkcs11_exponent)); - ExpectBufEQ(test_pkcs11_keygen_exp, test_pkcs11_exponent, - sizeof(test_pkcs11_exponent)); + if (EXPECT_SUCCESS()) + sessObj = (CK_OBJECT_HANDLE)(wc_ptr_t)key.devCtx; + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 1); + + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_RSA, &key), 0); + ExpectNull(test_pkcs11_obj(sessObj)); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntNE(test_pkcs11_find_obj(CKO_PUBLIC_KEY, CK_TRUE), 0); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectPtrEq(key.devCtx, + (void*)(wc_ptr_t)test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_TRUE)); + + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_RSA, &key), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + ExpectNull(key.devCtx); ExpectIntEQ(wc_FreeRsaKey(&key), 0); wc_CryptoCb_UnRegisterDevice(TEST_PKCS11_DEVID); @@ -1340,51 +1802,524 @@ int test_wc_Pkcs11_RsaKeyGenExponent(void) return EXPECT_RESULT(); } -int test_wc_Pkcs11_RsaKeyGenError(void) +#if !defined(NO_AES) && defined(HAVE_AESGCM) && !defined(NO_PKCS11_AES) && \ + !defined(NO_PKCS11_AESGCM) + #define TEST_PKCS11_PERSIST_AES +#endif +#if !defined(NO_HMAC) && !defined(NO_SHA256) && !defined(NO_PKCS11_HMAC) + #define TEST_PKCS11_PERSIST_HMAC +#endif + +int test_wc_Pkcs11_SecretKeyPersist(void) { EXPECT_DECLS; -#ifdef TEST_PKCS11_RSA_KEYGEN +#if defined(TEST_PKCS11_PERSIST_AES) || defined(TEST_PKCS11_PERSIST_HMAC) + static unsigned char id[] = { 0x71 }; + static const byte secret[16] = { 0x01 }; Pkcs11Token token; CK_FUNCTION_LIST func; - RsaKey key; -#ifdef TEST_PKCS11_EC_KEYGEN - ecc_key ecc; +#ifdef TEST_PKCS11_PERSIST_AES + Aes aes; #endif - WC_RNG rng; -#if defined(HAVE_WOLF_BIGINT) && defined(USE_WOLFSSL_MEMORY) && \ - !defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) - int haveAlloc = 0; +#ifdef TEST_PKCS11_PERSIST_HMAC + Hmac hmac; #endif test_pkcs11_store_setup(&token, &func); - ExpectIntEQ(wc_InitRng(&rng), 0); - ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_PKCS11_DEVID, - wc_Pkcs11_CryptoDevCb, &token), 0); - -#if defined(HAVE_WOLF_BIGINT) && defined(USE_WOLFSSL_MEMORY) && \ - !defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) - /* Freeing the key on the device must still free its software parts. */ - ExpectIntEQ(wolfSSL_GetAllocators(&test_pkcs11_mf, &test_pkcs11_ff, - &test_pkcs11_rf), 0); +#ifdef TEST_PKCS11_PERSIST_AES + ExpectIntEQ(wc_AesInit_Id(&aes, id, (int)sizeof(id), NULL, INVALID_DEVID), + 0); if (EXPECT_SUCCESS()) { - test_pkcs11_live = 0; - ExpectIntEQ(wolfSSL_SetAllocators(test_pkcs11_malloc, - test_pkcs11_free, test_pkcs11_realloc), 0); - haveAlloc = EXPECT_SUCCESS(); + aes.keylen = sizeof(secret); + XMEMCPY(aes.devKey, secret, sizeof(secret)); } -#endif - ExpectIntEQ(wc_InitRsaKey_ex(&key, NULL, TEST_PKCS11_DEVID), 0); - ExpectIntEQ(wc_MakeRsaKey(&key, 2048, WC_RSA_EXPONENT, &rng), 0); + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_AES_GCM, 0, &aes), + 0); ExpectIntEQ(test_pkcs11_count(CK_FALSE), 1); - ExpectNotNull(key.devCtx); - test_pkcs11_find_calls = 0; - test_pkcs11_modulus_reads = 0; - ExpectIntEQ(test_pkcs11_rsa_decrypt(&token, &key), 0); - ExpectIntEQ(test_pkcs11_find_calls, 0); - ExpectIntEQ(test_pkcs11_modulus_reads, 0); - ExpectIntEQ(wc_FreeRsaKey(&key), 0); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_AES_GCM, &aes), 0); ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); -#if defined(HAVE_WOLF_BIGINT) && defined(USE_WOLFSSL_MEMORY) && \ + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_AES_GCM, &aes), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + wc_AesFree(&aes); +#endif + +#ifdef TEST_PKCS11_PERSIST_HMAC + /* A token without the HMAC key type holds a generic secret. */ + test_pkcs11_reset(); + test_pkcs11_no_hmac_type = 1; + ExpectIntEQ(wc_HmacInit_Id(&hmac, id, (int)sizeof(id), NULL, + INVALID_DEVID), 0); + if (EXPECT_SUCCESS()) { + hmac.macType = WC_SHA256; + hmac.keyRaw = secret; + hmac.keyLen = sizeof(secret); + } + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_HMAC, 0, &hmac), 0); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_HMAC, &hmac), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_HMAC, 0, &hmac, + 1), WC_NO_ERR_TRACE(BAD_STATE_E)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_HMAC, &hmac), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + test_pkcs11_no_hmac_type = 0; + wc_HmacFree(&hmac); +#endif +#endif + return EXPECT_RESULT(); +} + +int test_wc_Pkcs11_PqcPersistDelete(void) +{ + EXPECT_DECLS; +#if defined(TEST_PKCS11_MLDSA_44) || defined(TEST_PKCS11_MLKEM_768) + static const unsigned char id[] = { 0x91 }; + Pkcs11Token token; + CK_FUNCTION_LIST func; + WC_RNG rng; +#ifdef TEST_PKCS11_MLDSA_44 + wc_MlDsaKey dsa; + wc_MlDsaKey ref; +#endif +#ifdef TEST_PKCS11_MLKEM_768 + MlKemKey kem; +#endif + + test_pkcs11_store_setup(&token, &func); + ExpectIntEQ(wc_InitRng(&rng), 0); + +#ifdef TEST_PKCS11_MLDSA_44 + ExpectIntEQ(wc_MlDsaKey_InitId(&dsa, id, (int)sizeof(id), NULL, + INVALID_DEVID), 0); + ExpectIntEQ(wc_MlDsaKey_SetParams(&dsa, WC_ML_DSA_44), 0); + ExpectIntEQ(wc_MlDsaKey_MakeKey(&dsa, &rng), 0); + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_MLDSA, 0, &dsa), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 2); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_MLDSA, &dsa), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectPtrEq(dsa.devCtx, + (void*)(wc_ptr_t)test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_TRUE)); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_MLDSA, &dsa), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + ExpectNull(dsa.devCtx); + + /* An import can go to the token directly. */ + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_MLDSA, 0, &dsa, + 1), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_MLDSA, &dsa), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + + /* A reference without the public key keeps the session public key. */ + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_MLDSA, 0, &dsa), 0); + ExpectIntEQ(wc_MlDsaKey_InitId(&ref, id, (int)sizeof(id), NULL, + INVALID_DEVID), 0); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_MLDSA, &ref), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntNE(test_pkcs11_find_obj(CKO_PUBLIC_KEY, CK_TRUE), 0); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_MLDSA, &ref), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + wc_MlDsaKey_Free(&ref); + wc_MlDsaKey_Free(&dsa); +#endif + +#ifdef TEST_PKCS11_MLKEM_768 + test_pkcs11_reset(); + ExpectIntEQ(wc_MlKemKey_Init_Id(&kem, WC_ML_KEM_768, (unsigned char*)id, + (int)sizeof(id), NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_MlKemKey_MakeKey(&kem, &rng), 0); + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_MLKEM, 0, &kem), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 2); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_MLKEM, &kem), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectNotNull(test_pkcs11_obj(test_pkcs11_find_obj(CKO_PUBLIC_KEY, + CK_TRUE))); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_MLKEM, &kem), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + ExpectNull(kem.devCtx); + + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_MLKEM, 0, &kem, + 1), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_MLKEM, &kem), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + wc_MlKemKey_Free(&kem); +#endif + + DoExpectIntEQ(wc_FreeRng(&rng), 0); +#endif + return EXPECT_RESULT(); +} + +int test_wc_Pkcs11_PqcKeyGen(void) +{ + EXPECT_DECLS; +#if defined(TEST_PKCS11_MLDSA_44) || defined(TEST_PKCS11_MLKEM_768) + static const unsigned char id[] = { 0xb1 }; + Pkcs11Token token; + CK_FUNCTION_LIST func; + WC_RNG rng; +#ifdef TEST_PKCS11_MLDSA_44 + wc_MlDsaKey soft; + wc_MlDsaKey dsa; + word32 dsaLen = sizeof(test_pkcs11_pq_pub); +#endif +#ifdef TEST_PKCS11_MLKEM_768 + MlKemKey softKem; + MlKemKey kem; + word32 kemLen = 0; +#endif + + test_pkcs11_store_setup(&token, &func); + func.C_OpenSession = test_pkcs11_open_session; + func.C_CloseSession = test_pkcs11_close_session; + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_PKCS11_DEVID, + wc_Pkcs11_CryptoDevCb, &token), 0); + +#ifdef TEST_PKCS11_MLDSA_44 + ExpectIntEQ(wc_MlDsaKey_Init(&soft, NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_MlDsaKey_SetParams(&soft, WC_ML_DSA_44), 0); + ExpectIntEQ(wc_MlDsaKey_MakeKey(&soft, &rng), 0); + ExpectIntEQ(wc_MlDsaKey_ExportPubRaw(&soft, test_pkcs11_pq_pub, &dsaLen), + 0); + test_pkcs11_pq_pub_len = dsaLen; + test_pkcs11_pq_param = CKP_ML_DSA_44; + wc_MlDsaKey_Free(&soft); + + /* A named key becomes a token key with its public key. */ + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 1), 0); + ExpectIntEQ(wc_MlDsaKey_InitId(&dsa, id, (int)sizeof(id), NULL, + TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MlDsaKey_SetParams(&dsa, WC_ML_DSA_44), 0); + ExpectIntEQ(wc_MlDsaKey_MakeKey(&dsa, &rng), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectPtrEq(dsa.devCtx, + (void*)(wc_ptr_t)test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_TRUE)); + ExpectIntEQ(wc_MlDsaKey_MakeKey(&dsa, &rng), + WC_NO_ERR_TRACE(BAD_STATE_E)); + dsa.devCtx = NULL; + wc_MlDsaKey_Free(&dsa); + + /* A named session key in a session that closes is refused. */ + test_pkcs11_reset(); + token.handle = 0; + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 0), 0); + ExpectIntEQ(wc_MlDsaKey_InitId(&dsa, id, (int)sizeof(id), NULL, + TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MlDsaKey_SetParams(&dsa, WC_ML_DSA_44), 0); + ExpectIntEQ(wc_MlDsaKey_MakeKey(&dsa, &rng), + WC_NO_ERR_TRACE(BAD_STATE_E)); + ExpectNull(dsa.devCtx); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + wc_MlDsaKey_Free(&dsa); + + /* A named token key in a session that closes stays on the token. */ + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 1), 0); + ExpectIntEQ(wc_MlDsaKey_InitId(&dsa, id, (int)sizeof(id), NULL, + TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MlDsaKey_SetParams(&dsa, WC_ML_DSA_44), 0); + ExpectIntEQ(wc_MlDsaKey_MakeKey(&dsa, &rng), 0); + ExpectNull(dsa.devCtx); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + wc_MlDsaKey_Free(&dsa); + test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 0), 0); + + /* A key without a name is generated in software. */ + ExpectIntEQ(wc_MlDsaKey_Init(&dsa, NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MlDsaKey_SetParams(&dsa, WC_ML_DSA_44), 0); + ExpectIntEQ(wc_MlDsaKey_MakeKey(&dsa, &rng), 0); + ExpectNull(dsa.devCtx); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + wc_MlDsaKey_Free(&dsa); + token.handle = 1; +#endif + +#ifdef TEST_PKCS11_MLKEM_768 + test_pkcs11_reset(); + ExpectIntEQ(wc_MlKemKey_Init(&softKem, WC_ML_KEM_768, NULL, + INVALID_DEVID), 0); + ExpectIntEQ(wc_MlKemKey_MakeKey(&softKem, &rng), 0); + ExpectIntEQ(wc_MlKemKey_PublicKeySize(&softKem, &kemLen), 0); + ExpectIntEQ(wc_MlKemKey_EncodePublicKey(&softKem, test_pkcs11_pq_pub, + kemLen), 0); + test_pkcs11_pq_pub_len = kemLen; + test_pkcs11_pq_param = CKP_ML_KEM_768; + wc_MlKemKey_Free(&softKem); + + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 1), 0); + ExpectIntEQ(wc_MlKemKey_Init_Id(&kem, WC_ML_KEM_768, (unsigned char*)id, + (int)sizeof(id), NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MlKemKey_MakeKey(&kem, &rng), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectPtrEq(kem.devCtx, + (void*)(wc_ptr_t)test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_TRUE)); + ExpectIntEQ(wc_MlKemKey_MakeKey(&kem, &rng), + WC_NO_ERR_TRACE(BAD_STATE_E)); + kem.devCtx = NULL; + wc_MlKemKey_Free(&kem); + + test_pkcs11_reset(); + token.handle = 0; + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 0), 0); + ExpectIntEQ(wc_MlKemKey_Init_Id(&kem, WC_ML_KEM_768, (unsigned char*)id, + (int)sizeof(id), NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MlKemKey_MakeKey(&kem, &rng), + WC_NO_ERR_TRACE(BAD_STATE_E)); + ExpectNull(kem.devCtx); + ExpectIntEQ(kem.flags & MLKEM_FLAG_PRIV_SET, 0); + wc_MlKemKey_Free(&kem); + + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 1), 0); + ExpectIntEQ(wc_MlKemKey_Init_Id(&kem, WC_ML_KEM_768, (unsigned char*)id, + (int)sizeof(id), NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MlKemKey_MakeKey(&kem, &rng), 0); + ExpectNull(kem.devCtx); + ExpectIntNE(kem.flags & MLKEM_FLAG_PRIV_SET, 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + wc_MlKemKey_Free(&kem); + test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 0), 0); + + ExpectIntEQ(wc_MlKemKey_Init(&kem, WC_ML_KEM_768, NULL, + TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MlKemKey_MakeKey(&kem, &rng), 0); + ExpectNull(kem.devCtx); + ExpectIntNE(kem.flags & MLKEM_FLAG_PRIV_SET, 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + wc_MlKemKey_Free(&kem); + token.handle = 1; +#endif + + wc_CryptoCb_UnRegisterDevice(TEST_PKCS11_DEVID); + DoExpectIntEQ(wc_FreeRng(&rng), 0); +#endif + return EXPECT_RESULT(); +} + +int test_wc_Pkcs11_PersistPaths(void) +{ + static const byte id[] = { 0xa1 }; + static const byte secret[16] = { 0x02 }; + Pkcs11Token token; + CK_FUNCTION_LIST func; + CK_OBJECT_HANDLE sessObj = 0; + ecc_key key; + WC_RNG rng; +#if !defined(NO_AES) && defined(HAVE_AES_CBC) && !defined(NO_PKCS11_AES) && \ + !defined(NO_PKCS11_AESCBC) + Aes aes; +#endif +#if !defined(NO_HMAC) && !defined(NO_SHA256) && !defined(NO_PKCS11_HMAC) + Hmac hmac; + TestPkcs11Obj* secObj = NULL; +#endif +#ifdef TEST_PKCS11_RSA_KEYGEN + RsaKey rsa; +#endif + EXPECT_DECLS; + + test_pkcs11_store_setup(&token, &func); + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(test_pkcs11_make_ecc(&key, &rng, id, (int)sizeof(id)), 0); + + /* A failed copy leaves the session key and nothing on the token. */ + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_EC, 0, &key), 0); + sessObj = test_pkcs11_find_obj(CKO_PRIVATE_KEY, CK_FALSE); + test_pkcs11_fail_copy = 1; + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(WC_HW_E)); + test_pkcs11_fail_copy = 0; + ExpectNotNull(test_pkcs11_obj(sessObj)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + + /* Delete reports a session state or destroy it cannot complete. */ + test_pkcs11_reset(); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + 0); + test_pkcs11_fail_session_info = 1; + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(WC_HW_E)); + test_pkcs11_fail_session_info = 0; + test_pkcs11_fail_destroy = 1; + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_EC, &key), + WC_NO_ERR_TRACE(WC_HW_E)); + test_pkcs11_fail_destroy = 0; + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + +#ifdef TEST_PKCS11_RSA_KEYGEN + test_pkcs11_reset(); + ExpectIntEQ(wc_InitRsaKey_Id(&rsa, (unsigned char*)id, (int)sizeof(id), + NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_MakeRsaKey(&rsa, 2048, WC_RSA_EXPONENT, &rng), 0); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_RSA, 0, &rsa, 1), + 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntNE(test_pkcs11_find_obj(CKO_PUBLIC_KEY, CK_TRUE), 0); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_RSA, 0, &rsa, 1), + WC_NO_ERR_TRACE(BAD_STATE_E)); + ExpectIntEQ(wc_FreeRsaKey(&rsa), 0); +#endif + +#if !defined(NO_AES) && defined(HAVE_AES_CBC) && !defined(NO_PKCS11_AES) && \ + !defined(NO_PKCS11_AESCBC) + test_pkcs11_reset(); + ExpectIntEQ(wc_AesInit_Id(&aes, (unsigned char*)id, (int)sizeof(id), NULL, + INVALID_DEVID), 0); + if (EXPECT_SUCCESS()) { + aes.keylen = sizeof(secret); + XMEMCPY(aes.devKey, secret, sizeof(secret)); + } + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_AES_CBC, 0, &aes, + 1), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_AES_CBC, &aes), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + wc_AesFree(&aes); +#endif + +#if !defined(NO_HMAC) && !defined(NO_SHA256) && !defined(NO_PKCS11_HMAC) + /* An HMAC key stored under its own key type. */ + test_pkcs11_reset(); + ExpectIntEQ(wc_HmacInit_Id(&hmac, (unsigned char*)id, (int)sizeof(id), + NULL, INVALID_DEVID), 0); + if (EXPECT_SUCCESS()) { + hmac.macType = WC_SHA256; + hmac.keyRaw = secret; + hmac.keyLen = sizeof(secret); + } + ExpectIntEQ(wc_Pkcs11StoreKey(&token, PKCS11_KEY_TYPE_HMAC, 0, &hmac), 0); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_HMAC, &hmac), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + ExpectNotNull(secObj = test_pkcs11_obj(test_pkcs11_find_obj( + CKO_SECRET_KEY, CK_TRUE))); + if (secObj != NULL) + ExpectIntEQ(secObj->keyType, CKK_SHA256_HMAC); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_HMAC, &hmac), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + wc_HmacFree(&hmac); + + /* A key named only by id has no hash type to find it by. */ + ExpectIntEQ(wc_HmacInit_Id(&hmac, (unsigned char*)id, (int)sizeof(id), + NULL, INVALID_DEVID), 0); + ExpectIntEQ(wc_Pkcs11PersistKey(&token, PKCS11_KEY_TYPE_HMAC, &hmac), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_HMAC, &hmac), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + wc_HmacFree(&hmac); +#endif + + wc_ecc_free(&key); + DoExpectIntEQ(wc_FreeRng(&rng), 0); + (void)secret; + + return EXPECT_RESULT(); +} + +int test_wc_Pkcs11_RsaKeyGenExponent(void) +{ + EXPECT_DECLS; +#ifdef TEST_PKCS11_RSA_KEYGEN + static const byte exp65539[] = { 0x01, 0x00, 0x03 }; + Pkcs11Token token; + CK_FUNCTION_LIST func; + RsaKey key; + WC_RNG rng; + + test_pkcs11_store_setup(&token, &func); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_PKCS11_DEVID, + wc_Pkcs11_CryptoDevCb, &token), 0); + + ExpectIntEQ(wc_InitRsaKey_ex(&key, NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MakeRsaKey(&key, 2048, 65539, &rng), 0); + ExpectIntEQ(test_pkcs11_keygen_exp_len, sizeof(exp65539)); + ExpectBufEQ(test_pkcs11_keygen_exp, exp65539, sizeof(exp65539)); + ExpectIntEQ(wc_FreeRsaKey(&key), 0); + + /* The next key gets the default exponent again. */ + ExpectIntEQ(wc_InitRsaKey_ex(&key, NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MakeRsaKey(&key, 2048, WC_RSA_EXPONENT, &rng), 0); + ExpectIntEQ(test_pkcs11_keygen_exp_len, sizeof(test_pkcs11_exponent)); + ExpectBufEQ(test_pkcs11_keygen_exp, test_pkcs11_exponent, + sizeof(test_pkcs11_exponent)); + ExpectIntEQ(wc_FreeRsaKey(&key), 0); + + wc_CryptoCb_UnRegisterDevice(TEST_PKCS11_DEVID); + DoExpectIntEQ(wc_FreeRng(&rng), 0); +#endif + return EXPECT_RESULT(); +} + +int test_wc_Pkcs11_RsaKeyGenError(void) +{ + EXPECT_DECLS; +#ifdef TEST_PKCS11_RSA_KEYGEN + Pkcs11Token token; + CK_FUNCTION_LIST func; + RsaKey key; +#ifdef TEST_PKCS11_EC_KEYGEN + ecc_key ecc; +#endif + WC_RNG rng; +#if defined(HAVE_WOLF_BIGINT) && defined(USE_WOLFSSL_MEMORY) && \ + !defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) + int haveAlloc = 0; +#endif + + test_pkcs11_store_setup(&token, &func); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_PKCS11_DEVID, + wc_Pkcs11_CryptoDevCb, &token), 0); + +#if defined(HAVE_WOLF_BIGINT) && defined(USE_WOLFSSL_MEMORY) && \ + !defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) + /* Freeing the key on the device must still free its software parts. */ + ExpectIntEQ(wolfSSL_GetAllocators(&test_pkcs11_mf, &test_pkcs11_ff, + &test_pkcs11_rf), 0); + if (EXPECT_SUCCESS()) { + test_pkcs11_live = 0; + ExpectIntEQ(wolfSSL_SetAllocators(test_pkcs11_malloc, + test_pkcs11_free, test_pkcs11_realloc), 0); + haveAlloc = EXPECT_SUCCESS(); + } +#endif + ExpectIntEQ(wc_InitRsaKey_ex(&key, NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MakeRsaKey(&key, 2048, WC_RSA_EXPONENT, &rng), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 1); + ExpectNotNull(key.devCtx); + test_pkcs11_find_calls = 0; + test_pkcs11_modulus_reads = 0; + ExpectIntEQ(test_pkcs11_rsa_decrypt(&token, &key), 0); + ExpectIntEQ(test_pkcs11_find_calls, 0); + ExpectIntEQ(test_pkcs11_modulus_reads, 0); + ExpectIntEQ(wc_FreeRsaKey(&key), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); +#if defined(HAVE_WOLF_BIGINT) && defined(USE_WOLFSSL_MEMORY) && \ !defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFSSL_DEBUG_MEMORY) if (haveAlloc) { (void)wolfSSL_SetAllocators(test_pkcs11_mf, test_pkcs11_ff, @@ -1422,4 +2357,246 @@ int test_wc_Pkcs11_RsaKeyGenError(void) return EXPECT_RESULT(); } +int test_wc_Pkcs11_KeyGenPersistent(void) +{ + EXPECT_DECLS; +#ifdef TEST_PKCS11_EC_KEYGEN + static const byte id[] = { 0x21, 0x22 }; + Pkcs11Token token; + CK_FUNCTION_LIST func; + ecc_key soft; + ecc_key key; + WC_RNG rng; + word32 len = sizeof(test_pkcs11_ec_point) - 2; + TestPkcs11Obj* priv = NULL; + TestPkcs11Obj* pub = NULL; +#ifdef TEST_PKCS11_RSA_KEYGEN + RsaKey rsa; +#endif + + test_pkcs11_store_setup(&token, &func); + XMEMSET(&soft, 0, sizeof(soft)); + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(test_pkcs11_make_ecc(&soft, &rng, id, (int)sizeof(id)), 0); + test_pkcs11_ec_point[0] = ASN_OCTET_STRING; + test_pkcs11_ec_point[1] = (byte)len; + ExpectIntEQ(wc_ecc_export_x963(&soft, test_pkcs11_ec_point + 2, &len), 0); + ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_PKCS11_DEVID, + wc_Pkcs11_CryptoDevCb, &token), 0); + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(NULL, 1), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + + /* A token that only reports the public point of token objects. */ + test_pkcs11_session_no_point = 1; + ExpectIntEQ(wc_ecc_init_id(&key, (unsigned char*)id, (int)sizeof(id), + NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_ecc_make_key_ex2(&rng, 32, &key, ECC_SECP256R1, + WC_ECC_FLAG_DEC_SIGN), WC_NO_ERR_TRACE(WC_HW_E)); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 1), 0); + ExpectIntEQ(wc_ecc_make_key_ex2(&rng, 32, &key, ECC_SECP256R1, + WC_ECC_FLAG_DEC_SIGN), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectNotNull(priv = test_pkcs11_obj((CK_OBJECT_HANDLE)(wc_ptr_t) + key.devCtx)); + if (priv != NULL) { + ExpectIntEQ(priv->cls, CKO_PRIVATE_KEY); + ExpectIntEQ(priv->onToken, CK_TRUE); + ExpectIntEQ(priv->idLen, sizeof(id)); + } + ExpectNotNull(pub = test_pkcs11_obj(test_pkcs11_find_obj(CKO_PUBLIC_KEY, + CK_TRUE))); + if (pub != NULL) + ExpectIntEQ(pub->idLen, sizeof(id)); + wc_ecc_free(&key); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + + /* The id is taken now. */ + ExpectIntEQ(wc_ecc_init_id(&key, (unsigned char*)id, (int)sizeof(id), + NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_ecc_make_key_ex2(&rng, 32, &key, ECC_SECP256R1, + WC_ECC_FLAG_DEC_SIGN), WC_NO_ERR_TRACE(BAD_STATE_E)); + wc_ecc_free(&key); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + + /* A key without a name, like a TLS ephemeral key, is a session key. */ + test_pkcs11_session_no_point = 0; + ExpectIntEQ(wc_ecc_init_ex(&key, NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_ecc_make_key_ex2(&rng, 32, &key, ECC_SECP256R1, + WC_ECC_FLAG_DEC_SIGN), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 1); + wc_ecc_free(&key); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + +#ifdef TEST_PKCS11_RSA_KEYGEN + test_pkcs11_reset(); + ExpectIntEQ(wc_InitRsaKey_Id(&rsa, (unsigned char*)id, (int)sizeof(id), + NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MakeRsaKey(&rsa, 2048, WC_RSA_EXPONENT, &rng), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectNotNull(pub = test_pkcs11_obj(test_pkcs11_find_obj(CKO_PUBLIC_KEY, + CK_TRUE))); + if (pub != NULL) + ExpectIntEQ(pub->idLen, sizeof(id)); + ExpectIntEQ(test_pkcs11_token_keys_protected(), 1); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(wc_FreeRsaKey(&rsa), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + + /* A token key outlives a session that closes. */ + test_pkcs11_reset(); + func.C_OpenSession = test_pkcs11_open_session; + func.C_CloseSession = test_pkcs11_close_session; + token.handle = 0; + ExpectIntEQ(wc_InitRsaKey_Id(&rsa, (unsigned char*)id, (int)sizeof(id), + NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_MakeRsaKey(&rsa, 2048, WC_RSA_EXPONENT, &rng), 0); + ExpectNull(rsa.devCtx); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 0); + ExpectIntEQ(wc_FreeRsaKey(&rsa), 0); + token.handle = 1; +#endif + + test_pkcs11_reset(); + test_pkcs11_session_no_point = 0; + ExpectIntEQ(wc_Pkcs11Token_SetKeyGenPersistent(&token, 0), 0); + ExpectIntEQ(wc_ecc_init_id(&key, (unsigned char*)id, (int)sizeof(id), + NULL, TEST_PKCS11_DEVID), 0); + ExpectIntEQ(wc_ecc_make_key_ex2(&rng, 32, &key, ECC_SECP256R1, + WC_ECC_FLAG_DEC_SIGN), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 0); + ExpectIntEQ(test_pkcs11_count(CK_FALSE), 1); + wc_ecc_free(&key); + + wc_CryptoCb_UnRegisterDevice(TEST_PKCS11_DEVID); + wc_ecc_free(&soft); + DoExpectIntEQ(wc_FreeRng(&rng), 0); +#endif + return EXPECT_RESULT(); +} + +static int test_pkcs11_add_token_key(const char* label, byte idByte) +{ + static CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; + static CK_KEY_TYPE ecType = CKK_EC; + static CK_BBOOL isToken = CK_TRUE; + byte id[1]; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &ecType, sizeof(ecType) }, + { CKA_TOKEN, &isToken, sizeof(isToken) }, + { CKA_ID, id, sizeof(id) }, + { CKA_LABEL, (void*)label, 0 } + }; + CK_OBJECT_HANDLE h = 0; + + id[0] = idByte; + tmpl[4].ulValueLen = (CK_ULONG)XSTRLEN(label); + if (test_pkcs11_store_create(0, tmpl, 5, &h) != CKR_OK) + return 0; + return (int)h; +} + +static void test_pkcs11_name_key(ecc_key* key, byte idByte, const char* label) +{ + key->id[0] = idByte; + key->idLen = 1; + key->labelLen = (int)XSTRLEN(label); + XMEMCPY(key->label, label, (size_t)key->labelLen); +} + +int test_wc_Pkcs11_KeyNames(void) +{ + static const byte id[] = { 0x31 }; + static byte certId[] = { 0x61 }; + static CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; + static CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; + static CK_KEY_TYPE ecType = CKK_EC; + static CK_BBOOL onToken = CK_TRUE; + CK_ATTRIBUTE sess[] = { + { CKA_CLASS, &privClass, sizeof(privClass) }, + { CKA_KEY_TYPE, &ecType, sizeof(ecType) } + }; + CK_ATTRIBUTE cert[] = { + { CKA_CLASS, &certClass, sizeof(certClass) }, + { CKA_TOKEN, &onToken, sizeof(onToken) }, + { CKA_ID, certId, sizeof(certId) } + }; + Pkcs11Token token; + CK_FUNCTION_LIST func; + CK_OBJECT_HANDLE sessObj = 0; + CK_OBJECT_HANDLE certObj = 0; + ecc_key key; + ecc_key noName; + WC_RNG rng; + int other = 0; + EXPECT_DECLS; + + test_pkcs11_store_setup(&token, &func); + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&noName, 0, sizeof(noName)); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(test_pkcs11_make_ecc(&key, &rng, id, (int)sizeof(id)), 0); + ExpectIntEQ(wc_ecc_init(&noName), 0); + ExpectIntEQ(wc_ecc_make_key(&rng, 32, &noName), 0); + + /* A persistent import needs a name that no token key has. */ + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &noName, + 1), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + 0); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + WC_NO_ERR_TRACE(BAD_STATE_E)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 2); + + /* Either name in use makes a duplicate. */ + test_pkcs11_reset(); + ExpectIntNE(test_pkcs11_add_token_key("old", 0x41), 0); + test_pkcs11_name_key(&key, 0x41, "new"); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + WC_NO_ERR_TRACE(BAD_STATE_E)); + test_pkcs11_name_key(&key, 0x42, "old"); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + WC_NO_ERR_TRACE(BAD_STATE_E)); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + + /* A certificate with the key's id does not block the key. */ + test_pkcs11_reset(); + ExpectIntEQ(test_pkcs11_store_create(0, cert, 3, &certObj), CKR_OK); + test_pkcs11_name_key(&key, 0x61, ""); + ExpectIntEQ(wc_Pkcs11StoreKey_ex(&token, PKCS11_KEY_TYPE_EC, 0, &key, 1), + 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 3); + + /* A delete only removes keys with both the id and the label. */ + test_pkcs11_reset(); + ExpectIntNE(test_pkcs11_add_token_key("shared", 0x51), 0); + ExpectIntNE(other = test_pkcs11_add_token_key("shared", 0x52), 0); + test_pkcs11_name_key(&key, 0x51, "shared"); + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_EC, &key), 0); + ExpectIntEQ(test_pkcs11_count(CK_TRUE), 1); + ExpectNotNull(test_pkcs11_obj((CK_OBJECT_HANDLE)other)); + + /* A key without a name is rejected before its session key is touched. */ + ExpectIntEQ(test_pkcs11_store_create(0, sess, 2, &sessObj), CKR_OK); + noName.devCtx = (void*)(wc_ptr_t)sessObj; + ExpectIntEQ(wc_Pkcs11DeleteKey(&token, PKCS11_KEY_TYPE_EC, &noName), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectPtrEq(noName.devCtx, (void*)(wc_ptr_t)sessObj); + ExpectNotNull(test_pkcs11_obj(sessObj)); + noName.devCtx = NULL; + + wc_ecc_free(&key); + wc_ecc_free(&noName); + DoExpectIntEQ(wc_FreeRng(&rng), 0); + + return EXPECT_RESULT(); +} + #endif diff --git a/tests/api/test_pkcs11.h b/tests/api/test_pkcs11.h index ff7089a6729..ba1ea743766 100644 --- a/tests/api/test_pkcs11.h +++ b/tests/api/test_pkcs11.h @@ -30,22 +30,42 @@ int test_wc_Pkcs11_EcdsaSigDecode(void); int test_wc_Pkcs11_FreeKeepsTokenKey(void); +int test_wc_Pkcs11_StoreKeyPersistent(void); +int test_wc_Pkcs11_PersistKey(void); +int test_wc_Pkcs11_DeleteKey(void); int test_wc_Pkcs11_RsaIdNoLeak(void); int test_wc_Pkcs11_EcKeyUsage(void); int test_wc_Pkcs11_RsaKeyGenError(void); int test_wc_Pkcs11_RsaKeyGenExponent(void); +int test_wc_Pkcs11_KeyGenPersistent(void); +int test_wc_Pkcs11_KeyNames(void); int test_wc_Pkcs11_FreeNoObject(void); int test_wc_Pkcs11_KeyGenSessionClosed(void); +int test_wc_Pkcs11_SecretKeyPersist(void); +int test_wc_Pkcs11_RsaPersistDelete(void); +int test_wc_Pkcs11_PqcPersistDelete(void); +int test_wc_Pkcs11_PersistPaths(void); +int test_wc_Pkcs11_PqcKeyGen(void); #define TEST_PKCS11_DECLS \ TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_EcdsaSigDecode), \ TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_FreeKeepsTokenKey), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_StoreKeyPersistent), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_PersistKey), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_DeleteKey), \ TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_RsaIdNoLeak), \ TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_EcKeyUsage), \ TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_RsaKeyGenError), \ TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_RsaKeyGenExponent), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_KeyGenPersistent), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_KeyNames), \ TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_FreeNoObject), \ - TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_KeyGenSessionClosed) + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_KeyGenSessionClosed), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_SecretKeyPersist), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_RsaPersistDelete), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_PqcPersistDelete), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_PersistPaths), \ + TEST_DECL_GROUP("pkcs11", test_wc_Pkcs11_PqcKeyGen) #else diff --git a/wolfcrypt/src/wc_pkcs11.c b/wolfcrypt/src/wc_pkcs11.c index 09bdb96613d..f4c2ff186e8 100644 --- a/wolfcrypt/src/wc_pkcs11.c +++ b/wolfcrypt/src/wc_pkcs11.c @@ -75,8 +75,10 @@ #endif -#if (defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH)) || \ - defined(WOLFSSL_HAVE_MLKEM) +#if (!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || defined(HAVE_ECC) || \ + defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) || \ + (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ + !defined(NO_HMAC) /* Pointer to false required for templates. */ static CK_BBOOL ckFalse = CK_FALSE; #endif @@ -88,6 +90,30 @@ static CK_BBOOL ckFalse = CK_FALSE; static CK_BBOOL ckTrue = CK_TRUE; #endif +#if (!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || defined(HAVE_ECC) || \ + defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) || \ + (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ + !defined(NO_HMAC) +/* Attributes of a private or secret key created as a token object. */ +static CK_ATTRIBUTE pkcs11TokenKeyAttrs[] = { + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse) } +}; +#define PKCS11_TOKEN_KEY_ATTRS 4 +#endif + +#if (!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || defined(HAVE_ECC) || \ + defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) +/* Attributes of a public key created as a token object. */ +static CK_ATTRIBUTE pkcs11TokenPubKeyAttrs[] = { + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) } +}; +#define PKCS11_TOKEN_PUB_KEY_ATTRS 2 +#endif + #ifndef NO_RSA /* Pointer to RSA key type required for templates. */ static CK_KEY_TYPE rsaKeyType = CKK_RSA; @@ -243,7 +269,10 @@ static void pkcs11_dump_template(const char* name, CK_ATTRIBUTE* templ, } else #endif -#if defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH) +#if (!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || defined(HAVE_ECC) || \ + defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) || \ + (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ + !defined(NO_HMAC) if (templ[i].pValue == &ckFalse) { XSNPRINTF(line, sizeof(line), "%25s: FALSE", type); WOLFSSL_MSG(line); @@ -957,6 +986,7 @@ static int Pkcs11Token_Init(Pkcs11Token* token, Pkcs11Dev* dev, int slotId, token->userPin = NULL_PTR; token->userPinSz = 0; token->userPinLogin = 0; + token->keyGenOnToken = 0; token->version = dev->version; } @@ -1135,6 +1165,7 @@ static int Pkcs11OpenSession(Pkcs11Token* token, Pkcs11Session* session, session->func = token->func; session->slotId = token->slotId; session->version = token->version; + session->tokenObjects = 0; session->closes = (session->handle != token->handle); } @@ -1169,14 +1200,14 @@ static void Pkcs11CloseSession(Pkcs11Token* token, Pkcs11Session* session) * @return BAD_STATE_E when a key with an id or label would be destroyed * with a session that closes after this operation. * @return CRYPTOCB_UNAVAILABLE when such a key has no id or label. - * @return 0 when the session stays open. + * @return 0 when the session stays open or the key is a token object. */ static int Pkcs11KeyGenSessionCheck(Pkcs11Session* session, int idLen, int labelLen) { int ret = 0; - if (session->closes) + if (session->closes && !session->tokenObjects) ret = (idLen > 0 || labelLen > 0) ? BAD_STATE_E : CRYPTOCB_UNAVAILABLE; return ret; @@ -1226,8 +1257,55 @@ void wc_Pkcs11Token_Close(Pkcs11Token* token) } } -#if (!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || defined(HAVE_ECC) || \ - defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) +/** + * Set whether RSA, ECC, ML-DSA and ML-KEM key generation creates token objects. + * + * @param [in] token Token object. + * @param [in] persistent Generate token objects when non-zero. + * @return BAD_FUNC_ARG when token is NULL. + * @return 0 on success. + */ +int wc_Pkcs11Token_SetKeyGenPersistent(Pkcs11Token* token, int persistent) +{ + if (token == NULL) + return BAD_FUNC_ARG; + + token->keyGenOnToken = (persistent != 0); + return 0; +} + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(WOLFSSL_HAVE_MLDSA) || \ + defined(WOLFSSL_HAVE_MLKEM) || (!defined(NO_AES) && \ + (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || !defined(NO_HMAC) +/** + * Read whether a key object is a token object. + * + * @param [in] session Session object. + * @param [in] handle Handle of key object. + * @param [out] onToken CK_TRUE for a token object. + * @return WC_HW_E when CKA_TOKEN cannot be read. + * @return 0 on success. + */ +static int Pkcs11KeyOnToken(Pkcs11Session* session, CK_OBJECT_HANDLE handle, + CK_BBOOL* onToken) +{ + int ret = 0; + CK_RV rv; + CK_ATTRIBUTE tmpl[] = { + { CKA_TOKEN, onToken, sizeof(*onToken) } + }; + + rv = session->func->C_GetAttributeValue(session->handle, handle, tmpl, 1); + PKCS11_RV("C_GetAttributeValue", rv); + if (rv != CKR_OK || tmpl[0].ulValueLen != sizeof(*onToken)) + ret = WC_HW_E; + + return ret; +} +#endif + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(WOLFSSL_HAVE_MLDSA) || \ + defined(WOLFSSL_HAVE_MLKEM) /** * Destroy a key object only when it is a session object. * Token objects, and objects whose CKA_TOKEN cannot be read, are kept. @@ -1238,19 +1316,15 @@ void wc_Pkcs11Token_Close(Pkcs11Token* token) static void Pkcs11DestroySessionKey(Pkcs11Session* session, CK_OBJECT_HANDLE handle) { - CK_RV rv; - CK_BBOOL onToken = CK_TRUE; - CK_ATTRIBUTE tmpl[] = { - { CKA_TOKEN, &onToken, sizeof(onToken) } - }; + CK_RV rv = CKR_OK; + CK_BBOOL onToken = CK_TRUE; - rv = session->func->C_GetAttributeValue(session->handle, handle, tmpl, 1); - PKCS11_RV("C_GetAttributeValue", rv); - if (rv == CKR_OK && tmpl[0].ulValueLen == sizeof(onToken) && + if (Pkcs11KeyOnToken(session, handle, &onToken) == 0 && onToken == CK_FALSE) { rv = session->func->C_DestroyObject(session->handle, handle); PKCS11_RV("C_DestroyObject", rv); } + (void)rv; } #endif @@ -1280,7 +1354,7 @@ static int Pkcs11CreateSecretKey(CK_OBJECT_HANDLE* key, Pkcs11Session* session, { int ret = 0; CK_RV rv; - /* Empty entries for optional label/ID. */ + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE keyTemplateEncDec[] = { { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, @@ -1288,9 +1362,13 @@ static int Pkcs11CreateSecretKey(CK_OBJECT_HANDLE* key, Pkcs11Session* session, { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_VALUE, NULL, 0 }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; - /* Empty entries for optional label/ID. */ + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE keyTemplateSignVfy[] = { { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, @@ -1298,10 +1376,14 @@ static int Pkcs11CreateSecretKey(CK_OBJECT_HANDLE* key, Pkcs11Session* session, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_VALUE, NULL, 0 }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; CK_ATTRIBUTE* keyTemplate = NULL; - /* 5 mandatory entries + 2 optional. */ + /* 5 mandatory entries + 6 optional. */ int keyTmplCnt = 5; WOLFSSL_MSG("PKCS#11: Create Secret Key"); @@ -1333,6 +1415,11 @@ static int Pkcs11CreateSecretKey(CK_OBJECT_HANDLE* key, Pkcs11Session* session, keyTemplate[keyTmplCnt].ulValueLen = idLen; keyTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&keyTemplate[keyTmplCnt], pkcs11TokenKeyAttrs, + sizeof(pkcs11TokenKeyAttrs)); + keyTmplCnt += PKCS11_TOKEN_KEY_ATTRS; + } PKCS11_DUMP_TEMPLATE("Secret Key", keyTemplate, keyTmplCnt); /* Create an object containing key data for device to use. */ @@ -1364,7 +1451,7 @@ static int Pkcs11CreateRsaPrivateKey(CK_OBJECT_HANDLE* privateKey, { int ret = 0; CK_RV rv; - /* Empty entries for optional label/ID. */ + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, @@ -1379,10 +1466,14 @@ static int Pkcs11CreateRsaPrivateKey(CK_OBJECT_HANDLE* privateKey, { CKA_COEFFICIENT, NULL, 0 }, { CKA_PUBLIC_EXPONENT, NULL, 0 }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; - /* Mandatory entries + 2 optional. */ - CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; + /* Mandatory entries + 6 optional. */ + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 6; /* Set the modulus and private key data. */ keyTemplate[ 4].pValue = rsaKey->n.raw.buf; @@ -1414,6 +1505,11 @@ static int Pkcs11CreateRsaPrivateKey(CK_OBJECT_HANDLE* privateKey, keyTemplate[keyTmplCnt].ulValueLen = rsaKey->idLen; keyTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&keyTemplate[keyTmplCnt], pkcs11TokenKeyAttrs, + sizeof(pkcs11TokenKeyAttrs)); + keyTmplCnt += PKCS11_TOKEN_KEY_ATTRS; + } PKCS11_DUMP_TEMPLATE("RSA Private Key", keyTemplate, keyTmplCnt); rv = session->func->C_CreateObject(session->handle, keyTemplate, keyTmplCnt, @@ -1425,6 +1521,92 @@ static int Pkcs11CreateRsaPrivateKey(CK_OBJECT_HANDLE* privateKey, return ret; } + +/** + * Create a PKCS#11 object containing the RSA public key data. + * + * @param [out] publicKey Handle to public key object. + * @param [in] session Session object. + * @param [in] rsaKey RSA key with the modulus and public exponent. + * @return BAD_FUNC_ARG when the modulus or exponent is zero. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return MEMORY_E when a memory allocation fails. + * @return 0 on success. + */ +static int Pkcs11CreateRsaPublicKey(CK_OBJECT_HANDLE* publicKey, + Pkcs11Session* session, RsaKey* rsaKey) +{ + int ret = 0; + CK_RV rv; + byte* data = NULL; + int modSz; + int expSz; + /* Empty entries for optional label/ID/token. */ + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType) }, + { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, + { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { CKA_MODULUS, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 } + }; + /* Mandatory entries + 4 optional. */ + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 4; + + modSz = mp_unsigned_bin_size(&rsaKey->n); + expSz = mp_unsigned_bin_size(&rsaKey->e); + if (modSz <= 0 || expSz <= 0) + ret = BAD_FUNC_ARG; + if (ret == 0) { + data = (byte*)XMALLOC((size_t)(modSz + expSz), rsaKey->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (data == NULL) + ret = MEMORY_E; + } + if (ret == 0) + ret = mp_to_unsigned_bin(&rsaKey->n, data); + if (ret == 0) + ret = mp_to_unsigned_bin(&rsaKey->e, data + modSz); + if (ret == 0) { + keyTemplate[4].pValue = data; + keyTemplate[4].ulValueLen = (CK_ULONG)modSz; + keyTemplate[5].pValue = data + modSz; + keyTemplate[5].ulValueLen = (CK_ULONG)expSz; + if (rsaKey->labelLen > 0) { + keyTemplate[keyTmplCnt].type = CKA_LABEL; + keyTemplate[keyTmplCnt].pValue = rsaKey->label; + keyTemplate[keyTmplCnt].ulValueLen = rsaKey->labelLen; + keyTmplCnt++; + } + if (rsaKey->idLen > 0) { + keyTemplate[keyTmplCnt].type = CKA_ID; + keyTemplate[keyTmplCnt].pValue = rsaKey->id; + keyTemplate[keyTmplCnt].ulValueLen = rsaKey->idLen; + keyTmplCnt++; + } + if (session->tokenObjects) { + XMEMCPY(&keyTemplate[keyTmplCnt], pkcs11TokenPubKeyAttrs, + sizeof(pkcs11TokenPubKeyAttrs)); + keyTmplCnt += PKCS11_TOKEN_PUB_KEY_ATTRS; + } + + PKCS11_DUMP_TEMPLATE("RSA Public Key", keyTemplate, keyTmplCnt); + rv = session->func->C_CreateObject(session->handle, keyTemplate, + keyTmplCnt, publicKey); + PKCS11_RV("C_CreateObject", rv); + if (rv != CKR_OK) { + ret = WC_HW_E; + } + } + + XFREE(data, rsaKey->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} #endif /* !NO_RSA && WOLFSSL_KEY_GEN */ #ifdef HAVE_ECC @@ -1489,7 +1671,7 @@ static int Pkcs11CreateEccPublicKey(CK_OBJECT_HANDLE* publicKey, word32 len; CK_RV rv; CK_UTF8CHAR params[ECC_MAX_OID_LEN]; - /* Empty entries for optional label/ID. */ + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, { CKA_KEY_TYPE, &ecKeyType, sizeof(ecKeyType) }, @@ -1497,10 +1679,12 @@ static int Pkcs11CreateEccPublicKey(CK_OBJECT_HANDLE* publicKey, { CKA_EC_PARAMS, params, 0 }, { CKA_EC_POINT, NULL, 0 }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; - /* Mandatory entries + 2 optional. */ - CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; + /* Mandatory entries + 4 optional. */ + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 4; if (public_key->labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; @@ -1514,6 +1698,11 @@ static int Pkcs11CreateEccPublicKey(CK_OBJECT_HANDLE* publicKey, keyTemplate[keyTmplCnt].ulValueLen = public_key->idLen; keyTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&keyTemplate[keyTmplCnt], pkcs11TokenPubKeyAttrs, + sizeof(pkcs11TokenPubKeyAttrs)); + keyTmplCnt += PKCS11_TOKEN_PUB_KEY_ATTRS; + } ret = Pkcs11EccSetParams(public_key, keyTemplate, 3); if (ret == 0) { @@ -1572,7 +1761,7 @@ static int Pkcs11CreateEccPrivateKey(CK_OBJECT_HANDLE* privateKey, int ret = 0; CK_RV rv; CK_UTF8CHAR params[ECC_MAX_OID_LEN]; - /* Empty entries for optional sign/derive/label/ID. */ + /* Empty entries for optional sign/derive/label/ID/token. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &ecKeyType, sizeof(ecKeyType) }, @@ -1581,10 +1770,14 @@ static int Pkcs11CreateEccPrivateKey(CK_OBJECT_HANDLE* privateKey, { 0, NULL, 0 }, { 0, NULL, 0 }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; - /* Mandatory entries + 4 optional. */ - CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 4; + /* Mandatory entries + 8 optional. */ + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 8; if ((usage & PKCS11_ECC_SIGN) != 0) { keyTemplate[keyTmplCnt].type = CKA_SIGN; @@ -1611,6 +1804,11 @@ static int Pkcs11CreateEccPrivateKey(CK_OBJECT_HANDLE* privateKey, keyTemplate[keyTmplCnt].ulValueLen = private_key->idLen; keyTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&keyTemplate[keyTmplCnt], pkcs11TokenKeyAttrs, + sizeof(pkcs11TokenKeyAttrs)); + keyTmplCnt += PKCS11_TOKEN_KEY_ATTRS; + } ret = Pkcs11EccSetParams(private_key, keyTemplate, 2); if (ret == 0) { @@ -1668,9 +1866,11 @@ static int Pkcs11CreateMlKemPublicKey(CK_OBJECT_HANDLE* handle, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, }; CK_ULONG keyTmplCnt = - sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; + sizeof(keyTemplate) / sizeof(*keyTemplate) - 4; if (mechInfo == NULL || (key->flags & MLKEM_FLAG_PUB_SET) == 0) { ret = BAD_FUNC_ARG; @@ -1687,6 +1887,11 @@ static int Pkcs11CreateMlKemPublicKey(CK_OBJECT_HANDLE* handle, keyTemplate[keyTmplCnt].ulValueLen = key->idLen; keyTmplCnt++; } + if (ret == 0 && session->tokenObjects) { + XMEMCPY(&keyTemplate[keyTmplCnt], pkcs11TokenPubKeyAttrs, + sizeof(pkcs11TokenPubKeyAttrs)); + keyTmplCnt += PKCS11_TOKEN_PUB_KEY_ATTRS; + } if (ret == 0) { switch (key->type) { #ifndef WOLFSSL_NO_ML_KEM @@ -1766,9 +1971,13 @@ static int Pkcs11CreateMlKemPrivateKey(CK_OBJECT_HANDLE* privateKey, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, }; CK_ULONG keyTmplCnt = - sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; + sizeof(keyTemplate) / sizeof(*keyTemplate) - 6; if (mechInfo == NULL || (key->flags & MLKEM_FLAG_PRIV_SET) == 0) { ret = BAD_FUNC_ARG; @@ -1785,6 +1994,11 @@ static int Pkcs11CreateMlKemPrivateKey(CK_OBJECT_HANDLE* privateKey, keyTemplate[keyTmplCnt].ulValueLen = key->idLen; keyTmplCnt++; } + if (ret == 0 && session->tokenObjects) { + XMEMCPY(&keyTemplate[keyTmplCnt], pkcs11TokenKeyAttrs, + sizeof(pkcs11TokenKeyAttrs)); + keyTmplCnt += PKCS11_TOKEN_KEY_ATTRS; + } if (ret == 0) { switch (key->type) { #ifndef WOLFSSL_NO_ML_KEM @@ -1869,7 +2083,7 @@ static int Pkcs11CreateMldsaPublicKey(CK_OBJECT_HANDLE* handle, CK_RV rv; CK_ULONG publicKeyLen = 0; CK_ML_DSA_PARAMETER_SET_TYPE param_set = 0; - /* Empty entries for optional label/ID. */ + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, { CKA_KEY_TYPE, &mldsaKeyType, sizeof(mldsaKeyType) }, @@ -1878,9 +2092,11 @@ static int Pkcs11CreateMldsaPublicKey(CK_OBJECT_HANDLE* handle, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, }; - /* Mandatory entries + 2 optional. */ - CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; + /* Mandatory entries + 4 optional. */ + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 4; if (!key->pubKeySet) { ret = PUBLIC_KEY_E; @@ -1898,6 +2114,11 @@ static int Pkcs11CreateMldsaPublicKey(CK_OBJECT_HANDLE* handle, keyTemplate[keyTmplCnt].ulValueLen = key->idLen; keyTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&keyTemplate[keyTmplCnt], pkcs11TokenPubKeyAttrs, + sizeof(pkcs11TokenPubKeyAttrs)); + keyTmplCnt += PKCS11_TOKEN_PUB_KEY_ATTRS; + } if ((key->level == WC_ML_DSA_44) && (mechInfo->ulMinKeySize <= WC_MLDSA_44_PUB_KEY_SIZE) && @@ -1956,7 +2177,7 @@ static int Pkcs11CreateMldsaPrivateKey(CK_OBJECT_HANDLE* privateKey, CK_RV rv; CK_ULONG privateKeyLen = 0; CK_ML_DSA_PARAMETER_SET_TYPE param_set = 0; - /* Empty entries for optional label/ID. */ + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE keyTemplate[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_KEY_TYPE, &mldsaKeyType, sizeof(mldsaKeyType) }, @@ -1964,10 +2185,14 @@ static int Pkcs11CreateMldsaPrivateKey(CK_OBJECT_HANDLE* privateKey, { CKA_VALUE, NULL, 0 }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; - /* Mandatory entries + 2 optional. */ - CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; + /* Mandatory entries + 6 optional. */ + CK_ULONG keyTmplCnt = sizeof(keyTemplate) / sizeof(*keyTemplate) - 6; if (key->labelLen > 0) { keyTemplate[keyTmplCnt].type = CKA_LABEL; @@ -1981,6 +2206,11 @@ static int Pkcs11CreateMldsaPrivateKey(CK_OBJECT_HANDLE* privateKey, keyTemplate[keyTmplCnt].ulValueLen = key->idLen; keyTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&keyTemplate[keyTmplCnt], pkcs11TokenKeyAttrs, + sizeof(pkcs11TokenKeyAttrs)); + keyTmplCnt += PKCS11_TOKEN_KEY_ATTRS; + } if ((key->level == WC_ML_DSA_44) && (mechInfo->ulMinKeySize <= WC_MLDSA_44_PUB_KEY_SIZE) && @@ -2168,6 +2398,14 @@ static int Pkcs11HmacTypes(int macType, int* mechType, int* keyType) } #endif +#if (!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || defined(HAVE_ECC) || \ + defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) || \ + (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ + !defined(NO_HMAC) +static int Pkcs11CheckNewTokenKey(Pkcs11Session* session, CK_KEY_TYPE keyType, + byte* id, int idLen, char* label, int labelLen); +#endif + /** * Store the private key on the token in the session. * @@ -2175,7 +2413,7 @@ static int Pkcs11HmacTypes(int macType, int* mechType, int* keyType) * @param [in] type Key type. * @param [in] clear Clear out the private data from software key. * @param [in] key Key type specific object. - * @return BAD_FUNC_ARG when token is NULL. + * @return BAD_FUNC_ARG when token or key is NULL. * @return BAD_STATE_E when the token has no session from * wc_Pkcs11Token_Open, so the key would go with this call's session. * @return MEMORY_E when a memory allocation fails. @@ -2184,24 +2422,54 @@ static int Pkcs11HmacTypes(int macType, int* mechType, int* keyType) * @return 0 on success. */ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) +{ + return wc_Pkcs11StoreKey_ex(token, type, clear, key, 0); +} + +/** + * Store the private key on the token, in the session or persistently. + * + * @param [in] token Token to store private key on. + * @param [in] type Key type. + * @param [in] clear Clear out the private data from software key. + * @param [in] key Key type specific object. + * @param [in] persistent Create token objects (CKA_TOKEN set). + * @return BAD_FUNC_ARG when token or key is NULL, or a persistent key has + * neither id nor label. + * @return BAD_STATE_E when persistent is 0 and the token has no session + * from wc_Pkcs11Token_Open, or a token key of the type already has + * the persistent key's id or label. + * @return MEMORY_E when a memory allocation fails. + * @return NOT_COMPILED_IN when mechanism not available. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return 0 on success. + */ +int wc_Pkcs11StoreKey_ex(Pkcs11Token* token, int type, int clear, void* key, + int persistent) { int ret = 0; Pkcs11Session session; CK_OBJECT_HANDLE privKey = NULL_PTR; - if (token == NULL) + if (token == NULL || key == NULL) ret = BAD_FUNC_ARG; - else if (token->handle == NULL_PTR) + else if (token->handle == NULL_PTR && !persistent) ret = BAD_STATE_E; else ret = Pkcs11OpenSession(token, &session, 1); if (ret == 0) { + session.tokenObjects = (persistent != 0); switch (type) { #if !defined(NO_AES) && defined(HAVE_AESGCM) case PKCS11_KEY_TYPE_AES_GCM: { Aes* aes = (Aes*)key; ret = Pkcs11MechAvail(&session, CKM_AES_GCM, NULL); + if (ret == 0 && persistent) { + ret = Pkcs11CheckNewTokenKey(&session, CKK_AES, + (byte*)aes->id, aes->idLen, aes->label, + aes->labelLen); + } if (ret == 0) { ret = Pkcs11CreateSecretKey(&privKey, &session, CKK_AES, (unsigned char*)aes->devKey, @@ -2220,6 +2488,11 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) Aes* aes = (Aes*)key; ret = Pkcs11MechAvail(&session, CKM_AES_CBC, NULL); + if (ret == 0 && persistent) { + ret = Pkcs11CheckNewTokenKey(&session, CKK_AES, + (byte*)aes->id, aes->idLen, aes->label, + aes->labelLen); + } if (ret == 0) { ret = Pkcs11CreateSecretKey(&privKey, &session, CKK_AES, (unsigned char*)aes->devKey, @@ -2245,6 +2518,16 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) if (ret == 0) ret = Pkcs11MechAvail(&session, mechType, NULL); + if (ret == 0 && persistent) { + ret = Pkcs11CheckNewTokenKey(&session, (CK_KEY_TYPE)keyType, + (byte*)hmac->id, hmac->idLen, hmac->label, + hmac->labelLen); + } + if (ret == 0 && persistent) { + ret = Pkcs11CheckNewTokenKey(&session, CKK_GENERIC_SECRET, + (byte*)hmac->id, hmac->idLen, hmac->label, + hmac->labelLen); + } if (ret == 0) { ret = Pkcs11CreateSecretKey(&privKey, &session, keyType, (unsigned char*)hmac->keyRaw, @@ -2270,9 +2553,22 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) RsaKey* rsaKey = (RsaKey*)key; ret = Pkcs11MechAvail(&session, CKM_RSA_X_509, NULL); + if (ret == 0 && persistent) { + ret = Pkcs11CheckNewTokenKey(&session, CKK_RSA, + (byte*)rsaKey->id, rsaKey->idLen, rsaKey->label, + rsaKey->labelLen); + } if (ret == 0) ret = Pkcs11CreateRsaPrivateKey(&privKey, &session, rsaKey, 1); + if (ret == 0 && persistent) { + CK_OBJECT_HANDLE pubKey = NULL_PTR; + + ret = Pkcs11CreateRsaPublicKey(&pubKey, &session, rsaKey); + if (ret != 0) { + session.func->C_DestroyObject(session.handle, privKey); + } + } if (ret == 0 && clear) { mp_forcezero(&rsaKey->u); mp_forcezero(&rsaKey->dQ); @@ -2289,7 +2585,13 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) ecc_key* eccKey = (ecc_key*)key; int usage = 0; - ret = Pkcs11EccKeyUsage(&session, eccKey, &usage); + if (persistent) { + ret = Pkcs11CheckNewTokenKey(&session, CKK_EC, + (byte*)eccKey->id, eccKey->idLen, eccKey->label, + eccKey->labelLen); + } + if (ret == 0) + ret = Pkcs11EccKeyUsage(&session, eccKey, &usage); if (ret == 0) { ret = Pkcs11CreateEccPrivateKey(&privKey, &session, eccKey, usage); @@ -2319,6 +2621,11 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) CK_MECHANISM_INFO mechInfo; ret = Pkcs11MechAvail(&session, CKM_ML_KEM, &mechInfo); + if (ret == 0 && persistent) { + ret = Pkcs11CheckNewTokenKey(&session, CKK_ML_KEM, + (byte*)mlkemKey->id, mlkemKey->idLen, mlkemKey->label, + mlkemKey->labelLen); + } if (ret == 0 && ((mlkemKey->flags & MLKEM_FLAG_PRIV_SET) != 0)) { ret = Pkcs11CreateMlKemPrivateKey(&privKey, &session, mlkemKey, &mechInfo); @@ -2349,6 +2656,11 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) CK_MECHANISM_INFO mechInfo; ret = Pkcs11MechAvail(&session, CKM_ML_DSA, &mechInfo); + if (ret == 0 && persistent) { + ret = Pkcs11CheckNewTokenKey(&session, CKK_ML_DSA, + (byte*)mldsaKey->id, mldsaKey->idLen, mldsaKey->label, + mldsaKey->labelLen); + } if (ret == 0 && mldsaKey->prvKeySet) { ret = Pkcs11CreateMldsaPrivateKey(&privKey, &session, @@ -2399,7 +2711,8 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) #if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ - !defined(NO_HMAC) || !defined(NO_CERTS) + !defined(NO_HMAC) || !defined(NO_CERTS) || \ + defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) /** * Find the PKCS#11 object containing key data using template. @@ -2519,6 +2832,107 @@ static int Pkcs11FindKeyById(CK_OBJECT_HANDLE* key, CK_OBJECT_CLASS keyClass, } #endif +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(WOLFSSL_HAVE_MLDSA) || \ + defined(WOLFSSL_HAVE_MLKEM) || (!defined(NO_AES) && \ + (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || !defined(NO_HMAC) +/** + * Find key objects by id and label. An empty id or label is not matched. + * + * @param [in] session Session object. + * @param [in] keyClass Key class to match. NULL matches any class. + * @param [in] keyType Key type to match. + * @param [in] onToken Match token objects or session objects. + * @param [in] id Identifier of key. + * @param [in] idLen Length of identifier. + * @param [in] label Label of key. + * @param [in] labelLen Length of label. + * @param [out] handle Handle of first object found. + * @param [out] count Number of objects found, 0 or 1. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return 0 on success. + */ +static int Pkcs11FindKeyObject(Pkcs11Session* session, + CK_OBJECT_CLASS* keyClass, CK_KEY_TYPE keyType, CK_BBOOL onToken, + byte* id, int idLen, char* label, int labelLen, CK_OBJECT_HANDLE* handle, + CK_ULONG* count) +{ + CK_ATTRIBUTE tmpl[5]; + CK_ULONG tmplCnt = 0; + + tmpl[tmplCnt].type = CKA_KEY_TYPE; + tmpl[tmplCnt].pValue = &keyType; + tmpl[tmplCnt].ulValueLen = sizeof(keyType); + tmplCnt++; + tmpl[tmplCnt].type = CKA_TOKEN; + tmpl[tmplCnt].pValue = &onToken; + tmpl[tmplCnt].ulValueLen = sizeof(onToken); + tmplCnt++; + if (idLen > 0) { + tmpl[tmplCnt].type = CKA_ID; + tmpl[tmplCnt].pValue = id; + tmpl[tmplCnt].ulValueLen = (CK_ULONG)idLen; + tmplCnt++; + } + if (labelLen > 0) { + tmpl[tmplCnt].type = CKA_LABEL; + tmpl[tmplCnt].pValue = label; + tmpl[tmplCnt].ulValueLen = (CK_ULONG)labelLen; + tmplCnt++; + } + if (keyClass != NULL) { + tmpl[tmplCnt].type = CKA_CLASS; + tmpl[tmplCnt].pValue = keyClass; + tmpl[tmplCnt].ulValueLen = sizeof(*keyClass); + tmplCnt++; + } + + return Pkcs11FindKeyByTemplate(handle, session, tmpl, tmplCnt, count); +} +#endif + +#if (!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || defined(HAVE_ECC) || \ + defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) || \ + (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ + !defined(NO_HMAC) +/** + * Check a key can be created as a new token object. + * Lookups go by label or by id, so neither may be in use by a token key. + * + * @param [in] session Session object. + * @param [in] keyType Key type. + * @param [in] id Identifier of key. + * @param [in] idLen Length of identifier. + * @param [in] label Label of key. + * @param [in] labelLen Length of label. + * @return BAD_FUNC_ARG when the key has neither id nor label. + * @return BAD_STATE_E when a token key of the type has the id or label. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return 0 on success. + */ +static int Pkcs11CheckNewTokenKey(Pkcs11Session* session, CK_KEY_TYPE keyType, + byte* id, int idLen, char* label, int labelLen) +{ + int ret = 0; + CK_ULONG count = 0; + CK_OBJECT_HANDLE handle; + + if (idLen <= 0 && labelLen <= 0) + ret = BAD_FUNC_ARG; + if (ret == 0 && idLen > 0) { + ret = Pkcs11FindKeyObject(session, NULL, keyType, CK_TRUE, id, idLen, + NULL, 0, &handle, &count); + } + if (ret == 0 && count == 0 && labelLen > 0) { + ret = Pkcs11FindKeyObject(session, NULL, keyType, CK_TRUE, NULL, 0, + label, labelLen, &handle, &count); + } + if (ret == 0 && count != 0) + ret = BAD_STATE_E; + + return ret; +} +#endif + #ifndef NO_RSA /** * Find the PKCS#11 object containing the RSA public or private key data with @@ -3241,27 +3655,43 @@ static int Pkcs11RsaKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) CK_OBJECT_HANDLE pubKey = NULL_PTR, privKey = NULL_PTR; CK_MECHANISM mech; CK_BYTE pubExp[sizeof(long)]; + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE pubKeyTmpl[] = { { CKA_MODULUS_BITS, &bits, sizeof(bits) }, { CKA_ENCRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, - { CKA_PUBLIC_EXPONENT, pubExp, sizeof(pubExp) } + { CKA_PUBLIC_EXPONENT, pubExp, sizeof(pubExp) }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 } }; - CK_ULONG pubTmplCnt = sizeof(pubKeyTmpl)/sizeof(*pubKeyTmpl); - /* Empty entries for optional label/ID. */ + /* 4 mandatory entries + 4 optional. */ + CK_ULONG pubTmplCnt = 4; + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE privKeyTmpl[] = { { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; - /* 2 mandatory entries + 2 optional. */ + /* 2 mandatory entries + 6 optional. */ int privTmplCnt = 2; int i; + if (key->idLen == 0 && key->labelLen == 0) + session->tokenObjects = 0; ret = Pkcs11MechAvail(session, CKM_RSA_PKCS_KEY_PAIR_GEN, NULL); if (ret == 0) ret = Pkcs11KeyGenSessionCheck(session, key->idLen, key->labelLen); + if (ret == 0 && session->tokenObjects) { + ret = Pkcs11CheckNewTokenKey(session, CKK_RSA, key->id, key->idLen, + key->label, key->labelLen); + } if (ret == 0) { WOLFSSL_MSG("PKCS#11: RSA Key Generation Operation"); @@ -3288,6 +3718,26 @@ static int Pkcs11RsaKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) privKeyTmpl[privTmplCnt].ulValueLen = key->idLen; privTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&privKeyTmpl[privTmplCnt], pkcs11TokenKeyAttrs, + sizeof(pkcs11TokenKeyAttrs)); + privTmplCnt += PKCS11_TOKEN_KEY_ATTRS; + if (key->labelLen != 0) { + pubKeyTmpl[pubTmplCnt].type = CKA_LABEL; + pubKeyTmpl[pubTmplCnt].pValue = key->label; + pubKeyTmpl[pubTmplCnt].ulValueLen = key->labelLen; + pubTmplCnt++; + } + if (key->idLen != 0) { + pubKeyTmpl[pubTmplCnt].type = CKA_ID; + pubKeyTmpl[pubTmplCnt].pValue = key->id; + pubKeyTmpl[pubTmplCnt].ulValueLen = key->idLen; + pubTmplCnt++; + } + XMEMCPY(&pubKeyTmpl[pubTmplCnt], pkcs11TokenPubKeyAttrs, + sizeof(pkcs11TokenPubKeyAttrs)); + pubTmplCnt += PKCS11_TOKEN_PUB_KEY_ATTRS; + } mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; mech.ulParameterLen = 0; @@ -3308,9 +3758,9 @@ static int Pkcs11RsaKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) if (ret == 0) ret = Pkcs11GetRsaPublicKey(key, session, pubKey); - if (pubKey != NULL_PTR) + if (pubKey != NULL_PTR && (ret != 0 || !session->tokenObjects)) session->func->C_DestroyObject(session->handle, pubKey); - if (ret == 0 && privKey != NULL_PTR) + if (ret == 0 && privKey != NULL_PTR && !session->closes) key->devCtx = (void*)(wc_ptr_t)privKey; else if (ret != 0 && privKey != NULL_PTR) session->func->C_DestroyObject(session->handle, privKey); @@ -3519,23 +3969,35 @@ static int Pkcs11EcKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) CK_OBJECT_HANDLE pubKey = NULL_PTR, privKey = NULL_PTR; CK_MECHANISM mech; CK_UTF8CHAR params[ECC_MAX_OID_LEN]; + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE pubKeyTmpl[] = { { CKA_EC_PARAMS, params, 0 }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, }; int pubTmplCnt = 1; - /* Empty entries for optional label/ID. */ + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE privKeyAttrs[] = { { CKA_DECRYPT, &ckTrue, sizeof(ckTrue) }, { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, { 0, NULL, 0 }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, }; CK_ATTRIBUTE* privKeyTmpl = privKeyAttrs; int privTmplCnt = 0; int usage = 0; + /* An unnamed key, such as a TLS ephemeral key, stays a session object. */ + if (key->idLen == 0 && key->labelLen == 0) + session->tokenObjects = 0; ret = Pkcs11MechAvail(session, CKM_EC_KEY_PAIR_GEN, NULL); if (ret == 0) ret = Pkcs11KeyGenSessionCheck(session, key->idLen, key->labelLen); @@ -3544,6 +4006,10 @@ static int Pkcs11EcKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) ret = Pkcs11EccSetParams(key, pubKeyTmpl, 0); } + if (ret == 0 && session->tokenObjects) { + ret = Pkcs11CheckNewTokenKey(session, CKK_EC, key->id, key->idLen, + key->label, key->labelLen); + } if (ret == 0) { ret = Pkcs11EccKeyUsage(session, key, &usage); if (ret == WC_NO_ERR_TRACE(NOT_COMPILED_IN) && @@ -3578,6 +4044,26 @@ static int Pkcs11EcKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) privKeyTmpl[privTmplCnt].ulValueLen = key->idLen; privTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&privKeyTmpl[privTmplCnt], pkcs11TokenKeyAttrs, + sizeof(pkcs11TokenKeyAttrs)); + privTmplCnt += PKCS11_TOKEN_KEY_ATTRS; + if (key->labelLen != 0) { + pubKeyTmpl[pubTmplCnt].type = CKA_LABEL; + pubKeyTmpl[pubTmplCnt].pValue = key->label; + pubKeyTmpl[pubTmplCnt].ulValueLen = key->labelLen; + pubTmplCnt++; + } + if (key->idLen != 0) { + pubKeyTmpl[pubTmplCnt].type = CKA_ID; + pubKeyTmpl[pubTmplCnt].pValue = key->id; + pubKeyTmpl[pubTmplCnt].ulValueLen = key->idLen; + pubTmplCnt++; + } + XMEMCPY(&pubKeyTmpl[pubTmplCnt], pkcs11TokenPubKeyAttrs, + sizeof(pkcs11TokenPubKeyAttrs)); + pubTmplCnt += PKCS11_TOKEN_PUB_KEY_ATTRS; + } mech.mechanism = CKM_EC_KEY_PAIR_GEN; mech.ulParameterLen = 0; @@ -3599,9 +4085,9 @@ static int Pkcs11EcKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) if (ret == 0) ret = Pkcs11GetEccPublicKey(key, session, pubKey); - if (pubKey != NULL_PTR) + if (pubKey != NULL_PTR && (ret != 0 || !session->tokenObjects)) session->func->C_DestroyObject(session->handle, pubKey); - if (ret == 0 && privKey != NULL_PTR) { + if (ret == 0 && privKey != NULL_PTR && !session->closes) { key->devCtx = (void*)(wc_ptr_t)privKey; } else if (ret != 0 && privKey != NULL_PTR) { @@ -4589,23 +5075,35 @@ static int Pkcs11MlKemKeyGen(Pkcs11Session* session, MlKemKey* key) { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; CK_ULONG pubTmplCnt = - sizeof(pubKeyTmpl) / sizeof(*pubKeyTmpl) - 2; + sizeof(pubKeyTmpl) / sizeof(*pubKeyTmpl) - 4; CK_ATTRIBUTE privKeyTmpl[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_DECAPSULATE, &ckTrue, sizeof(ckTrue) }, { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; CK_ULONG privTmplCnt = - sizeof(privKeyTmpl) / sizeof(*privKeyTmpl) - 2; + sizeof(privKeyTmpl) / sizeof(*privKeyTmpl) - 6; + if (key->idLen == 0 && key->labelLen == 0) + session->tokenObjects = 0; ret = Pkcs11MechAvail(session, CKM_ML_KEM_KEY_PAIR_GEN, &mechInfo); if (ret == 0) ret = Pkcs11KeyGenSessionCheck(session, key->idLen, key->labelLen); + if (ret == 0 && session->tokenObjects) { + ret = Pkcs11CheckNewTokenKey(session, CKK_ML_KEM, key->id, key->idLen, + key->label, key->labelLen); + } if (ret == 0) { switch (key->type) { #ifndef WOLFSSL_NO_ML_KEM @@ -4661,6 +5159,15 @@ static int Pkcs11MlKemKeyGen(Pkcs11Session* session, MlKemKey* key) pubKeyTmpl[pubTmplCnt].ulValueLen = key->idLen; pubTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&privKeyTmpl[privTmplCnt], pkcs11TokenKeyAttrs, + sizeof(pkcs11TokenKeyAttrs)); + privTmplCnt += PKCS11_TOKEN_KEY_ATTRS; + + XMEMCPY(&pubKeyTmpl[pubTmplCnt], pkcs11TokenPubKeyAttrs, + sizeof(pkcs11TokenPubKeyAttrs)); + pubTmplCnt += PKCS11_TOKEN_PUB_KEY_ATTRS; + } mech.mechanism = CKM_ML_KEM_KEY_PAIR_GEN; mech.ulParameterLen = 0; @@ -4681,14 +5188,13 @@ static int Pkcs11MlKemKeyGen(Pkcs11Session* session, MlKemKey* key) ret = Pkcs11GetMlKemPublicKey(key, session, pubKey); } - /* Destroy the public key object, as encapsulation using the public key will - * probably be performed outside of the PKCS#11 token. If not, user can call - * wc_Pkcs11StoreKey() to import the public key to the token. */ - if (pubKey != NULL_PTR) { + /* Encapsulation usually runs in software, so a session public key goes. */ + if (pubKey != NULL_PTR && (ret != 0 || !session->tokenObjects)) { session->func->C_DestroyObject(session->handle, pubKey); } if (ret == 0 && privKey != NULL_PTR) { - key->devCtx = (void*)(wc_ptr_t)privKey; + if (!session->closes) + key->devCtx = (void*)(wc_ptr_t)privKey; key->flags |= MLKEM_FLAG_PRIV_SET; } else if (ret != 0 && privKey != NULL_PTR) { @@ -5155,29 +5661,37 @@ static int Pkcs11MldsaKeyGen(Pkcs11Session* session, wc_MlDsaKey* key) CK_MECHANISM_INFO mechInfo; CK_ML_DSA_PARAMETER_SET_TYPE param_set = 0; - /* Empty entries for optional label/ID. */ + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE pubKeyTmpl[] = { { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, { CKA_VERIFY, &ckTrue, sizeof(ckTrue) }, { CKA_KEY_TYPE, &mldsaKeyType, sizeof(mldsaKeyType) }, { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; - /* Mandatory entries + 2 optional. */ - CK_ULONG pubTmplCnt = sizeof(pubKeyTmpl)/sizeof(*pubKeyTmpl) - 2; + /* Mandatory entries + 4 optional. */ + CK_ULONG pubTmplCnt = sizeof(pubKeyTmpl)/sizeof(*pubKeyTmpl) - 4; - /* Empty entries for optional label/ID. */ + /* Empty entries for optional label/ID/token. */ CK_ATTRIBUTE privKeyTmpl[] = { { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, { CKA_KEY_TYPE, &mldsaKeyType, sizeof(mldsaKeyType) }, { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, { 0, NULL, 0 } }; - /* Mandatory entries + 2 optional. */ - CK_ULONG privTmplCnt = sizeof(privKeyTmpl)/sizeof(*privKeyTmpl) - 2; + /* Mandatory entries + 6 optional. */ + CK_ULONG privTmplCnt = sizeof(privKeyTmpl)/sizeof(*privKeyTmpl) - 6; + if (key->idLen == 0 && key->labelLen == 0) + session->tokenObjects = 0; ret = Pkcs11MechAvail(session, CKM_ML_DSA_KEY_PAIR_GEN, &mechInfo); if (ret == 0) ret = Pkcs11KeyGenSessionCheck(session, key->idLen, key->labelLen); @@ -5201,6 +5715,10 @@ static int Pkcs11MldsaKeyGen(Pkcs11Session* session, wc_MlDsaKey* key) ret = WC_KEY_SIZE_E; } } + if (ret == 0 && session->tokenObjects) { + ret = Pkcs11CheckNewTokenKey(session, CKK_ML_DSA, key->id, key->idLen, + key->label, key->labelLen); + } if (ret == 0) { WOLFSSL_MSG("PKCS#11: ML-DSA Key Generation Operation"); @@ -5226,6 +5744,14 @@ static int Pkcs11MldsaKeyGen(Pkcs11Session* session, wc_MlDsaKey* key) pubKeyTmpl[pubTmplCnt].ulValueLen = key->idLen; pubTmplCnt++; } + if (session->tokenObjects) { + XMEMCPY(&privKeyTmpl[privTmplCnt], pkcs11TokenKeyAttrs, + sizeof(pkcs11TokenKeyAttrs)); + privTmplCnt += PKCS11_TOKEN_KEY_ATTRS; + XMEMCPY(&pubKeyTmpl[pubTmplCnt], pkcs11TokenPubKeyAttrs, + sizeof(pkcs11TokenPubKeyAttrs)); + pubTmplCnt += PKCS11_TOKEN_PUB_KEY_ATTRS; + } mech.mechanism = CKM_ML_DSA_KEY_PAIR_GEN; mech.ulParameterLen = 0; @@ -5247,9 +5773,9 @@ static int Pkcs11MldsaKeyGen(Pkcs11Session* session, wc_MlDsaKey* key) if (ret == 0) ret = Pkcs11GetMldsaPublicKey(key, session, pubKey); - if (pubKey != NULL_PTR) + if (pubKey != NULL_PTR && (ret != 0 || !session->tokenObjects)) session->func->C_DestroyObject(session->handle, pubKey); - if (ret == 0 && privKey != NULL_PTR) { + if (ret == 0 && privKey != NULL_PTR && !session->closes) { key->devCtx = (void*)(wc_ptr_t)privKey; } else if (ret != 0 && privKey != NULL_PTR) @@ -6521,22 +7047,603 @@ static int Pkcs11GetCert(Pkcs11Session* session, wc_CryptoInfo* info) { #endif /* !NO_CERTS */ +#if (!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)) || defined(HAVE_ECC) || \ + defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_MLKEM) || \ + (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ + !defined(NO_HMAC) /** - * Perform a cryptographic operation using PKCS#11 device. + * Copy a private or secret key's session object to a new token object. * - * @param [in] devId Device identifier. - * @param [in] info Cryptographic operation data. - * @param [in] ctx Context data for device - the token object. - * @return WC_HW_E when a PKCS#11 library call fails. - * @return NOT_COMPILED_IN when an unsupported operation is requested. + * @param [in] session Session object. + * @param [in] keyClass Key class. + * @param [in] keyType Key type. + * @param [in] devCtx Handle of session object from key, may be NULL. + * @param [in] id Identifier of key. + * @param [in] idLen Length of identifier. + * @param [in] label Label of key. + * @param [in] labelLen Length of label. + * @param [out] sessKey Handle of session object. + * @param [out] tokenKey Handle of new token object. + * @return BAD_FUNC_ARG when the key has neither id nor label. + * @return BAD_STATE_E when the token already holds a key with the id or + * label, or devCtx is a token object. + * @return WC_HW_E when no session object is found or a PKCS#11 call fails. * @return 0 on success. */ -int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) +static int Pkcs11PersistPrivKey(Pkcs11Session* session, + CK_OBJECT_CLASS* keyClass, CK_KEY_TYPE keyType, void* devCtx, byte* id, + int idLen, char* label, int labelLen, CK_OBJECT_HANDLE* sessKey, + CK_OBJECT_HANDLE* tokenKey) { - int ret = 0; - Pkcs11Token* token = (Pkcs11Token*)ctx; - Pkcs11Session session; - + int ret; + CK_RV rv; + CK_ULONG count = 0; + CK_BBOOL onToken = CK_FALSE; + CK_ATTRIBUTE tmpl[PKCS11_TOKEN_KEY_ATTRS + 2]; + CK_ULONG tmplCnt = PKCS11_TOKEN_KEY_ATTRS; + + ret = Pkcs11CheckNewTokenKey(session, keyType, id, idLen, label, labelLen); + if (ret == 0 && devCtx != NULL) { + *sessKey = (CK_OBJECT_HANDLE)(wc_ptr_t)devCtx; + ret = Pkcs11KeyOnToken(session, *sessKey, &onToken); + if (ret == 0 && onToken != CK_FALSE) + ret = BAD_STATE_E; + } + else if (ret == 0) { + ret = Pkcs11FindKeyObject(session, keyClass, keyType, CK_FALSE, id, + idLen, label, labelLen, sessKey, &count); + if (ret == 0 && count == 0) + ret = WC_HW_E; + } + if (ret == 0) { + XMEMCPY(tmpl, pkcs11TokenKeyAttrs, sizeof(pkcs11TokenKeyAttrs)); + if (idLen > 0) { + tmpl[tmplCnt].type = CKA_ID; + tmpl[tmplCnt].pValue = id; + tmpl[tmplCnt].ulValueLen = (CK_ULONG)idLen; + tmplCnt++; + } + if (labelLen > 0) { + tmpl[tmplCnt].type = CKA_LABEL; + tmpl[tmplCnt].pValue = label; + tmpl[tmplCnt].ulValueLen = (CK_ULONG)labelLen; + tmplCnt++; + } + rv = session->func->C_CopyObject(session->handle, *sessKey, tmpl, + tmplCnt, tokenKey); + PKCS11_RV("C_CopyObject", rv); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + return ret; +} +#endif + +#if defined(HAVE_ECC) || defined(WOLFSSL_HAVE_MLDSA) || \ + defined(WOLFSSL_HAVE_MLKEM) +/** + * Copy the session public key object with a key's id and label to a new + * token object. Nothing is copied when there is no such session object. + * + * @param [in] session Session object. + * @param [in] keyType Key type. + * @param [in] id Identifier of key. + * @param [in] idLen Length of identifier. + * @param [in] label Label of key. + * @param [in] labelLen Length of label. + * @param [out] tokenKey Handle of new token object. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return 0 on success. + */ +static int Pkcs11PersistPubKey(Pkcs11Session* session, CK_KEY_TYPE keyType, + byte* id, int idLen, char* label, int labelLen, + CK_OBJECT_HANDLE* tokenKey) +{ + int ret; + CK_RV rv; + CK_ULONG count = 0; + CK_OBJECT_HANDLE sessKey = NULL_PTR; + + ret = Pkcs11FindKeyObject(session, &pubKeyClass, keyType, CK_FALSE, id, + idLen, label, labelLen, &sessKey, &count); + if (ret == 0 && count != 0) { + rv = session->func->C_CopyObject(session->handle, sessKey, + pkcs11TokenPubKeyAttrs, + PKCS11_TOKEN_PUB_KEY_ATTRS, tokenKey); + PKCS11_RV("C_CopyObject", rv); + if (rv != CKR_OK) + ret = WC_HW_E; + } + + return ret; +} +#endif + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(WOLFSSL_HAVE_MLDSA) || \ + defined(WOLFSSL_HAVE_MLKEM) || (!defined(NO_AES) && \ + (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || !defined(NO_HMAC) +/** + * Destroy all key objects of a key type with a key's id and label. + * + * @param [in] session Session object. + * @param [in] keyClass Key class to match. NULL matches any class. + * @param [in] keyType Key type. + * @param [in] onToken Destroy token objects or session objects. + * @param [in] id Identifier of key. + * @param [in] idLen Length of identifier. + * @param [in] label Label of key. + * @param [in] labelLen Length of label. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return 0 on success. + */ +static int Pkcs11DestroyKeyObjects(Pkcs11Session* session, + CK_OBJECT_CLASS* keyClass, CK_KEY_TYPE keyType, CK_BBOOL onToken, + byte* id, int idLen, char* label, int labelLen) +{ + int ret = 0; + CK_RV rv; + CK_ULONG count = 1; + CK_OBJECT_HANDLE handle; + + while (ret == 0 && count != 0) { + ret = Pkcs11FindKeyObject(session, keyClass, keyType, onToken, id, + idLen, label, labelLen, &handle, &count); + if (ret == 0 && count != 0) { + rv = session->func->C_DestroyObject(session->handle, handle); + PKCS11_RV("C_DestroyObject", rv); + if (rv != CKR_OK) + ret = WC_HW_E; + } + } + + return ret; +} +#endif + +/** + * Make a private or secret key held in a session object persistent on the + * token. + * + * @param [in] token Token holding the key. + * @param [in] type PKCS11_KEY_TYPE_RSA, _EC, _MLDSA, _MLKEM, _AES_GCM, + * _AES_CBC or _HMAC. + * @param [in] key Key with an id or label. + * @return BAD_FUNC_ARG when token or key is NULL, the key has neither id + * nor label, or an HMAC key has no hash type. + * @return BAD_STATE_E when the token already holds a key with the id or + * label, or the key already refers to a token object. + * @return NOT_COMPILED_IN when the key type is not supported. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return 0 on success. + */ +int wc_Pkcs11PersistKey(Pkcs11Token* token, int type, void* key) +{ + int ret = 0; + Pkcs11Session session; + CK_OBJECT_HANDLE sessKey = NULL_PTR; + CK_OBJECT_HANDLE privKey = NULL_PTR; + CK_OBJECT_HANDLE pubKey = NULL_PTR; + CK_RV rv = CKR_OK; + + if (token == NULL || key == NULL) + ret = BAD_FUNC_ARG; + if (ret == 0) + ret = Pkcs11OpenSession(token, &session, 1); + if (ret == 0) { + session.tokenObjects = 1; + switch (type) { + #if !defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC)) + case PKCS11_KEY_TYPE_AES_GCM: + case PKCS11_KEY_TYPE_AES_CBC: { + Aes* aes = (Aes*)key; + + ret = Pkcs11PersistPrivKey(&session, &secretKeyClass, CKK_AES, + NULL, (byte*)aes->id, aes->idLen, + aes->label, aes->labelLen, + &sessKey, &privKey); + break; + } + #endif + #ifndef NO_HMAC + case PKCS11_KEY_TYPE_HMAC: { + Hmac* hmac = (Hmac*)key; + int mechType; + int keyType; + CK_KEY_TYPE otherType = CKK_GENERIC_SECRET; + CK_ULONG count = 0; + + if (hmac->macType == WC_HASH_TYPE_NONE) + ret = BAD_FUNC_ARG; + else + ret = Pkcs11HmacTypes(hmac->macType, &mechType, &keyType); + if (ret == 0) { + ret = Pkcs11FindKeyObject(&session, &secretKeyClass, + (CK_KEY_TYPE)keyType, CK_FALSE, (byte*)hmac->id, + hmac->idLen, hmac->label, hmac->labelLen, &sessKey, + &count); + } + /* wc_Pkcs11StoreKey falls back to a generic secret. */ + if (ret == 0 && count == 0) { + otherType = (CK_KEY_TYPE)keyType; + keyType = (int)CKK_GENERIC_SECRET; + } + if (ret == 0) { + ret = Pkcs11CheckNewTokenKey(&session, otherType, + (byte*)hmac->id, hmac->idLen, hmac->label, + hmac->labelLen); + } + if (ret == 0) { + ret = Pkcs11PersistPrivKey(&session, &secretKeyClass, + (CK_KEY_TYPE)keyType, NULL, (byte*)hmac->id, + hmac->idLen, hmac->label, hmac->labelLen, &sessKey, + &privKey); + } + break; + } + #endif + #if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) + case PKCS11_KEY_TYPE_RSA: { + RsaKey* rsaKey = (RsaKey*)key; + + ret = Pkcs11PersistPrivKey(&session, &privKeyClass, CKK_RSA, + rsaKey->devCtx, + rsaKey->id, rsaKey->idLen, + rsaKey->label, rsaKey->labelLen, + &sessKey, &privKey); + if (ret == 0 && !mp_iszero(&rsaKey->e)) { + ret = Pkcs11CreateRsaPublicKey(&pubKey, &session, + rsaKey); + } + if (ret == 0) + rsaKey->devCtx = (void*)(wc_ptr_t)privKey; + break; + } + #endif + #ifdef HAVE_ECC + case PKCS11_KEY_TYPE_EC: { + ecc_key* eccKey = (ecc_key*)key; + CK_BBOOL canSign = CK_TRUE; + CK_ATTRIBUTE signAttr; + + ret = Pkcs11PersistPrivKey(&session, &privKeyClass, CKK_EC, + eccKey->devCtx, + eccKey->id, eccKey->idLen, + eccKey->label, eccKey->labelLen, + &sessKey, &privKey); + if (ret == 0 && !mp_iszero(eccKey->pubkey.x) && + Pkcs11MechAvail(&session, CKM_ECDSA, NULL) == 0) { + ret = Pkcs11CreateEccPublicKey(&pubKey, &session, eccKey, + CKA_VERIFY); + if (ret != 0) { + signAttr.type = CKA_SIGN; + signAttr.pValue = &canSign; + signAttr.ulValueLen = sizeof(canSign); + rv = session.func->C_GetAttributeValue(session.handle, + privKey, &signAttr, 1); + PKCS11_RV("C_GetAttributeValue", rv); + if (rv == CKR_OK && canSign == CK_FALSE) + ret = 0; + } + } + else if (ret == 0 && mp_iszero(eccKey->pubkey.x)) { + ret = Pkcs11PersistPubKey(&session, CKK_EC, eccKey->id, + eccKey->idLen, eccKey->label, eccKey->labelLen, + &pubKey); + } + if (ret == 0) { + eccKey->devCtx = (void*)(wc_ptr_t)privKey; + (void)Pkcs11DestroyKeyObjects(&session, &pubKeyClass, + CKK_EC, CK_FALSE, eccKey->id, eccKey->idLen, + eccKey->label, eccKey->labelLen); + } + break; + } + #endif + #ifdef WOLFSSL_HAVE_MLDSA + case PKCS11_KEY_TYPE_MLDSA: { + wc_MlDsaKey* mldsaKey = (wc_MlDsaKey*)key; + CK_MECHANISM_INFO mechInfo; + + ret = Pkcs11PersistPrivKey(&session, &privKeyClass, + CKK_ML_DSA, mldsaKey->devCtx, + mldsaKey->id, mldsaKey->idLen, + mldsaKey->label, mldsaKey->labelLen, + &sessKey, &privKey); + if (ret == 0 && mldsaKey->pubKeySet) { + ret = Pkcs11MechAvail(&session, CKM_ML_DSA, &mechInfo); + if (ret == 0) { + ret = Pkcs11CreateMldsaPublicKey(&pubKey, &session, + mldsaKey, &mechInfo); + } + } + else if (ret == 0) { + ret = Pkcs11PersistPubKey(&session, CKK_ML_DSA, + mldsaKey->id, mldsaKey->idLen, mldsaKey->label, + mldsaKey->labelLen, &pubKey); + } + if (ret == 0) { + mldsaKey->devCtx = (void*)(wc_ptr_t)privKey; + (void)Pkcs11DestroyKeyObjects(&session, &pubKeyClass, + CKK_ML_DSA, CK_FALSE, mldsaKey->id, mldsaKey->idLen, + mldsaKey->label, mldsaKey->labelLen); + } + break; + } + #endif + #ifdef WOLFSSL_HAVE_MLKEM + case PKCS11_KEY_TYPE_MLKEM: { + MlKemKey* mlkemKey = (MlKemKey*)key; + CK_MECHANISM_INFO mechInfo; + + ret = Pkcs11PersistPrivKey(&session, &privKeyClass, + CKK_ML_KEM, mlkemKey->devCtx, + mlkemKey->id, mlkemKey->idLen, + mlkemKey->label, mlkemKey->labelLen, + &sessKey, &privKey); + if (ret == 0 && (mlkemKey->flags & MLKEM_FLAG_PUB_SET) != 0) { + ret = Pkcs11MechAvail(&session, CKM_ML_KEM, &mechInfo); + if (ret == 0) { + ret = Pkcs11CreateMlKemPublicKey(&pubKey, &session, + mlkemKey, &mechInfo); + } + } + else if (ret == 0) { + ret = Pkcs11PersistPubKey(&session, CKK_ML_KEM, + mlkemKey->id, mlkemKey->idLen, mlkemKey->label, + mlkemKey->labelLen, &pubKey); + } + if (ret == 0) { + mlkemKey->devCtx = (void*)(wc_ptr_t)privKey; + (void)Pkcs11DestroyKeyObjects(&session, &pubKeyClass, + CKK_ML_KEM, CK_FALSE, mlkemKey->id, mlkemKey->idLen, + mlkemKey->label, mlkemKey->labelLen); + } + break; + } + #endif + default: + ret = NOT_COMPILED_IN; + break; + } + + if (ret == 0) { + rv = session.func->C_DestroyObject(session.handle, sessKey); + PKCS11_RV("C_DestroyObject", rv); + } + else if (privKey != NULL_PTR) { + rv = session.func->C_DestroyObject(session.handle, privKey); + PKCS11_RV("C_DestroyObject", rv); + } + Pkcs11CloseSession(token, &session); + } + + (void)pubKey; + (void)rv; + + return ret; +} + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(WOLFSSL_HAVE_MLDSA) || \ + defined(WOLFSSL_HAVE_MLKEM) || (!defined(NO_AES) && \ + (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || !defined(NO_HMAC) +/** + * Check that the user is logged in, so the session sees private objects. + * + * @param [in] session Session object. + * @return BAD_STATE_E when the user is not logged in. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return 0 on success. + */ +static int Pkcs11CheckUserSession(Pkcs11Session* session) +{ + int ret = 0; + CK_RV rv; + CK_SESSION_INFO info; + + rv = session->func->C_GetSessionInfo(session->handle, &info); + PKCS11_RV("C_GetSessionInfo", rv); + if (rv != CKR_OK) + ret = WC_HW_E; + else if (info.state != CKS_RO_USER_FUNCTIONS && + info.state != CKS_RW_USER_FUNCTIONS) + ret = BAD_STATE_E; + + return ret; +} + +/** + * Destroy all token objects of a key type with the key's id and label. + * + * @param [in] session Session object. + * @param [in] keyType Key type. + * @param [in] id Identifier of key. + * @param [in] idLen Length of identifier. + * @param [in] label Label of key. + * @param [in] labelLen Length of label. + * @return BAD_FUNC_ARG when the key has neither id nor label. + * @return BAD_STATE_E when the user is not logged in. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return 0 on success. + */ +static int Pkcs11DeleteTokenKey(Pkcs11Session* session, CK_KEY_TYPE keyType, + byte* id, int idLen, char* label, int labelLen) +{ + int ret = 0; + + if (idLen <= 0 && labelLen <= 0) + ret = BAD_FUNC_ARG; + if (ret == 0) + ret = Pkcs11CheckUserSession(session); + if (ret == 0) { + ret = Pkcs11DestroyKeyObjects(session, NULL, keyType, CK_TRUE, id, + idLen, label, labelLen); + } + + return ret; +} +#endif + +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(WOLFSSL_HAVE_MLDSA) || \ + defined(WOLFSSL_HAVE_MLKEM) +/** + * Release the key object a key refers to after deleting its token objects. + * + * @param [in] session Session object. + * @param [in, out] devCtx Device context of the key. + * @param [in] result Result of deleting the token objects. + */ +static void Pkcs11DeleteDevCtx(Pkcs11Session* session, void** devCtx, + int result) +{ + CK_OBJECT_HANDLE handle; + CK_BBOOL onToken; + + if (*devCtx != NULL) { + handle = (CK_OBJECT_HANDLE)(wc_ptr_t)*devCtx; + if (result == 0) { + Pkcs11DestroySessionKey(session, handle); + *devCtx = NULL; + } + else if (result == WC_NO_ERR_TRACE(WC_HW_E) && + Pkcs11KeyOnToken(session, handle, &onToken) != 0) { + *devCtx = NULL; + } + } +} +#endif + +/** + * Remove a key's token objects from the token. + * + * @param [in] token Token holding the key. + * @param [in] type PKCS11_KEY_TYPE_RSA, _EC, _MLDSA, _MLKEM, _AES_GCM, + * _AES_CBC or _HMAC. + * @param [in] key Key with an id or label. + * @return BAD_FUNC_ARG when token or key is NULL, the key has neither id + * nor label, or an HMAC key has no hash type. + * @return BAD_STATE_E when the user is not logged in. + * @return NOT_COMPILED_IN when the key type is not supported. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return 0 on success. + */ +int wc_Pkcs11DeleteKey(Pkcs11Token* token, int type, void* key) +{ + int ret = 0; + Pkcs11Session session; + + if (token == NULL || key == NULL) + ret = BAD_FUNC_ARG; + if (ret == 0) + ret = Pkcs11OpenSession(token, &session, 1); + if (ret == 0) { + switch (type) { + #if !defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC)) + case PKCS11_KEY_TYPE_AES_GCM: + case PKCS11_KEY_TYPE_AES_CBC: { + Aes* aes = (Aes*)key; + + ret = Pkcs11DeleteTokenKey(&session, CKK_AES, (byte*)aes->id, + aes->idLen, aes->label, + aes->labelLen); + break; + } + #endif + #ifndef NO_HMAC + case PKCS11_KEY_TYPE_HMAC: { + Hmac* hmac = (Hmac*)key; + int mechType; + int keyType; + + if (hmac->macType == WC_HASH_TYPE_NONE) + ret = BAD_FUNC_ARG; + else + ret = Pkcs11HmacTypes(hmac->macType, &mechType, &keyType); + if (ret == 0) { + ret = Pkcs11DeleteTokenKey(&session, (CK_KEY_TYPE)keyType, + (byte*)hmac->id, hmac->idLen, + hmac->label, hmac->labelLen); + } + if (ret == 0) { + ret = Pkcs11DeleteTokenKey(&session, CKK_GENERIC_SECRET, + (byte*)hmac->id, hmac->idLen, + hmac->label, hmac->labelLen); + } + break; + } + #endif + #ifndef NO_RSA + case PKCS11_KEY_TYPE_RSA: { + RsaKey* rsaKey = (RsaKey*)key; + + ret = Pkcs11DeleteTokenKey(&session, CKK_RSA, rsaKey->id, + rsaKey->idLen, rsaKey->label, + rsaKey->labelLen); + Pkcs11DeleteDevCtx(&session, &rsaKey->devCtx, ret); + break; + } + #endif + #ifdef HAVE_ECC + case PKCS11_KEY_TYPE_EC: { + ecc_key* eccKey = (ecc_key*)key; + + ret = Pkcs11DeleteTokenKey(&session, CKK_EC, eccKey->id, + eccKey->idLen, eccKey->label, + eccKey->labelLen); + Pkcs11DeleteDevCtx(&session, &eccKey->devCtx, ret); + break; + } + #endif + #ifdef WOLFSSL_HAVE_MLDSA + case PKCS11_KEY_TYPE_MLDSA: { + wc_MlDsaKey* mldsaKey = (wc_MlDsaKey*)key; + + ret = Pkcs11DeleteTokenKey(&session, CKK_ML_DSA, + mldsaKey->id, mldsaKey->idLen, + mldsaKey->label, + mldsaKey->labelLen); + Pkcs11DeleteDevCtx(&session, &mldsaKey->devCtx, ret); + break; + } + #endif + #ifdef WOLFSSL_HAVE_MLKEM + case PKCS11_KEY_TYPE_MLKEM: { + MlKemKey* mlkemKey = (MlKemKey*)key; + + ret = Pkcs11DeleteTokenKey(&session, CKK_ML_KEM, + mlkemKey->id, mlkemKey->idLen, + mlkemKey->label, + mlkemKey->labelLen); + Pkcs11DeleteDevCtx(&session, &mlkemKey->devCtx, ret); + break; + } + #endif + default: + ret = NOT_COMPILED_IN; + break; + } + Pkcs11CloseSession(token, &session); + } + + return ret; +} + +/** + * Perform a cryptographic operation using PKCS#11 device. + * + * @param [in] devId Device identifier. + * @param [in] info Cryptographic operation data. + * @param [in] ctx Context data for device - the token object. + * @return WC_HW_E when a PKCS#11 library call fails. + * @return NOT_COMPILED_IN when an unsupported operation is requested. + * @return 0 on success. + */ +int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) +{ + int ret = 0; + Pkcs11Token* token = (Pkcs11Token*)ctx; + Pkcs11Session session; + #ifdef WOLFSSL_PKCS11_RW_TOKENS int readWrite = 1; #else @@ -6569,8 +7676,10 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) break; #ifdef WOLFSSL_KEY_GEN case WC_PK_TYPE_RSA_KEYGEN: - ret = Pkcs11OpenSession(token, &session, readWrite); + ret = Pkcs11OpenSession(token, &session, + readWrite || token->keyGenOnToken); if (ret == 0) { + session.tokenObjects = token->keyGenOnToken; ret = Pkcs11RsaKeyGen(&session, info); Pkcs11CloseSession(token, &session); } @@ -6594,8 +7703,10 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) #ifdef HAVE_ECC #ifndef NO_PKCS11_EC_KEYGEN case WC_PK_TYPE_EC_KEYGEN: - ret = Pkcs11OpenSession(token, &session, readWrite); + ret = Pkcs11OpenSession(token, &session, + readWrite || token->keyGenOnToken); if (ret == 0) { + session.tokenObjects = token->keyGenOnToken; ret = Pkcs11EcKeyGen(&session, info); Pkcs11CloseSession(token, &session); } @@ -6634,8 +7745,10 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) #endif #ifdef WOLFSSL_HAVE_MLKEM case WC_PK_TYPE_PQC_KEM_KEYGEN: - ret = Pkcs11OpenSession(token, &session, readWrite); + ret = Pkcs11OpenSession(token, &session, + readWrite || token->keyGenOnToken); if (ret == 0) { + session.tokenObjects = token->keyGenOnToken; ret = Pkcs11PqcKemKeyGen(&session, info); Pkcs11CloseSession(token, &session); } @@ -6657,8 +7770,10 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) #endif #if defined(WOLFSSL_HAVE_MLDSA) case WC_PK_TYPE_PQC_SIG_KEYGEN: - ret = Pkcs11OpenSession(token, &session, readWrite); + ret = Pkcs11OpenSession(token, &session, + readWrite || token->keyGenOnToken); if (ret == 0) { + session.tokenObjects = token->keyGenOnToken; ret = Pkcs11PqcSigKeyGen(&session, info); Pkcs11CloseSession(token, &session); } @@ -6770,6 +7885,7 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) session.version = token->version; session.handle = (CK_SESSION_HANDLE)(wc_ptr_t)hmac->devCtx; + session.tokenObjects = 0; session.closes = 0; ret = Pkcs11Hmac(&session, info); if (ret != 0 || diff --git a/wolfssl/wolfcrypt/pkcs11.h b/wolfssl/wolfcrypt/pkcs11.h index d77a5ccfc76..0fdde36b1b0 100644 --- a/wolfssl/wolfcrypt/pkcs11.h +++ b/wolfssl/wolfcrypt/pkcs11.h @@ -74,6 +74,12 @@ extern "C" { #define CKF_RW_SESSION 0x00000002UL #define CKF_SERIAL_SESSION 0x00000004UL +#define CKS_RO_PUBLIC_SESSION 0UL +#define CKS_RO_USER_FUNCTIONS 1UL +#define CKS_RW_PUBLIC_SESSION 2UL +#define CKS_RW_USER_FUNCTIONS 3UL +#define CKS_RW_SO_FUNCTIONS 4UL + #define CKO_CERTIFICATE 0x00000001UL #define CKO_PUBLIC_KEY 0x00000002UL #define CKO_PRIVATE_KEY 0x00000003UL diff --git a/wolfssl/wolfcrypt/wc_pkcs11.h b/wolfssl/wolfcrypt/wc_pkcs11.h index 0477666edbd..0e1ba687f61 100644 --- a/wolfssl/wolfcrypt/wc_pkcs11.h +++ b/wolfssl/wolfcrypt/wc_pkcs11.h @@ -60,7 +60,8 @@ typedef struct Pkcs11Token { CK_SESSION_HANDLE handle; /* Handle to active session */ CK_UTF8CHAR_PTR userPin; /* User's PIN to login with */ CK_ULONG userPinSz; /* Size of user's PIN in bytes */ - byte userPinLogin:1; /* Login with User's PIN */ + WC_BITFIELD userPinLogin:1; /* Login with User's PIN */ + WC_BITFIELD keyGenOnToken:1; /* Generate keys as token objects */ int version; /* Pkcs11InterfaceVersionType */ } Pkcs11Token; @@ -70,6 +71,7 @@ typedef struct Pkcs11Session { CK_SESSION_HANDLE handle; /* Handle to active session */ int version; /* Pkcs11InterfaceVersionType */ WC_BITFIELD closes:1; /* Closed after this operation */ + WC_BITFIELD tokenObjects:1; /* Create keys with CKA_TOKEN set */ } Pkcs11Session; /* Types of keys that can be stored. */ @@ -105,9 +107,15 @@ WOLFSSL_API int wc_Pkcs11Token_InitName_NoLogin(Pkcs11Token* token, WOLFSSL_API void wc_Pkcs11Token_Final(Pkcs11Token* token); WOLFSSL_API int wc_Pkcs11Token_Open(Pkcs11Token* token, int readWrite); WOLFSSL_API void wc_Pkcs11Token_Close(Pkcs11Token* token); +WOLFSSL_API int wc_Pkcs11Token_SetKeyGenPersistent(Pkcs11Token* token, + int persistent); WOLFSSL_API int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key); +WOLFSSL_API int wc_Pkcs11StoreKey_ex(Pkcs11Token* token, int type, int clear, + void* key, int persistent); +WOLFSSL_API int wc_Pkcs11PersistKey(Pkcs11Token* token, int type, void* key); +WOLFSSL_API int wc_Pkcs11DeleteKey(Pkcs11Token* token, int type, void* key); WOLFSSL_API int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx);