From 2879d60d894aa57277d7168c9c428c91814ef726 Mon Sep 17 00:00:00 2001 From: Hideki Miyazaki Date: Wed, 11 Mar 2026 17:01:15 +0900 Subject: [PATCH] f-311:C_WrapKey check --- src/crypto.c | 34 ++++++++++- tests/pkcs11mtt.c | 2 +- tests/pkcs11test.c | 142 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 170 insertions(+), 8 deletions(-) diff --git a/src/crypto.c b/src/crypto.c index 6dc25d3b..571b5ae9 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -6838,7 +6838,15 @@ CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, * @return CKR_CRYPTOKI_NOT_INITIALIZED when library not initialized. * CKR_SESSION_HANDLE_INVALID when session handle is not valid. * CKR_ARGUMENTS_BAD when pMechanism or pulWrappedKeyLen is NULL. - * CKR_OBJECT_HANDLE_INVALID when a key object handle is not valid. + * CKR_OBJECT_HANDLE_INVALID when hKey object handle is not valid. + * CKR_WRAPPING_KEY_HANDLE_INVALID when hWrappingKey handle is not + * valid. + * CKR_KEY_UNEXTRACTABLE when hKey has CKA_EXTRACTABLE set to + * CK_FALSE. + * CKR_KEY_NOT_WRAPPABLE when hKey has CKA_WRAP_WITH_TRUSTED set to + * CK_TRUE but hWrappingKey does not have CKA_TRUSTED set to CK_TRUE, + * or when the key class/type combination is not supported for + * wrapping. * CKR_MECHANISM_INVALID when the mechanism is not supported with this * type of operation. */ @@ -6858,6 +6866,8 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; word32 serialSize = 0; byte* serialBuff = NULL; + CK_BBOOL getVar; + CK_ULONG getVarLen = sizeof(CK_BBOOL); WOLFPKCS11_ENTER("C_WrapKey"); #ifdef DEBUG_WOLFPKCS11 @@ -6889,6 +6899,14 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, if (ret != 0) return CKR_OBJECT_HANDLE_INVALID; + ret = WP11_Object_GetAttr(key, CKA_EXTRACTABLE, &getVar, &getVarLen); + if (ret != 0) { + return CKR_KEY_NOT_WRAPPABLE; + } + if (getVar == CK_FALSE) { + return CKR_KEY_UNEXTRACTABLE; + } + ret = WP11_Object_Find(session, hWrappingKey, &wrappingKey); if (ret != 0) return CKR_WRAPPING_KEY_HANDLE_INVALID; @@ -6897,6 +6915,20 @@ CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, if (ret != CKR_OK) return ret; + /* key can only be wrapped by a trusted wrapping key */ + getVarLen = sizeof(CK_BBOOL); + ret = WP11_Object_GetAttr(key, CKA_WRAP_WITH_TRUSTED, + &getVar, &getVarLen); + if (ret == CKR_OK && getVar == CK_TRUE) { + CK_BBOOL trustedVar = CK_FALSE; + CK_ULONG trustedVarLen = sizeof(CK_BBOOL); + ret = WP11_Object_GetAttr(wrappingKey, CKA_TRUSTED, + &trustedVar, &trustedVarLen); + if (ret != CKR_OK || trustedVar != CK_TRUE) { + return CKR_KEY_NOT_WRAPPABLE; + } + } + wrapkeyType = WP11_Object_GetType(wrappingKey); keyType = WP11_Object_GetType(key); diff --git a/tests/pkcs11mtt.c b/tests/pkcs11mtt.c index 3cd94908..4fd187fc 100644 --- a/tests/pkcs11mtt.c +++ b/tests/pkcs11mtt.c @@ -1821,7 +1821,7 @@ static CK_RV test_wrap_unwrap_key(void* args) ret = get_generic_key(session, wrappingKeyData, sizeof(wrappingKeyData), CK_FALSE, &wrappingKey); if (ret == CKR_OK) { - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + ret = get_generic_key(session, keyData, sizeof(keyData), CK_TRUE, &key); } if (ret == CKR_OK) { diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index 2e720aa5..af16fe4c 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -5760,7 +5760,7 @@ static CK_RV test_aes_wrap_unwrap_key(void* args) ret = get_aes_128_key(session, NULL, 0, &wrappingKey); if (ret == CKR_OK) { - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + ret = get_generic_key(session, keyData, sizeof(keyData), CK_TRUE, &key); } if (ret == CKR_OK) { @@ -5804,7 +5804,7 @@ static CK_RV test_aes_wrap_unwrap_pad_key(void* args) ret = get_aes_128_key(session, NULL, 0, &wrappingKey); if (ret == CKR_OK) { - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + ret = get_generic_key(session, keyData, sizeof(keyData), CK_TRUE, &key); } if (ret == CKR_OK) { @@ -5854,7 +5854,7 @@ static CK_RV test_wrap_unwrap_key(void* args) ret = get_generic_key(session, wrappingKeyData, sizeof(wrappingKeyData), CK_FALSE, &wrappingKey); if (ret == CKR_OK) { - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + ret = get_generic_key(session, keyData, sizeof(keyData), CK_TRUE, &key); } if (ret == CKR_OK) { @@ -5952,6 +5952,134 @@ static CK_RV test_wrap_unwrap_key(void* args) return ret; } + +/* Regression test: C_WrapKey on a key with CKA_EXTRACTABLE=CK_FALSE must + * return CKR_KEY_UNEXTRACTABLE (PKCS#11 spec 2.1.4). */ +static CK_RV test_wrap_key_unextractable(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_MECHANISM mech = { CKM_AES_KEY_WRAP, NULL, 0 }; + CK_OBJECT_HANDLE wrappingKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE key = CK_INVALID_HANDLE; + byte wrappedKey[40], keyData[16]; + CK_ULONG wrappedKeyLen = sizeof(wrappedKey); + //CK_BBOOL ckfalse = CK_FALSE; + CK_ATTRIBUTE wrapKeyTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &aesKeyType, sizeof(aesKeyType) }, + { CKA_VALUE, aes_128_key, sizeof(aes_128_key) }, + { CKA_WRAP, &ckTrue, sizeof(ckTrue) }, + }; + CK_ULONG wrapKeyTmplCnt = sizeof(wrapKeyTmpl) / sizeof(*wrapKeyTmpl); + CK_ATTRIBUTE nonExtractTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_EXTRACTABLE, &ckFalse, sizeof(CK_BBOOL) }, + }; + CK_ULONG nonExtractTmplCnt = sizeof(nonExtractTmpl) / + sizeof(*nonExtractTmpl); + + memset(keyData, 0x42, sizeof(keyData)); + + ret = funcList->C_CreateObject(session, wrapKeyTmpl, wrapKeyTmplCnt, + &wrappingKey); + CHECK_CKR(ret, "Create AES wrapping key for unextractable test"); + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, nonExtractTmpl, + nonExtractTmplCnt, &key); + CHECK_CKR(ret, "Create non-extractable key"); + } + if (ret == CKR_OK) { + ret = funcList->C_WrapKey(session, &mech, wrappingKey, key, + wrappedKey, &wrappedKeyLen); + CHECK_CKR_FAIL(ret, CKR_KEY_UNEXTRACTABLE, + "Wrap non-extractable key must return CKR_KEY_UNEXTRACTABLE"); + } + + funcList->C_DestroyObject(session, wrappingKey); + funcList->C_DestroyObject(session, key); + + return ret; +} + +/* Regression test: C_WrapKey on a key with CKA_WRAP_WITH_TRUSTED=CK_TRUE must + * return CKR_KEY_NOT_WRAPPABLE when the wrapping key lacks CKA_TRUSTED, and + * succeed when the wrapping key has CKA_TRUSTED=CK_TRUE. */ +static CK_RV test_wrap_key_wrap_with_trusted(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_MECHANISM mech = { CKM_AES_KEY_WRAP, NULL, 0 }; + CK_OBJECT_HANDLE untrustedKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE trustedKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE key = CK_INVALID_HANDLE; + byte wrappedKey[40], keyData[16]; + CK_ULONG wrappedKeyLen; + CK_BBOOL ckTrusted = CK_TRUE; + CK_ATTRIBUTE untrustedWrapTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &aesKeyType, sizeof(aesKeyType) }, + { CKA_VALUE, aes_128_key, sizeof(aes_128_key) }, + { CKA_WRAP, &ckTrue, sizeof(ckTrue) }, + }; + CK_ULONG untrustedWrapTmplCnt = sizeof(untrustedWrapTmpl) / + sizeof(*untrustedWrapTmpl); + CK_ATTRIBUTE trustedWrapTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &aesKeyType, sizeof(aesKeyType) }, + { CKA_VALUE, aes_128_key, sizeof(aes_128_key) }, + { CKA_WRAP, &ckTrue, sizeof(ckTrue) }, + { CKA_TRUSTED, &ckTrusted, sizeof(CK_BBOOL) }, + }; + CK_ULONG trustedWrapTmplCnt = sizeof(trustedWrapTmpl) / + sizeof(*trustedWrapTmpl); + CK_ATTRIBUTE wwtTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_WRAP_WITH_TRUSTED, &ckTrusted, sizeof(CK_BBOOL) }, + }; + CK_ULONG wwtTmplCnt = sizeof(wwtTmpl) / sizeof(*wwtTmpl); + + memset(keyData, 0x55, sizeof(keyData)); + + ret = funcList->C_CreateObject(session, untrustedWrapTmpl, + untrustedWrapTmplCnt, &untrustedKey); + CHECK_CKR(ret, "Create untrusted AES wrapping key"); + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, trustedWrapTmpl, + trustedWrapTmplCnt, &trustedKey); + CHECK_CKR(ret, "Create trusted AES wrapping key"); + } + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, wwtTmpl, wwtTmplCnt, &key); + CHECK_CKR(ret, "Create CKA_WRAP_WITH_TRUSTED key"); + } + /* Wrap with untrusted key must fail */ + if (ret == CKR_OK) { + wrappedKeyLen = sizeof(wrappedKey); + ret = funcList->C_WrapKey(session, &mech, untrustedKey, key, + wrappedKey, &wrappedKeyLen); + CHECK_CKR_FAIL(ret, CKR_KEY_NOT_WRAPPABLE, + "Wrap CKA_WRAP_WITH_TRUSTED key with untrusted wrapping key"); + } + /* Wrap with trusted key must succeed */ + if (ret == CKR_OK) { + wrappedKeyLen = sizeof(wrappedKey); + ret = funcList->C_WrapKey(session, &mech, trustedKey, key, + wrappedKey, &wrappedKeyLen); + CHECK_CKR(ret, "Wrap CKA_WRAP_WITH_TRUSTED key with trusted wrapping key"); + } + + funcList->C_DestroyObject(session, untrustedKey); + funcList->C_DestroyObject(session, trustedKey); + funcList->C_DestroyObject(session, key); + + return ret; +} #endif /* HAVE_AES_KEYWRAP && !WOLFPKCS11_NO_STORE */ #ifndef NO_DH @@ -6339,7 +6467,7 @@ static CK_RV test_rsa_wrap_unwrap_key(void* args) /* Create a secret key to wrap */ if (ret == CKR_OK) { - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + ret = get_generic_key(session, keyData, sizeof(keyData), CK_TRUE, &key); } @@ -6364,7 +6492,7 @@ static CK_RV test_rsa_wrap_unwrap_key(void* args) /* Test getting wrapped key length */ if (ret == CKR_OK) { - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + ret = get_generic_key(session, keyData, sizeof(keyData), CK_TRUE, &key); if (ret == CKR_OK) { CK_ULONG testLen = 0; @@ -6409,7 +6537,7 @@ static CK_RV test_rsa_wrap_unwrap_key(void* args) /* Test buffer too small error */ if (ret == CKR_OK) { /* Create fresh key for this test since original was destroyed */ - ret = get_generic_key(session, keyData, sizeof(keyData), CK_FALSE, + ret = get_generic_key(session, keyData, sizeof(keyData), CK_TRUE, &key); if (ret == CKR_OK) { CK_ULONG smallLen = 1; @@ -15822,6 +15950,8 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_aes_wrap_unwrap_key), PKCS11TEST_FUNC_SESS_DECL(test_aes_wrap_unwrap_pad_key), PKCS11TEST_FUNC_SESS_DECL(test_wrap_unwrap_key), + PKCS11TEST_FUNC_SESS_DECL(test_wrap_key_unextractable), + PKCS11TEST_FUNC_SESS_DECL(test_wrap_key_wrap_with_trusted), #endif /* HAVE_AES_KEYWRAP && !WOLFPKCS11_NO_STORE */ #if (!defined(NO_RSA) && !defined(WOLFPKCS11_NO_STORE)) PKCS11TEST_FUNC_SESS_DECL(test_rsa_wrap_unwrap_key),