diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 3bcb317b8d..f6a6f54400 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -421,6 +421,7 @@ NO_PKCS11_ECDH NO_PKCS11_EC_KEYGEN NO_PKCS11_HMAC NO_PKCS11_MLDSA +NO_PKCS11_MLKEM NO_PKCS11_RNG NO_PKCS11_RSA NO_PKCS11_RSA_PKCS diff --git a/src/tls.c b/src/tls.c index 535b43826b..823d974dad 100644 --- a/src/tls.c +++ b/src/tls.c @@ -8596,7 +8596,9 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) } #ifdef WOLFSSL_HAVE_MLKEM -#if defined(WOLFSSL_MLKEM_CACHE_A) && \ +#if (defined(WOLFSSL_MLKEM_CACHE_A) || \ + (defined(HAVE_PKCS11) && defined(WOLFSSL_WC_MLKEM) && \ + !defined(NO_PKCS11_MLKEM))) && \ !defined(WOLFSSL_TLSX_PQC_MLKEM_STORE_PRIV_KEY) /* Store KyberKey object rather than private key bytes in key share entry. * Improves performance at cost of more dynamic memory being used. */ diff --git a/wolfcrypt/src/dilithium.c b/wolfcrypt/src/dilithium.c index 2a0334e278..a70b4ab6f7 100644 --- a/wolfcrypt/src/dilithium.c +++ b/wolfcrypt/src/dilithium.c @@ -10905,22 +10905,15 @@ int wc_dilithium_get_level(dilithium_key* key, byte* level) */ void wc_dilithium_free(dilithium_key* key) { -#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) - int ret = 0; -#endif - if (key != NULL) { #if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) if (key->devId != INVALID_DEVID) { - ret = wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK, + (void)wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK, WC_PK_TYPE_PQC_SIG_KEYGEN, WC_PQC_SIG_TYPE_DILITHIUM, (void*)key); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) - return; - /* fall-through to software cleanup */ + /* always continue to software cleanup */ } - (void)ret; #endif #ifdef WOLFSSL_WC_DILITHIUM #ifndef WC_DILITHIUM_FIXED_ARRAY diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 7940679aeb..83b06c00f6 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -7945,23 +7945,19 @@ void wc_ecc_free_curve(const ecc_set_type* curve, void* heap) WOLFSSL_ABI int wc_ecc_free(ecc_key* key) { -#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) - int ret = 0; -#endif - if (key == NULL) { return 0; } #if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) if (key->devId != INVALID_DEVID) { - ret = wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK, + /* Best-effort HSM resource release; errors are intentionally discarded + * so that software cleanup always runs and wc_ecc_free() retains its + * ABI guarantee of returning 0 on success. */ + (void)wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK, WC_PK_TYPE_EC_KEYGEN, 0, key); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) - return ret; - /* fall-through to software cleanup */ + /* always continue to software cleanup */ } - (void)ret; #endif #if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP) || \ @@ -7975,6 +7971,7 @@ int wc_ecc_free(ecc_key* key) mp_free(key->sign_k); #ifndef WOLFSSL_NO_MALLOC XFREE(key->sign_k, key->heap, DYNAMIC_TYPE_ECC); + key->sign_k = NULL; #endif } #endif @@ -8040,8 +8037,10 @@ int wc_ecc_free(ecc_key* key) #endif #ifdef WOLFSSL_CUSTOM_CURVES - if (key->deallocSet && key->dp != NULL) + if (key->deallocSet && key->dp != NULL) { wc_ecc_free_curve(key->dp, key->heap); + key->dp = NULL; + } #endif #ifdef WOLFSSL_CHECK_MEM_ZERO diff --git a/wolfcrypt/src/wc_mlkem.c b/wolfcrypt/src/wc_mlkem.c index 66c86e9f7b..98f21536a6 100644 --- a/wolfcrypt/src/wc_mlkem.c +++ b/wolfcrypt/src/wc_mlkem.c @@ -75,6 +75,9 @@ #include #include #include +#ifdef WOLF_CRYPTO_CB + #include +#endif #ifdef NO_INLINE #include @@ -298,9 +301,13 @@ int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, int devId) /* Cache heap pointer. */ key->heap = heap; #ifdef WOLF_CRYPTO_CB - /* Cache device id - not used in this algorithm yet. */ + key->devCtx = NULL; key->devId = devId; #endif +#ifdef WOLF_PRIVATE_KEY_ID + key->idLen = 0; + key->labelLen = 0; +#endif key->flags = 0; /* Zero out all data. */ @@ -322,6 +329,58 @@ int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, int devId) return ret; } +#ifdef WOLF_PRIVATE_KEY_ID +int wc_MlKemKey_Init_Id(MlKemKey* key, int type, const unsigned char* id, + int len, void* heap, int devId) +{ + int ret = 0; + + if (key == NULL || (id == NULL && len != 0)) { + ret = BAD_FUNC_ARG; + } + if (ret == 0 && (len < 0 || len > MLKEM_MAX_ID_LEN)) { + ret = BUFFER_E; + } + + if (ret == 0) { + ret = wc_MlKemKey_Init(key, type, heap, devId); + } + if (ret == 0 && id != NULL && len != 0) { + XMEMCPY(key->id, id, (size_t)len); + key->idLen = len; + } + + return ret; +} + +int wc_MlKemKey_Init_Label(MlKemKey* key, int type, const char* label, + void* heap, int devId) +{ + int ret = 0; + int labelLen = 0; + + if (key == NULL || label == NULL) { + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + labelLen = (int)XSTRLEN(label); + if ((labelLen == 0) || (labelLen > MLKEM_MAX_LABEL_LEN)) { + ret = BUFFER_E; + } + } + + if (ret == 0) { + ret = wc_MlKemKey_Init(key, type, heap, devId); + } + if (ret == 0) { + XMEMCPY(key->label, label, (size_t)labelLen); + key->labelLen = labelLen; + } + + return ret; +} +#endif + /** * Free the Kyber key object. * @@ -330,7 +389,19 @@ int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, int devId) */ int wc_MlKemKey_Free(MlKemKey* key) { + int ret = 0; + if (key != NULL) { +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) + if (key->devId != INVALID_DEVID) { + ret = wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK, + WC_PK_TYPE_PQC_KEM_KEYGEN, WC_PQC_KEM_TYPE_KYBER, (void*)key); + if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + ret = 0; + } + /* always continue to software cleanup */ + } +#endif /* Dispose of PRF object. */ mlkem_prf_free(&key->prf); /* Dispose of hash object. */ @@ -342,7 +413,7 @@ int wc_MlKemKey_Free(MlKemKey* key) ForceZero(key->z, sizeof(key->z)); } - return 0; + return ret; } /******************************************************************************/ @@ -382,6 +453,21 @@ int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng) ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + if ((ret == 0) + #ifndef WOLF_CRYPTO_CB_FIND + && (key->devId != INVALID_DEVID) + #endif + ) { + ret = wc_CryptoCb_MakePqcKemKey(rng, WC_PQC_KEM_TYPE_KYBER, + key->type, key); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when unavailable */ + ret = 0; + } +#endif + if (ret == 0) { /* Generate random to use with PRFs. * Step 1: d is 32 random bytes @@ -1063,12 +1149,33 @@ int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* c, unsigned char* k, #ifndef WC_NO_RNG int ret = 0; unsigned char m[WC_ML_KEM_ENC_RAND_SZ]; +#ifdef WOLF_CRYPTO_CB + word32 ctlen = 0; +#endif /* Validate parameters. */ if ((key == NULL) || (c == NULL) || (k == NULL) || (rng == NULL)) { ret = BAD_FUNC_ARG; } +#ifdef WOLF_CRYPTO_CB + if (ret == 0) { + ret = wc_MlKemKey_CipherTextSize(key, &ctlen); + } + if ((ret == 0) + #ifndef WOLF_CRYPTO_CB_FIND + && (key->devId != INVALID_DEVID) + #endif + ) { + ret = wc_CryptoCb_PqcEncapsulate(c, ctlen, k, KYBER_SS_SZ, rng, + WC_PQC_KEM_TYPE_KYBER, key); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when unavailable */ + ret = 0; + } +#endif + if (ret == 0) { /* Generate seed for use with PRFs. * Step 1: m is 32 random bytes @@ -1531,6 +1638,21 @@ int wc_MlKemKey_Decapsulate(MlKemKey* key, unsigned char* ss, ret = BUFFER_E; } +#ifdef WOLF_CRYPTO_CB + if ((ret == 0) + #ifndef WOLF_CRYPTO_CB_FIND + && (key->devId != INVALID_DEVID) + #endif + ) { + ret = wc_CryptoCb_PqcDecapsulate(ct, ctSz, ss, KYBER_SS_SZ, + WC_PQC_KEM_TYPE_KYBER, key); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when unavailable */ + ret = 0; + } +#endif + #if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC) if (ret == 0) { /* Allocate memory for cipher text that is generated. */ diff --git a/wolfcrypt/src/wc_pkcs11.c b/wolfcrypt/src/wc_pkcs11.c index e44e2a500d..67cd5fa365 100644 --- a/wolfcrypt/src/wc_pkcs11.c +++ b/wolfcrypt/src/wc_pkcs11.c @@ -29,6 +29,7 @@ #include #include +#include #ifndef NO_RSA #include #endif @@ -69,14 +70,23 @@ #if defined(NO_PKCS11_MLDSA) && defined(HAVE_DILITHIUM) #undef HAVE_DILITHIUM #endif +#if defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_WC_MLKEM) + #define HAVE_PKCS11_MLKEM +#endif +#if defined(NO_PKCS11_MLKEM) && defined(HAVE_PKCS11_MLKEM) + #undef HAVE_PKCS11_MLKEM +#endif -#if defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH) +#if (defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH)) || \ + defined(HAVE_PKCS11_MLKEM) /* Pointer to false required for templates. */ static CK_BBOOL ckFalse = CK_FALSE; #endif #if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ - (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || !defined(NO_HMAC) + (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ + !defined(NO_HMAC) || defined(HAVE_DILITHIUM) || \ + defined(HAVE_PKCS11_MLKEM) /* Pointer to true required for templates. */ static CK_BBOOL ckTrue = CK_TRUE; #endif @@ -89,18 +99,24 @@ static CK_KEY_TYPE rsaKeyType = CKK_RSA; /* Pointer to EC key type required for templates. */ static CK_KEY_TYPE ecKeyType = CKK_EC; #endif +#if defined(HAVE_PKCS11_MLKEM) +/* Pointer to ML-KEM key type required for templates. */ +static CK_KEY_TYPE mlkemKeyType = CKK_ML_KEM; +#endif #if defined(HAVE_DILITHIUM) /* Pointer to ML-DSA key type required for templates. */ static CK_KEY_TYPE mldsaKeyType = CKK_ML_DSA; #endif -#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_DILITHIUM) +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_DILITHIUM) || \ + defined(HAVE_PKCS11_MLKEM) /* Pointer to public key class required for templates. */ static CK_OBJECT_CLASS pubKeyClass = CKO_PUBLIC_KEY; /* Pointer to private key class required for templates. */ static CK_OBJECT_CLASS privKeyClass = CKO_PRIVATE_KEY; #endif #if (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ - !defined(NO_HMAC) || (defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH)) + !defined(NO_HMAC) || (defined(HAVE_ECC) && !defined(NO_PKCS11_ECDH)) || \ + defined(HAVE_PKCS11_MLKEM) /* Pointer to secret key class required for templates. */ static CK_OBJECT_CLASS secretKeyClass = CKO_SECRET_KEY; #endif @@ -175,6 +191,9 @@ static struct PKCS11_TYPE_STR { { CKA_EXTRACTABLE, "CKA_EXTRACTABLE", PKCS11_FMT_BOOLEAN }, { CKA_EC_PARAMS, "CKA_EC_PARAMS", PKCS11_FMT_DATA }, { CKA_EC_POINT, "CKA_EC_POINT", PKCS11_FMT_DATA }, + { CKA_ENCAPSULATE, "CKA_ENCAPSULATE", PKCS11_FMT_BOOLEAN }, + { CKA_DECAPSULATE, "CKA_DECAPSULATE", PKCS11_FMT_BOOLEAN }, + { CKA_PARAMETER_SET, "CKA_PARAMETER_SET", PKCS11_FMT_NUMBER }, }; /* Count of known attribute types for logging. */ #define PKCS11_TYPE_STR_CNT ((int)(sizeof(typeStr) / sizeof(*typeStr))) @@ -302,6 +321,9 @@ static void pkcs11_dump_template(const char* name, CK_ATTRIBUTE* templ, case CKK_ML_DSA: XSNPRINTF(line, sizeof(line), "%25s: ML_DSA", type); break; + case CKK_ML_KEM: + XSNPRINTF(line, sizeof(line), "%25s: ML_KEM", type); + break; default: XSNPRINTF(line, sizeof(line), "%25s: UNKNOWN (%08lx)", type, keyType); @@ -406,6 +428,11 @@ static struct PKCS11_MECHANISM_STR { { CKM_AES_KEY_GEN, "CKM_AES_KEY_GEN" }, { CKM_AES_CBC, "CKM_AES_CBC" }, { CKM_AES_GCM, "CKM_AES_GCM" }, + { CKM_ML_KEM_KEY_PAIR_GEN, "CKM_ML_KEM_KEY_PAIR_GEN" }, + { CKM_ML_KEM, "CKM_ML_KEM" }, + { CKM_ML_DSA_KEY_PAIR_GEN, "CKM_ML_DSA_KEY_PAIR_GEN" }, + { CKM_ML_DSA, "CKM_ML_DSA" }, + { CKM_HASH_ML_DSA, "CKM_HASH_ML_DSA" }, }; /* Count of known mechanism for logging. */ #define PKCS11_MECH_STR_CNT ((int)(sizeof(mechStr) / sizeof(*mechStr))) @@ -430,7 +457,7 @@ static void pkcs11_dump_mechanism(const char* op, CK_MECHANISM_TYPE mech) break; } } - if (i == PKCS11_TYPE_STR_CNT) { + if (i == PKCS11_MECH_STR_CNT) { mechName = "UNKNOWN"; } @@ -1546,6 +1573,208 @@ static int Pkcs11CreateEccPrivateKey(CK_OBJECT_HANDLE* privateKey, } #endif +#ifdef HAVE_PKCS11_MLKEM +/** + * Create a PKCS#11 object containing the ML-KEM public key data. + */ +static int Pkcs11CreateMlKemPublicKey(CK_OBJECT_HANDLE* handle, + Pkcs11Session* session, + MlKemKey* key, + CK_MECHANISM_INFO_PTR mechInfo) +{ + int ret = 0; + CK_RV rv; + CK_ULONG publicKeyLen = 0; + CK_ML_KEM_PARAMETER_SET_TYPE param_set = 0; + unsigned char* publicKey = NULL; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, + { CKA_ENCAPSULATE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, NULL, 0 }, + { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + }; + CK_ULONG keyTmplCnt = + sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; + + if (mechInfo == NULL || (key->flags & MLKEM_FLAG_PUB_SET) == 0) { + ret = BAD_FUNC_ARG; + } + if (ret == 0 && key->labelLen > 0) { + keyTemplate[keyTmplCnt].type = CKA_LABEL; + keyTemplate[keyTmplCnt].pValue = key->label; + keyTemplate[keyTmplCnt].ulValueLen = key->labelLen; + keyTmplCnt++; + } + if (ret == 0 && key->idLen > 0) { + keyTemplate[keyTmplCnt].type = CKA_ID; + keyTemplate[keyTmplCnt].pValue = key->id; + keyTemplate[keyTmplCnt].ulValueLen = key->idLen; + keyTmplCnt++; + } + if (ret == 0) { + switch (key->type) { + #ifndef WOLFSSL_NO_ML_KEM + case WC_ML_KEM_512: + param_set = CKP_ML_KEM_512; + publicKeyLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE; + break; + case WC_ML_KEM_768: + param_set = CKP_ML_KEM_768; + publicKeyLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE; + break; + case WC_ML_KEM_1024: + param_set = CKP_ML_KEM_1024; + publicKeyLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE; + break; + default: + ret = NOT_COMPILED_IN; + break; + #else + default: + ret = NOT_COMPILED_IN; + break; + #endif + } + } + if ((ret == 0) && + ((mechInfo->ulMinKeySize > publicKeyLen) || + (mechInfo->ulMaxKeySize < publicKeyLen))) { + ret = WC_KEY_SIZE_E; + } + if (ret == 0) { + publicKey = (unsigned char*)XMALLOC(publicKeyLen, key->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (publicKey == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0) { + ret = wc_MlKemKey_EncodePublicKey(key, publicKey, (word32)publicKeyLen); + } + if (ret == 0) { + keyTemplate[3].pValue = publicKey; + keyTemplate[3].ulValueLen = publicKeyLen; + + PKCS11_DUMP_TEMPLATE("ML-KEM Public Key", keyTemplate, keyTmplCnt); + rv = session->func->C_CreateObject(session->handle, keyTemplate, + keyTmplCnt, handle); + PKCS11_RV("C_CreateObject", rv); + if (rv != CKR_OK) { + ret = WC_HW_E; + } + } + + XFREE(publicKey, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/** + * Create a PKCS#11 object containing the ML-KEM private key data. + */ +static int Pkcs11CreateMlKemPrivateKey(CK_OBJECT_HANDLE* privateKey, + Pkcs11Session* session, + MlKemKey* key, + CK_MECHANISM_INFO_PTR mechInfo) +{ + int ret = 0; + CK_RV rv; + CK_ULONG privateKeyLen = 0; + CK_ML_KEM_PARAMETER_SET_TYPE param_set = 0; + unsigned char* privateData = NULL; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, + { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, + { CKA_DECAPSULATE, &ckTrue, sizeof(ckTrue) }, + { CKA_VALUE, NULL, 0 }, + { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, + { 0, NULL, 0 }, + { 0, NULL, 0 }, + }; + CK_ULONG keyTmplCnt = + sizeof(keyTemplate) / sizeof(*keyTemplate) - 2; + + if (mechInfo == NULL || (key->flags & MLKEM_FLAG_PRIV_SET) == 0) { + ret = BAD_FUNC_ARG; + } + if (ret == 0 && key->labelLen > 0) { + keyTemplate[keyTmplCnt].type = CKA_LABEL; + keyTemplate[keyTmplCnt].pValue = key->label; + keyTemplate[keyTmplCnt].ulValueLen = key->labelLen; + keyTmplCnt++; + } + if (ret == 0 && key->idLen > 0) { + keyTemplate[keyTmplCnt].type = CKA_ID; + keyTemplate[keyTmplCnt].pValue = key->id; + keyTemplate[keyTmplCnt].ulValueLen = key->idLen; + keyTmplCnt++; + } + if (ret == 0) { + switch (key->type) { + #ifndef WOLFSSL_NO_ML_KEM + case WC_ML_KEM_512: + param_set = CKP_ML_KEM_512; + privateKeyLen = WC_ML_KEM_512_PRIVATE_KEY_SIZE; + break; + case WC_ML_KEM_768: + param_set = CKP_ML_KEM_768; + privateKeyLen = WC_ML_KEM_768_PRIVATE_KEY_SIZE; + break; + case WC_ML_KEM_1024: + param_set = CKP_ML_KEM_1024; + privateKeyLen = WC_ML_KEM_1024_PRIVATE_KEY_SIZE; + break; + default: + ret = NOT_COMPILED_IN; + break; + #else + default: + ret = NOT_COMPILED_IN; + break; + #endif + } + } + if ((ret == 0) && + ((mechInfo->ulMinKeySize > privateKeyLen) || + (mechInfo->ulMaxKeySize < privateKeyLen))) { + ret = WC_KEY_SIZE_E; + } + if (ret == 0) { + privateData = (unsigned char*)XMALLOC(privateKeyLen, key->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (privateData == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0) { + ret = wc_MlKemKey_EncodePrivateKey(key, privateData, + (word32)privateKeyLen); + } + if (ret == 0) { + keyTemplate[3].pValue = privateData; + keyTemplate[3].ulValueLen = privateKeyLen; + + PKCS11_DUMP_TEMPLATE("ML-KEM Private Key", keyTemplate, keyTmplCnt); + rv = session->func->C_CreateObject(session->handle, keyTemplate, + keyTmplCnt, privateKey); + PKCS11_RV("C_CreateObject", rv); + if (rv != CKR_OK) { + ret = WC_HW_E; + } + } + + if (privateData != NULL) { + ForceZero(privateData, privateKeyLen); + } + XFREE(privateData, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} +#endif /* HAVE_PKCS11_MLKEM */ + #ifdef HAVE_DILITHIUM /** * Create a PKCS#11 object containing the ML-DSA public key data. @@ -1720,7 +1949,8 @@ static int Pkcs11CreateMldsaPrivateKey(CK_OBJECT_HANDLE* privateKey, #if !defined(NO_RSA) || defined(HAVE_ECC) || (!defined(NO_AES) && \ (defined(HAVE_AESGCM) || defined(HAVE_AES_CBC))) || \ - !defined(NO_HMAC) || defined(HAVE_DILITHIUM) + !defined(NO_HMAC) || defined(HAVE_DILITHIUM) || \ + defined(HAVE_PKCS11_MLKEM) /** * Check if mechanism is available in session on token. * @@ -1962,6 +2192,32 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key) break; } #endif + #ifdef HAVE_PKCS11_MLKEM + case PKCS11_KEY_TYPE_MLKEM: { + MlKemKey* mlkemKey = (MlKemKey*)key; + CK_MECHANISM_INFO mechInfo; + + ret = Pkcs11MechAvail(&session, CKM_ML_KEM, &mechInfo); + if (ret == 0 && ((mlkemKey->flags & MLKEM_FLAG_PRIV_SET) != 0)) { + ret = Pkcs11CreateMlKemPrivateKey(&privKey, &session, + mlkemKey, &mechInfo); + } + if (ret == 0 && ((mlkemKey->flags & MLKEM_FLAG_PUB_SET) != 0)) { + CK_OBJECT_HANDLE pubKey = NULL_PTR; + ret = Pkcs11CreateMlKemPublicKey(&pubKey, &session, + mlkemKey, &mechInfo); + if (ret != 0 && privKey != NULL_PTR) { + session.func->C_DestroyObject(session.handle, privKey); + } + } + if (ret == 0 && clear && + ((mlkemKey->flags & MLKEM_FLAG_PRIV_SET) != 0)) { + ForceZero(mlkemKey->priv, sizeof(mlkemKey->priv)); + ForceZero(mlkemKey->z, sizeof(mlkemKey->z)); + } + break; + } + #endif /* HAVE_PKCS11_MLKEM */ #if defined(HAVE_DILITHIUM) case PKCS11_KEY_TYPE_MLDSA: { MlDsaKey* mldsaKey = (MlDsaKey*) key; @@ -3979,6 +4235,506 @@ static int Pkcs11EccDeletePrivKey(Pkcs11Session* session, ecc_key* key) } #endif +#ifdef HAVE_PKCS11_MLKEM +static int Pkcs11FindMlKemKey(CK_OBJECT_HANDLE* handle, + CK_OBJECT_CLASS keyClass, + Pkcs11Session* session, + MlKemKey* key) +{ + int ret = 0; + CK_ULONG count = 0; + CK_ML_KEM_PARAMETER_SET_TYPE param_set = 0; + CK_ATTRIBUTE keyTemplate[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, + { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, + }; + CK_ULONG attrCnt = + sizeof(keyTemplate) / sizeof(*keyTemplate); + + switch (key->type) { + #ifndef WOLFSSL_NO_ML_KEM + case WC_ML_KEM_512: + param_set = CKP_ML_KEM_512; + break; + case WC_ML_KEM_768: + param_set = CKP_ML_KEM_768; + break; + case WC_ML_KEM_1024: + param_set = CKP_ML_KEM_1024; + break; + default: + ret = NOT_COMPILED_IN; + break; + #else + default: + ret = NOT_COMPILED_IN; + break; + #endif + } + if (ret == 0) { + ret = Pkcs11FindKeyByTemplate(handle, session, keyTemplate, attrCnt, + &count); + } + if (ret == 0 && count == 0) { + ret = WC_HW_E; + } + + return ret; +} + +static int Pkcs11GetMlKemPublicKey(MlKemKey* key, Pkcs11Session* session, + CK_OBJECT_HANDLE keyHandle) +{ + int ret = 0; + CK_ULONG pubKeySize; + CK_ML_KEM_PARAMETER_SET_TYPE paramSet = 0; + unsigned char* pubKey = NULL; + CK_ATTRIBUTE tmpl[] = { + { CKA_VALUE, NULL, 0 }, + { CKA_PARAMETER_SET, ¶mSet, sizeof(paramSet) } + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + CK_RV rv; + + PKCS11_DUMP_TEMPLATE("Get ML-KEM Public Key Length", tmpl, tmplCnt); + rv = session->func->C_GetAttributeValue(session->handle, keyHandle, + tmpl, tmplCnt); + PKCS11_RV("C_GetAttributeValue", rv); + if (rv != CKR_OK) { + ret = WC_HW_E; + } + PKCS11_DUMP_TEMPLATE("ML-KEM Public Key Length", tmpl, tmplCnt); + + if (ret == 0) { + #ifndef WOLFSSL_NO_ML_KEM + switch (paramSet) { + case CKP_ML_KEM_512: + key->type = WC_ML_KEM_512; + break; + case CKP_ML_KEM_768: + key->type = WC_ML_KEM_768; + break; + case CKP_ML_KEM_1024: + key->type = WC_ML_KEM_1024; + break; + default: + ret = WC_KEY_SIZE_E; + break; + } + #else + ret = NOT_COMPILED_IN; + #endif + } + if (ret == 0) { + pubKeySize = tmpl[0].ulValueLen; + pubKey = (unsigned char*)XMALLOC(pubKeySize, key->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (pubKey == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0) { + tmpl[0].pValue = pubKey; + + PKCS11_DUMP_TEMPLATE("Get ML-KEM Public Key", tmpl, tmplCnt); + rv = session->func->C_GetAttributeValue(session->handle, keyHandle, + tmpl, tmplCnt); + PKCS11_RV("C_GetAttributeValue", rv); + if (rv != CKR_OK) { + ret = WC_HW_E; + } + PKCS11_DUMP_TEMPLATE("ML-KEM Public Key", tmpl, tmplCnt); + } + if (ret == 0) { + ret = wc_MlKemKey_DecodePublicKey(key, pubKey, (word32)pubKeySize); + } + + XFREE(pubKey, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +static int Pkcs11MlKemKeyGen(Pkcs11Session* session, MlKemKey* key) +{ + int ret = 0; + CK_RV rv; + CK_OBJECT_HANDLE pubKey = NULL_PTR, privKey = NULL_PTR; + CK_MECHANISM mech; + CK_MECHANISM_INFO mechInfo; + CK_ML_KEM_PARAMETER_SET_TYPE param_set = 0; + CK_ULONG pubKeyLen = 0; + CK_ATTRIBUTE pubKeyTmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_ENCAPSULATE, &ckTrue, sizeof(ckTrue) }, + { CKA_KEY_TYPE, &mlkemKeyType, sizeof(mlkemKeyType) }, + { CKA_PARAMETER_SET, ¶m_set, sizeof(param_set) }, + { 0, NULL, 0 }, + { 0, NULL, 0 } + }; + CK_ULONG pubTmplCnt = + sizeof(pubKeyTmpl) / sizeof(*pubKeyTmpl) - 2; + 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 } + }; + CK_ULONG privTmplCnt = + sizeof(privKeyTmpl) / sizeof(*privKeyTmpl) - 2; + + ret = Pkcs11MechAvail(session, CKM_ML_KEM_KEY_PAIR_GEN, &mechInfo); + if (ret == 0) { + switch (key->type) { + #ifndef WOLFSSL_NO_ML_KEM + case WC_ML_KEM_512: + param_set = CKP_ML_KEM_512; + pubKeyLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE; + break; + case WC_ML_KEM_768: + param_set = CKP_ML_KEM_768; + pubKeyLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE; + break; + case WC_ML_KEM_1024: + param_set = CKP_ML_KEM_1024; + pubKeyLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE; + break; + default: + ret = NOT_COMPILED_IN; + break; + #else + default: + ret = NOT_COMPILED_IN; + break; + #endif + } + } + if ((ret == 0) && + ((mechInfo.ulMinKeySize > pubKeyLen) || + (mechInfo.ulMaxKeySize < pubKeyLen))) { + ret = WC_KEY_SIZE_E; + } + if (ret == 0) { + WOLFSSL_MSG("PKCS#11: ML-KEM Key Generation Operation"); + + if (key->labelLen != 0) { + privKeyTmpl[privTmplCnt].type = CKA_LABEL; + privKeyTmpl[privTmplCnt].pValue = key->label; + privKeyTmpl[privTmplCnt].ulValueLen = key->labelLen; + privTmplCnt++; + + pubKeyTmpl[pubTmplCnt].type = CKA_LABEL; + pubKeyTmpl[pubTmplCnt].pValue = key->label; + pubKeyTmpl[pubTmplCnt].ulValueLen = key->labelLen; + pubTmplCnt++; + } + if (key->idLen != 0) { + privKeyTmpl[privTmplCnt].type = CKA_ID; + privKeyTmpl[privTmplCnt].pValue = key->id; + privKeyTmpl[privTmplCnt].ulValueLen = key->idLen; + privTmplCnt++; + + pubKeyTmpl[pubTmplCnt].type = CKA_ID; + pubKeyTmpl[pubTmplCnt].pValue = key->id; + pubKeyTmpl[pubTmplCnt].ulValueLen = key->idLen; + pubTmplCnt++; + } + + mech.mechanism = CKM_ML_KEM_KEY_PAIR_GEN; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + PKCS11_DUMP_TEMPLATE("Private Key", privKeyTmpl, privTmplCnt); + PKCS11_DUMP_TEMPLATE("Public Key", pubKeyTmpl, pubTmplCnt); + rv = session->func->C_GenerateKeyPair(session->handle, &mech, + pubKeyTmpl, pubTmplCnt, + privKeyTmpl, privTmplCnt, + &pubKey, &privKey); + PKCS11_RV("C_GenerateKeyPair", rv); + if (rv != CKR_OK) { + ret = WC_HW_E; + } + } + if (ret == 0) { + ret = Pkcs11GetMlKemPublicKey(key, session, pubKey); + } + + if (pubKey != NULL_PTR) { + session->func->C_DestroyObject(session->handle, pubKey); + } + if (ret == 0 && privKey != NULL_PTR) { + key->devCtx = (void*)(wc_ptr_t)privKey; + key->flags |= MLKEM_FLAG_PRIV_SET; + } + else if (ret != 0 && privKey != NULL_PTR) { + session->func->C_DestroyObject(session->handle, privKey); + } + + return ret; +} + +static int Pkcs11MlKemEncapsulate(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + int sessionKey = 0; + CK_RV rv; + CK_MECHANISM mech; + CK_MECHANISM_INFO mechInfo; + CK_ULONG ctLen; + CK_OBJECT_HANDLE publicKey = NULL_PTR; + CK_OBJECT_HANDLE sharedKey = NULL_PTR; + CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; + CK_FUNCTION_LIST_3_2_PTR functionList = NULL; + MlKemKey* key = (MlKemKey*)info->pk.pqc_encaps.key; + word32 outLen = WC_ML_KEM_SS_SZ; + CK_ATTRIBUTE sharedKeyTempl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + }; + CK_ULONG sharedKeyTmplCnt = + sizeof(sharedKeyTempl) / sizeof(*sharedKeyTempl); + + if (session->version >= WC_PCKS11VERSION_3_2) { + functionList = (CK_FUNCTION_LIST_3_2_PTR)session->func; + } + else { + return NOT_COMPILED_IN; + } + + ret = Pkcs11MechAvail(session, CKM_ML_KEM, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_ENCAPSULATE) == 0) { + ret = NOT_COMPILED_IN; + } + if (ret == 0 && info->pk.pqc_encaps.sharedSecret == NULL) { + ret = BAD_FUNC_ARG; + } + if (ret == 0 && info->pk.pqc_encaps.ciphertext == NULL) { + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + WOLFSSL_MSG("PKCS#11: ML-KEM Encapsulation Operation"); + + if (key->labelLen > 0) { + ret = Pkcs11FindKeyByLabel(&publicKey, CKO_PUBLIC_KEY, CKK_ML_KEM, + session, key->label, key->labelLen); + } + else if (key->idLen > 0) { + ret = Pkcs11FindKeyById(&publicKey, CKO_PUBLIC_KEY, CKK_ML_KEM, + session, key->id, key->idLen); + } + else if ((key->flags & MLKEM_FLAG_PUB_SET) != 0) { + ret = Pkcs11CreateMlKemPublicKey(&publicKey, session, key, + &mechInfo); + sessionKey = 1; + } + else { + ret = Pkcs11FindMlKemKey(&publicKey, CKO_PUBLIC_KEY, session, key); + } + } + if (ret == 0) { + mech.mechanism = CKM_ML_KEM; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + ctLen = info->pk.pqc_encaps.ciphertextLen; + + rv = functionList->C_EncapsulateKey(session->handle, &mech, publicKey, + sharedKeyTempl, sharedKeyTmplCnt, + (CK_BYTE_PTR) + info->pk.pqc_encaps.ciphertext, + &ctLen, + &sharedKey); + PKCS11_RV("C_EncapsulateKey", rv); + if (rv != CKR_OK || + (word32)ctLen != info->pk.pqc_encaps.ciphertextLen) { + ret = WC_HW_E; + } + } + if (ret == 0) { + outLen = info->pk.pqc_encaps.sharedSecretLen; + ret = Pkcs11ExtractSecret(session, sharedKey, + info->pk.pqc_encaps.sharedSecret, &outLen); + if (ret == 0 && outLen != info->pk.pqc_encaps.sharedSecretLen) { + ret = WC_HW_E; + } + } + + if (sessionKey && publicKey != NULL_PTR) { + session->func->C_DestroyObject(session->handle, publicKey); + } + if (sharedKey != NULL_PTR) { + session->func->C_DestroyObject(session->handle, sharedKey); + } + + return ret; +} + +static int Pkcs11MlKemDecapsulate(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + int sessionKey = 0; + CK_RV rv; + CK_MECHANISM mech; + CK_MECHANISM_INFO mechInfo; + CK_OBJECT_HANDLE privateKey = NULL_PTR; + CK_OBJECT_HANDLE sharedKey = NULL_PTR; + CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; + CK_FUNCTION_LIST_3_2_PTR functionList = NULL; + MlKemKey* key = (MlKemKey*)info->pk.pqc_decaps.key; + word32 outLen = WC_ML_KEM_SS_SZ; + CK_ATTRIBUTE sharedKeyTempl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + }; + CK_ULONG sharedKeyTmplCnt = + sizeof(sharedKeyTempl) / sizeof(*sharedKeyTempl); + + if (session->version >= WC_PCKS11VERSION_3_2) { + functionList = (CK_FUNCTION_LIST_3_2_PTR)session->func; + } + else { + return NOT_COMPILED_IN; + } + + ret = Pkcs11MechAvail(session, CKM_ML_KEM, &mechInfo); + if (ret == 0 && (mechInfo.flags & CKF_DECAPSULATE) == 0) { + ret = NOT_COMPILED_IN; + } + if (ret == 0 && info->pk.pqc_decaps.sharedSecret == NULL) { + ret = BAD_FUNC_ARG; + } + if (ret == 0 && info->pk.pqc_decaps.ciphertext == NULL) { + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + WOLFSSL_MSG("PKCS#11: ML-KEM Decapsulation Operation"); + + if (key->devCtx != NULL) { + privateKey = (CK_OBJECT_HANDLE)(wc_ptr_t)key->devCtx; + } + else if (key->labelLen > 0) { + ret = Pkcs11FindKeyByLabel(&privateKey, CKO_PRIVATE_KEY, + CKK_ML_KEM, session, + key->label, key->labelLen); + } + else if (key->idLen > 0) { + ret = Pkcs11FindKeyById(&privateKey, CKO_PRIVATE_KEY, CKK_ML_KEM, + session, key->id, key->idLen); + } + else if ((key->flags & MLKEM_FLAG_PRIV_SET) != 0) { + ret = Pkcs11CreateMlKemPrivateKey(&privateKey, session, key, + &mechInfo); + sessionKey = 1; + } + else { + ret = Pkcs11FindMlKemKey(&privateKey, CKO_PRIVATE_KEY, session, + key); + } + } + if (ret == 0) { + mech.mechanism = CKM_ML_KEM; + mech.ulParameterLen = 0; + mech.pParameter = NULL; + + rv = functionList->C_DecapsulateKey(session->handle, &mech, privateKey, + sharedKeyTempl, sharedKeyTmplCnt, + (CK_BYTE_PTR) + info->pk.pqc_decaps.ciphertext, + info->pk.pqc_decaps.ciphertextLen, + &sharedKey); + PKCS11_RV("C_DecapsulateKey", rv); + if (rv != CKR_OK) { + ret = WC_HW_E; + } + } + if (ret == 0) { + outLen = info->pk.pqc_decaps.sharedSecretLen; + ret = Pkcs11ExtractSecret(session, sharedKey, + info->pk.pqc_decaps.sharedSecret, &outLen); + if (ret == 0 && outLen != info->pk.pqc_decaps.sharedSecretLen) { + ret = WC_HW_E; + } + } + + if (sessionKey && privateKey != NULL_PTR) { + session->func->C_DestroyObject(session->handle, privateKey); + } + if (sharedKey != NULL_PTR) { + session->func->C_DestroyObject(session->handle, sharedKey); + } + + return ret; +} + +static int Pkcs11MlKemDeletePrivKey(Pkcs11Session* session, MlKemKey* key) +{ + CK_OBJECT_HANDLE privateKey; + + if (key != NULL && key->devCtx != NULL) { + privateKey = (CK_OBJECT_HANDLE)(wc_ptr_t)key->devCtx; + session->func->C_DestroyObject(session->handle, privateKey); + key->devCtx = NULL; + } + + return 0; +} + +static int Pkcs11PqcKemKeyGen(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + + switch (info->pk.pqc_kem_kg.type) { + case WC_PQC_KEM_TYPE_KYBER: + ret = Pkcs11MlKemKeyGen(session, + (MlKemKey*)info->pk.pqc_kem_kg.key); + break; + default: + ret = NOT_COMPILED_IN; + break; + } + + return ret; +} + +static int Pkcs11PqcKemEncapsulate(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + + switch (info->pk.pqc_encaps.type) { + case WC_PQC_KEM_TYPE_KYBER: + ret = Pkcs11MlKemEncapsulate(session, info); + break; + default: + ret = NOT_COMPILED_IN; + break; + } + + return ret; +} + +static int Pkcs11PqcKemDecapsulate(Pkcs11Session* session, wc_CryptoInfo* info) +{ + int ret = 0; + + switch (info->pk.pqc_decaps.type) { + case WC_PQC_KEM_TYPE_KYBER: + ret = Pkcs11MlKemDecapsulate(session, info); + break; + default: + ret = NOT_COMPILED_IN; + break; + } + + return ret; +} +#endif /* HAVE_PKCS11_MLKEM */ + #if defined(HAVE_DILITHIUM) /** * Find the PKCS#11 object containing the ML-DSA public or private key data. @@ -5560,7 +6316,8 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) */ if (ret == 0) { if (info->algo_type == WC_ALGO_TYPE_PK) { -#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_DILITHIUM) +#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_DILITHIUM) || \ + defined(HAVE_PKCS11_MLKEM) switch (info->pk.type) { #ifndef NO_RSA case WC_PK_TYPE_RSA: @@ -5640,6 +6397,29 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) } break; #endif + #ifdef HAVE_PKCS11_MLKEM + case WC_PK_TYPE_PQC_KEM_KEYGEN: + ret = Pkcs11OpenSession(token, &session, readWrite); + if (ret == 0) { + ret = Pkcs11PqcKemKeyGen(&session, info); + Pkcs11CloseSession(token, &session); + } + break; + case WC_PK_TYPE_PQC_KEM_ENCAPS: + ret = Pkcs11OpenSession(token, &session, readWrite); + if (ret == 0) { + ret = Pkcs11PqcKemEncapsulate(&session, info); + Pkcs11CloseSession(token, &session); + } + break; + case WC_PK_TYPE_PQC_KEM_DECAPS: + ret = Pkcs11OpenSession(token, &session, readWrite); + if (ret == 0) { + ret = Pkcs11PqcKemDecapsulate(&session, info); + Pkcs11CloseSession(token, &session); + } + break; + #endif #if defined(HAVE_DILITHIUM) case WC_PK_TYPE_PQC_SIG_KEYGEN: ret = Pkcs11OpenSession(token, &session, readWrite); @@ -5676,7 +6456,7 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) } #else ret = NOT_COMPILED_IN; -#endif /* !NO_RSA || HAVE_ECC || HAVE_DILITHIUM */ +#endif /* !NO_RSA || HAVE_ECC || HAVE_DILITHIUM || HAVE_PKCS11_MLKEM */ } else if (info->algo_type == WC_ALGO_TYPE_CIPHER) { #ifndef NO_AES @@ -5794,12 +6574,6 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) (ecc_key*)info->free.obj); Pkcs11CloseSession(token, &session); } - /* Return CRYPTOCB_UNAVAILABLE so wc_ecc_free() still - * performs software cleanup. This callback only releases - * the HSM object. Conditional because wc_ecc_free returns - * int and can propagate an HSM error to the caller. */ - if (ret == 0) - ret = CRYPTOCB_UNAVAILABLE; } else #endif @@ -5813,11 +6587,19 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) (MlDsaKey*)info->free.obj); Pkcs11CloseSession(token, &session); } - /* Always return CRYPTOCB_UNAVAILABLE so wc_dilithium_free() - * performs software cleanup. This callback only releases - * the HSM object. Unconditional because wc_dilithium_free - * returns void and cannot propagate an error. */ - ret = CRYPTOCB_UNAVAILABLE; + } + else + #endif + #ifdef HAVE_PKCS11_MLKEM + if (info->free.algo == WC_ALGO_TYPE_PK && + info->free.type == WC_PK_TYPE_PQC_KEM_KEYGEN && + info->free.subType == WC_PQC_KEM_TYPE_KYBER) { + ret = Pkcs11OpenSession(token, &session, readWrite); + if (ret == 0) { + ret = Pkcs11MlKemDeletePrivKey(&session, + (MlKemKey*)info->free.obj); + Pkcs11CloseSession(token, &session); + } } else #endif diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index a3d6dcfcda..a86580b685 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -42564,6 +42564,7 @@ static wc_test_ret_t mlkem512_kat(void) #endif #endif int key_inited = 0; + const int katDevId = INVALID_DEVID; WOLFSSL_SMALL_STACK_STATIC const byte kyber512_rand[] = { 0x7c, 0x99, 0x35, 0xa0, 0xb0, 0x76, 0x94, 0xaa, 0x0c, 0x6d, 0x10, 0xe4, 0xdb, 0x6b, 0x1a, 0xdd, @@ -43451,7 +43452,7 @@ static wc_test_ret_t mlkem512_kat(void) #endif #ifdef WOLFSSL_MLKEM_KYBER - ret = wc_KyberKey_Init(KYBER512, key, HEAP_HINT, devId); + ret = wc_KyberKey_Init(KYBER512, key, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else @@ -43514,7 +43515,7 @@ static wc_test_ret_t mlkem512_kat(void) #endif #endif #ifndef WOLFSSL_NO_ML_KEM - ret = wc_MlKemKey_Init(key, WC_ML_KEM_512, HEAP_HINT, devId); + ret = wc_MlKemKey_Init(key, WC_ML_KEM_512, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else @@ -43577,7 +43578,7 @@ static wc_test_ret_t mlkem512_kat(void) wc_MlKemKey_Free(key); XMEMSET(key, 0, sizeof(MlKemKey)); key_inited = 0; - ret = wc_MlKemKey_Init(key, WC_ML_KEM_512, HEAP_HINT, devId); + ret = wc_MlKemKey_Init(key, WC_ML_KEM_512, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else @@ -43657,6 +43658,7 @@ static wc_test_ret_t mlkem768_kat(void) #endif #endif int key_inited = 0; + const int katDevId = INVALID_DEVID; WOLFSSL_SMALL_STACK_STATIC const byte kyber768_rand[] = { 0x7c, 0x99, 0x35, 0xa0, 0xb0, 0x76, 0x94, 0xaa, 0x0c, 0x6d, 0x10, 0xe4, 0xdb, 0x6b, 0x1a, 0xdd, @@ -44913,7 +44915,7 @@ static wc_test_ret_t mlkem768_kat(void) #endif #ifdef WOLFSSL_MLKEM_KYBER - ret = wc_KyberKey_Init(KYBER768, key, HEAP_HINT, devId); + ret = wc_KyberKey_Init(KYBER768, key, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else @@ -44976,7 +44978,7 @@ static wc_test_ret_t mlkem768_kat(void) #endif #endif #ifndef WOLFSSL_NO_ML_KEM - ret = wc_MlKemKey_Init(key, WC_ML_KEM_768, HEAP_HINT, devId); + ret = wc_MlKemKey_Init(key, WC_ML_KEM_768, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else @@ -45096,6 +45098,7 @@ static wc_test_ret_t mlkem1024_kat(void) #endif #endif int key_inited = 0; + const int katDevId = INVALID_DEVID; WOLFSSL_SMALL_STACK_STATIC const byte kyber1024_rand[] = { 0x7c, 0x99, 0x35, 0xa0, 0xb0, 0x76, 0x94, 0xaa, 0x0c, 0x6d, 0x10, 0xe4, 0xdb, 0x6b, 0x1a, 0xdd, @@ -46759,7 +46762,7 @@ static wc_test_ret_t mlkem1024_kat(void) #endif #ifdef WOLFSSL_MLKEM_KYBER - ret = wc_KyberKey_Init(KYBER1024, key, HEAP_HINT, devId); + ret = wc_KyberKey_Init(KYBER1024, key, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else @@ -46822,7 +46825,7 @@ static wc_test_ret_t mlkem1024_kat(void) #endif #endif #ifndef WOLFSSL_NO_ML_KEM - ret = wc_MlKemKey_Init(key, WC_ML_KEM_1024, HEAP_HINT, devId); + ret = wc_MlKemKey_Init(key, WC_ML_KEM_1024, HEAP_HINT, katDevId); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out); else @@ -64975,6 +64978,92 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) } #endif #endif /* HAVE_ED25519 */ + #ifdef WOLFSSL_HAVE_MLKEM + if (info->pk.type == WC_PK_TYPE_PQC_KEM_KEYGEN) { + if ((info->pk.pqc_kem_kg.type == WC_PQC_KEM_TYPE_KYBER) && + (info->pk.pqc_kem_kg.key != NULL)) { + MlKemKey* key = (MlKemKey*)info->pk.pqc_kem_kg.key; +#ifdef WOLFSSL_WC_MLKEM + int hashDevId = key->hash.devId; + int prfDevId = key->prf.devId; +#endif + + /* set devId to invalid, so software is used */ + key->devId = INVALID_DEVID; +#ifdef WOLFSSL_WC_MLKEM + key->hash.devId = INVALID_DEVID; + key->prf.devId = INVALID_DEVID; +#endif + + ret = wc_MlKemKey_MakeKey(key, info->pk.pqc_kem_kg.rng); + + /* reset devId */ + key->devId = devIdArg; +#ifdef WOLFSSL_WC_MLKEM + key->hash.devId = hashDevId; + key->prf.devId = prfDevId; +#endif + } + } + else if (info->pk.type == WC_PK_TYPE_PQC_KEM_ENCAPS) { + if ((info->pk.pqc_encaps.type == WC_PQC_KEM_TYPE_KYBER) && + (info->pk.pqc_encaps.key != NULL)) { + MlKemKey* key = (MlKemKey*)info->pk.pqc_encaps.key; +#ifdef WOLFSSL_WC_MLKEM + int hashDevId = key->hash.devId; + int prfDevId = key->prf.devId; +#endif + + /* set devId to invalid, so software is used */ + key->devId = INVALID_DEVID; +#ifdef WOLFSSL_WC_MLKEM + key->hash.devId = INVALID_DEVID; + key->prf.devId = INVALID_DEVID; +#endif + + ret = wc_MlKemKey_Encapsulate(key, + info->pk.pqc_encaps.ciphertext, + info->pk.pqc_encaps.sharedSecret, + info->pk.pqc_encaps.rng); + + /* reset devId */ + key->devId = devIdArg; +#ifdef WOLFSSL_WC_MLKEM + key->hash.devId = hashDevId; + key->prf.devId = prfDevId; +#endif + } + } + else if (info->pk.type == WC_PK_TYPE_PQC_KEM_DECAPS) { + if ((info->pk.pqc_decaps.type == WC_PQC_KEM_TYPE_KYBER) && + (info->pk.pqc_decaps.key != NULL)) { + MlKemKey* key = (MlKemKey*)info->pk.pqc_decaps.key; +#ifdef WOLFSSL_WC_MLKEM + int hashDevId = key->hash.devId; + int prfDevId = key->prf.devId; +#endif + + /* set devId to invalid, so software is used */ + key->devId = INVALID_DEVID; +#ifdef WOLFSSL_WC_MLKEM + key->hash.devId = INVALID_DEVID; + key->prf.devId = INVALID_DEVID; +#endif + + ret = wc_MlKemKey_Decapsulate(key, + info->pk.pqc_decaps.sharedSecret, + info->pk.pqc_decaps.ciphertext, + info->pk.pqc_decaps.ciphertextLen); + + /* reset devId */ + key->devId = devIdArg; +#ifdef WOLFSSL_WC_MLKEM + key->hash.devId = hashDevId; + key->prf.devId = prfDevId; +#endif + } + } + #endif /* WOLFSSL_HAVE_MLKEM */ } else if (info->algo_type == WC_ALGO_TYPE_CIPHER) { #if !defined(NO_AES) || !defined(NO_DES3) @@ -65680,6 +65769,21 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) } break; } +#endif +#ifdef WOLFSSL_HAVE_MLKEM + case WC_PK_TYPE_PQC_KEM_KEYGEN: + { + if (info->free.subType == WC_PQC_KEM_TYPE_KYBER) { + MlKemKey* mlkem = (MlKemKey*)info->free.obj; + mlkem->devId = INVALID_DEVID; +#ifdef WOLFSSL_WC_MLKEM + mlkem->hash.devId = INVALID_DEVID; + mlkem->prf.devId = INVALID_DEVID; +#endif + ret = wc_MlKemKey_Free(mlkem); + } + break; + } #endif default: ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); @@ -65873,6 +65977,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) ret = ecc_onlycb_test(&myCtx); PRIVATE_KEY_LOCK(); #endif +#ifdef WOLFSSL_HAVE_MLKEM + if (ret == 0) + ret = mlkem_test(); +#endif #ifdef HAVE_DILITHIUM if (ret == 0) ret = dilithium_test(); diff --git a/wolfssl/wolfcrypt/mlkem.h b/wolfssl/wolfcrypt/mlkem.h index eeb93f8db9..4c185482b8 100644 --- a/wolfssl/wolfcrypt/mlkem.h +++ b/wolfssl/wolfcrypt/mlkem.h @@ -304,6 +304,10 @@ enum { WC_ML_KEM_POLY_SIZE = 384 }; +#ifdef WOLF_PRIVATE_KEY_ID + #define MLKEM_MAX_ID_LEN 32 + #define MLKEM_MAX_LABEL_LEN 32 +#endif /* Different structures for different implementations. */ typedef struct MlKemKey MlKemKey; @@ -319,6 +323,12 @@ WOLFSSL_API int wc_MlKemKey_Delete(MlKemKey* key, MlKemKey** key_p); WOLFSSL_API int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, int devId); WOLFSSL_API int wc_MlKemKey_Free(MlKemKey* key); +#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_WC_MLKEM) +WOLFSSL_API int wc_MlKemKey_Init_Id(MlKemKey* key, int type, + const unsigned char* id, int len, void* heap, int devId); +WOLFSSL_API int wc_MlKemKey_Init_Label(MlKemKey* key, int type, + const char* label, void* heap, int devId); +#endif WOLFSSL_API int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng); WOLFSSL_API int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, @@ -352,6 +362,10 @@ WOLFSSL_API int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, #define wc_KyberKey_Init(type, key, heap, devId) \ wc_MlKemKey_Init(key, type, heap, devId) #define wc_KyberKey_Free wc_MlKemKey_Free +#if defined(WOLF_PRIVATE_KEY_ID) && defined(WOLFSSL_WC_MLKEM) +#define wc_KyberKey_Init_Id wc_MlKemKey_Init_Id +#define wc_KyberKey_Init_Label wc_MlKemKey_Init_Label +#endif #define wc_KyberKey_MakeKey wc_MlKemKey_MakeKey #define wc_KyberKey_MakeKeyWithRandom wc_MlKemKey_MakeKeyWithRandom #define wc_KyberKey_CipherTextSize wc_MlKemKey_CipherTextSize @@ -374,4 +388,3 @@ WOLFSSL_API int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, #endif /* WOLFSSL_HAVE_MLKEM */ #endif /* WOLF_CRYPT_MLKEM_H */ - diff --git a/wolfssl/wolfcrypt/pkcs11.h b/wolfssl/wolfcrypt/pkcs11.h index 9885b41ba5..d77a5ccfc7 100644 --- a/wolfssl/wolfcrypt/pkcs11.h +++ b/wolfssl/wolfcrypt/pkcs11.h @@ -61,6 +61,8 @@ extern "C" { #define CKF_EC_NAMEDCURVE 0x00800000UL #define CKF_EC_UNCOMPRESS 0x01000000UL #define CKF_EC_COMPRESS 0x02000000UL +#define CKF_ENCAPSULATE 0x10000000UL +#define CKF_DECAPSULATE 0x20000000UL #define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001UL #define CKF_OS_LOCKING_OK 0x00000002UL @@ -89,6 +91,7 @@ extern "C" { #define CKK_SHA384_HMAC 0x0000002cUL #define CKK_SHA512_HMAC 0x0000002dUL #define CKK_SHA224_HMAC 0x0000002eUL +#define CKK_ML_KEM 0x00000049UL #define CKK_ML_DSA 0x0000004aUL #define CKA_CLASS 0x00000000UL @@ -141,6 +144,8 @@ extern "C" { #define CKA_RESET_ON_INIT 0x00000301UL #define CKA_HAS_RESET 0x00000302UL #define CKA_PARAMETER_SET 0x0000061DUL +#define CKA_ENCAPSULATE 0x00000633UL +#define CKA_DECAPSULATE 0x00000634UL #define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000UL @@ -174,6 +179,8 @@ extern "C" { #define CKM_AES_CBC 0x00001082UL #define CKM_AES_CTR 0x00001086UL #define CKM_AES_GCM 0x00001087UL +#define CKM_ML_KEM_KEY_PAIR_GEN 0x0000000FUL +#define CKM_ML_KEM 0x00000017UL #define CKM_ML_DSA_KEY_PAIR_GEN 0x0000001CUL #define CKM_ML_DSA 0x0000001DUL #define CKM_HASH_ML_DSA 0x0000001FUL @@ -431,6 +438,12 @@ typedef CK_ULONG CK_ML_DSA_PARAMETER_SET_TYPE; #define CKP_ML_DSA_65 0x00000002UL #define CKP_ML_DSA_87 0x00000003UL +/* ML-KEM values for CKA_PARAMETER_SETS */ +typedef CK_ULONG CK_ML_KEM_PARAMETER_SET_TYPE; +#define CKP_ML_KEM_512 0x00000001UL +#define CKP_ML_KEM_768 0x00000002UL +#define CKP_ML_KEM_1024 0x00000003UL + /* Function list types. */ typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST; @@ -1152,12 +1165,12 @@ struct CK_FUNCTION_LIST_3_2 { /* PKCS#11 V 3.2 functions */ CK_RV (*C_EncapsulateKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPublicKey, CK_ATTRIBUTE_PTR pTemplate, - CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey, - CK_BYTE_PTR pCiphertext, CK_ULONG_PTR pulCiphertextLen); + CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, + CK_ULONG_PTR pulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey); CK_RV (*C_DecapsulateKey)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, - CK_OBJECT_HANDLE hPrivateKey, CK_BYTE_PTR pCiphertext, - CK_ULONG ulCiphertextLen, CK_ATTRIBUTE_PTR pTemplate, - CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey); + CK_OBJECT_HANDLE hPrivateKey, CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, CK_BYTE_PTR pCiphertext, + CK_ULONG ulCiphertextLen, CK_OBJECT_HANDLE_PTR phKey); CK_RV (*C_VerifySignatureInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); diff --git a/wolfssl/wolfcrypt/wc_mlkem.h b/wolfssl/wolfcrypt/wc_mlkem.h index e1dccb8c20..dd10c1fd37 100644 --- a/wolfssl/wolfcrypt/wc_mlkem.h +++ b/wolfssl/wolfcrypt/wc_mlkem.h @@ -107,12 +107,21 @@ struct MlKemKey { /* Dynamic memory allocation hint. */ void* heap; #if defined(WOLF_CRYPTO_CB) + /* Device context for hardware key handle. */ + void* devCtx; /* Device Id. */ int devId; #endif /* Flags indicating what is stored in the key. */ int flags; +#ifdef WOLF_PRIVATE_KEY_ID + byte id[MLKEM_MAX_ID_LEN]; + int idLen; + char label[MLKEM_MAX_LABEL_LEN]; + int labelLen; +#endif + /* A pseudo-random function object. */ MLKEM_HASH_T hash; /* A pseudo-random function object. */ diff --git a/wolfssl/wolfcrypt/wc_pkcs11.h b/wolfssl/wolfcrypt/wc_pkcs11.h index b65244ff43..b814b6b182 100644 --- a/wolfssl/wolfcrypt/wc_pkcs11.h +++ b/wolfssl/wolfcrypt/wc_pkcs11.h @@ -79,6 +79,7 @@ enum Pkcs11KeyType { PKCS11_KEY_TYPE_RSA, PKCS11_KEY_TYPE_EC, PKCS11_KEY_TYPE_MLDSA, + PKCS11_KEY_TYPE_MLKEM, }; WOLFSSL_API int wc_Pkcs11_Initialize(Pkcs11Dev* dev, const char* library,