diff --git a/src/crypto.c b/src/crypto.c index 35b7d0f1..c6ff2a32 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -54,12 +54,6 @@ #define PRF_KEY_SIZE 48 -/* Derive mechanisms that build their output into a secret key object. */ -#if defined(HAVE_ECC) || !defined(NO_DH) || defined(WOLFPKCS11_HKDF) || \ - (!defined(NO_AES) && defined(HAVE_AES_CBC)) || defined(WOLFSSL_HAVE_PRF) - #define WP11_DERIVE_SECRET_KEY -#endif - /* Check that a CK_ULONG value fits in word32 with room for overhead such as * authentication tags, key wrap blocks, or padding. On LP64 platforms CK_ULONG * is 64-bit but wolfCrypt functions use word32/int for lengths. */ @@ -580,6 +574,21 @@ static CK_RV CheckAttributes(CK_ATTRIBUTE* pTemplate, CK_ULONG ulCount, int set) return CKR_OK; } +static CK_RV UndecodedKeyRv(WP11_Slot* slot) +{ + /* A key still undecoded while logged in failed to verify. */ + if (WP11_Slot_IsUserLoggedIn(slot)) + return CKR_FUNCTION_FAILED; + return CKR_USER_NOT_LOGGED_IN; +} + +static CK_RV CheckKeyDecoded(WP11_Object* obj) +{ + if (WP11_Object_KeyState(obj) != 0) + return UndecodedKeyRv(WP11_Object_GetSlot(obj)); + return CKR_OK; +} + /* A certificate's type shares the key type field, so only key objects may be * used as keys. A data object may seed a derivation. */ static int CheckKeyObject(WP11_Object* obj, CK_ATTRIBUTE_TYPE op) @@ -609,7 +618,7 @@ static int CheckOpSupportedRv(WP11_Object* obj, CK_ATTRIBUTE_TYPE op, WOLFPKCS11_MSG("Operation not supported by object"); return (int)errRv; } - return CKR_OK; + return (int)CheckKeyDecoded(obj); } static int CheckOpSupported(WP11_Object* obj, CK_ATTRIBUTE_TYPE op) @@ -641,7 +650,6 @@ static CK_RV SetInitialStates(WP11_Object* key) return rv; } -#ifdef WP11_DERIVE_SECRET_KEY /* PKCS#11 derive rules: the historical flags also need the base key's. */ static CK_RV SetDerivedStates(WP11_Object* key, CK_BBOOL baseAlwaysSensitive, CK_BBOOL baseNeverExtractable) @@ -670,7 +678,6 @@ static CK_RV SetDerivedStates(WP11_Object* key, CK_BBOOL baseAlwaysSensitive, } return rv; } -#endif static CK_RV TemplateHasAttribute(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) @@ -1345,12 +1352,8 @@ static CK_RV SetAttributeValue(WP11_Session* session, WP11_Object* obj, return CKR_ATTRIBUTE_VALUE_INVALID; else if (ret == BUFFER_E) return CKR_BUFFER_TOO_SMALL; - else if (ret == BAD_STATE_E) { - /* Logged in yet undecoded: the stored key failed to verify. */ - if (WP11_Slot_IsUserLoggedIn(WP11_Session_GetSlot(session))) - return CKR_FUNCTION_FAILED; - return CKR_USER_NOT_LOGGED_IN; - } + else if (ret == BAD_STATE_E) + return UndecodedKeyRv(WP11_Session_GetSlot(session)); else if (ret != 0) return CKR_FUNCTION_FAILED; } @@ -2119,6 +2122,11 @@ static CK_RV wp11_C_CopyObject(CK_SESSION_HANDLE hSession, WOLFPKCS11_LEAVE("C_CopyObject", rv); return rv; } + rv = CheckKeyDecoded(obj); + if (rv != CKR_OK) { + WOLFPKCS11_LEAVE("C_CopyObject", rv); + return rv; + } /* Creating a private object requires an authenticated user session. The * copy template can set CKA_PRIVATE=CK_TRUE, so gate it like @@ -5529,6 +5537,10 @@ static CK_RV wp11_C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) ret = WP11_Digest_Key(obj, session); + if (ret == BAD_STATE_E) { + WP11_Session_AbortOp(session); + return UndecodedKeyRv(WP11_Session_GetSlot(session)); + } if (ret < 0) { WP11_Session_AbortOp(session); return CKR_FUNCTION_FAILED; @@ -9648,6 +9660,9 @@ static CK_RV wp11_C_WrapKey(CK_SESSION_HANDLE hSession, if (rv != CKR_OK) { return rv; } + rv = CheckKeyDecoded(key); + if (rv != CKR_OK) + return rv; switch (keyType) { #if !defined(NO_RSA) && !defined(WOLFPKCS11_NO_STORE) @@ -10149,7 +10164,6 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, return rv; } -#ifdef WP11_DERIVE_SECRET_KEY /** * Determine the key length of the object. * @@ -10199,7 +10213,6 @@ static int SymmKeyLen(WP11_Object* obj, word32 len, CK_ULONG* symmKeyLen) return ret; } -#endif #ifdef WOLFSSL_HAVE_PRF static int SetKeyExtract(WP11_Session* session, byte* ptr, CK_ULONG length, @@ -10352,6 +10365,36 @@ static int Tls12_Extract_Keys(WP11_Session* session, } #endif +static CK_RV ConcatKeyRv(WP11_Session* session, int ret) +{ + if (ret == 0) + return CKR_OK; + if (ret == BAD_STATE_E) + return UndecodedKeyRv(WP11_Session_GetSlot(session)); + if (ret == NOT_AVAILABLE_E) + return CKR_KEY_FUNCTION_NOT_PERMITTED; + return CKR_FUNCTION_FAILED; +} + +/* A result that ends inside a protected key lets each of its bytes be found + * by brute force, so it must hold all or none of such a key. */ +static int ConcatCutsProtectedKey(WP11_Object* key, CK_ULONG off, + CK_ULONG len, CK_ULONG reqLen) +{ + CK_BBOOL sensitive = CK_TRUE; + CK_BBOOL extractable = CK_FALSE; + CK_ULONG bLen = sizeof(CK_BBOOL); + + if (reqLen <= off || reqLen >= off + len) + return 0; + if (WP11_Object_GetAttr(key, CKA_SENSITIVE, &sensitive, &bLen) != 0) + sensitive = CK_TRUE; + bLen = sizeof(CK_BBOOL); + if (WP11_Object_GetAttr(key, CKA_EXTRACTABLE, &extractable, &bLen) != 0) + extractable = CK_FALSE; + return sensitive == CK_TRUE || extractable == CK_FALSE; +} + /** * Generate a symmetric key into a new key object. * @@ -10373,6 +10416,14 @@ static int Tls12_Extract_Keys(WP11_Session* session, * CKR_FUNCTION_FAILED when setting an attribute fails. * CKR_MECHANISM_INVALID when the mechanism is not supported with this * type of operation. + * CKR_KEY_HANDLE_INVALID when the other key handle is not valid. + * CKR_KEY_TYPE_INCONSISTENT when a concatenated key is not a secret + * key. + * CKR_KEY_FUNCTION_NOT_PERMITTED when a key may not be derived from. + * CKR_KEY_SIZE_RANGE when the derived key is too long. + * CKR_TEMPLATE_INCOMPLETE when an AES key has no CKA_VALUE_LEN and + * is concatenated, or the derived length is not an AES key size. + * CKR_USER_NOT_LOGGED_IN when a token key value is not decoded. * CKR_OK on success. */ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, @@ -10386,25 +10437,31 @@ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, CK_RV rv = CKR_OK; WP11_Session* session; WP11_Object* obj = NULL; -#ifdef WP11_DERIVE_SECRET_KEY + WP11_Object* otherKey = NULL; byte* derivedKey = NULL; word32 keyLen; CK_ULONG symmKeyLen; unsigned char* secretKeyData[2] = { NULL, NULL }; CK_ULONG secretKeyLen[2] = { 0, 0 }; -#ifndef WOLFPKCS11_LEGACY_DERIVE_NO_INHERIT /* F-4533: protection attributes inherited from the base key. */ CK_BBOOL baseSensitive = CK_FALSE; CK_BBOOL baseExtractable = CK_TRUE; CK_ULONG bLen; +#ifdef WOLFPKCS11_LEGACY_DERIVE_NO_INHERIT + int inherit = 0; +#else + int inherit = 1; #endif -#endif -#ifdef WP11_DERIVE_SECRET_KEY + int dataOnly = 0; + CK_BBOOL wrapTrusted = CK_FALSE; CK_BBOOL baseAlwaysSensitive = CK_FALSE; CK_BBOOL baseNeverExtractable = CK_FALSE; + CK_BBOOL otherState; CK_ULONG histLen; CK_ATTRIBUTE* valueLenAttr = NULL; CK_ULONG reqValueLen = 0; +#if !defined(NO_AES) && !defined(WOLFPKCS11_NSS) + CK_ATTRIBUTE* keyTypeAttr = NULL; #endif #ifndef NO_DH CK_ULONG dhPrimeLen = 0; @@ -10470,6 +10527,8 @@ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, ret = CheckOpSupported(obj, CKA_DERIVE); #else ret = CheckKeyObject(obj, CKA_DERIVE); + if (ret == CKR_OK) + ret = (int)CheckKeyDecoded(obj); #endif if (ret != CKR_OK) return ret; @@ -10524,6 +10583,7 @@ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, case CKM_HKDF_DATA: { CK_HKDF_PARAMS_PTR kdfParams; CK_ATTRIBUTE *lenAttr = NULL; + WP11_Object* saltObj = NULL; /* Data-derive feeds a CKO_DATA object, which has no key type. * Only a key base object is checked for an HKDF-compatible type. */ @@ -10545,6 +10605,15 @@ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, if (kdfParams->bExpand && !CK_ULONG_FITS_WORD32(kdfParams->ulInfoLen)) return CKR_MECHANISM_PARAM_INVALID; + if (kdfParams->bExtract && + kdfParams->ulSaltType == CKF_HKDF_SALT_KEY && + WP11_Object_Find(session, kdfParams->hSaltKey, + &saltObj) == 0 && + WP11_Object_GetClass(saltObj) == CKO_SECRET_KEY) { + rv = CheckKeyDecoded(saltObj); + if (rv != CKR_OK) + return rv; + } FindAttributeType(pTemplate, ulAttributeCount, CKA_VALUE_LEN, &lenAttr); @@ -10804,24 +10873,143 @@ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, } #endif #endif + case CKM_CONCATENATE_BASE_AND_KEY: + case CKM_CONCATENATE_BASE_AND_DATA: + case CKM_CONCATENATE_DATA_AND_BASE: { + CK_KEY_DERIVATION_STRING_DATA* strData = NULL; + CK_ATTRIBUTE* lenAttr = NULL; + CK_ATTRIBUTE* typeAttr = NULL; + CK_ULONG baseLen = 0; + CK_ULONG addLen = 0; + CK_ULONG totalLen; + CK_ULONG reqLen; + word32 keySz; + + if (WP11_Object_GetClass(obj) != CKO_SECRET_KEY || + !WP11_KeyType_IsSecret(WP11_Object_GetType(obj))) + return CKR_KEY_TYPE_INCONSISTENT; + if (pMechanism->pParameter == NULL) + return CKR_MECHANISM_PARAM_INVALID; + if (pMechanism->mechanism == CKM_CONCATENATE_BASE_AND_KEY) { + if (pMechanism->ulParameterLen != sizeof(CK_OBJECT_HANDLE)) + return CKR_MECHANISM_PARAM_INVALID; + if (WP11_Object_Find(session, + *(CK_OBJECT_HANDLE*)pMechanism->pParameter, + &otherKey) != 0) + return CKR_KEY_HANDLE_INVALID; + if (WP11_Object_GetClass(otherKey) != CKO_SECRET_KEY || + !WP11_KeyType_IsSecret(WP11_Object_GetType(otherKey))) + return CKR_KEY_TYPE_INCONSISTENT; +#ifndef WP11_NSS_PERMISSIVE_KEY_DEFAULTS + ret = CheckOpSupported(otherKey, CKA_DERIVE); + if (ret != CKR_OK) + return ret; +#endif + ret = WP11_Concat_KeyLen(otherKey, &keySz); + if (ret != 0) + return ConcatKeyRv(session, ret); + addLen = keySz; + } + else { + if (pMechanism->ulParameterLen != + sizeof(CK_KEY_DERIVATION_STRING_DATA)) + return CKR_MECHANISM_PARAM_INVALID; + strData = (CK_KEY_DERIVATION_STRING_DATA*) + pMechanism->pParameter; + if (strData->pData == NULL && strData->ulLen > 0) + return CKR_MECHANISM_PARAM_INVALID; + if (strData->ulLen > + (CK_ULONG)WOLFSSL_MAX_32BIT - WP11_MAX_SYM_KEY_SZ) + return CKR_KEY_SIZE_RANGE; + addLen = strData->ulLen; + } + ret = WP11_Concat_KeyLen(obj, &keySz); + if (ret != 0) + return ConcatKeyRv(session, ret); + baseLen = keySz; + totalLen = baseLen + addLen; + reqLen = totalLen; + + FindAttributeType(pTemplate, ulAttributeCount, CKA_VALUE_LEN, + &lenAttr); + if (lenAttr != NULL) { + if (lenAttr->pValue == NULL || + lenAttr->ulValueLen != sizeof(CK_ULONG)) + return CKR_ATTRIBUTE_VALUE_INVALID; + XMEMCPY(&reqLen, lenAttr->pValue, sizeof(CK_ULONG)); + if (reqLen == 0 || reqLen > totalLen) + return CKR_ATTRIBUTE_VALUE_INVALID; + if (ConcatCutsProtectedKey(obj, (pMechanism->mechanism == + CKM_CONCATENATE_DATA_AND_BASE) ? addLen : 0, baseLen, + reqLen) || (otherKey != NULL && + ConcatCutsProtectedKey(otherKey, baseLen, addLen, + reqLen))) + return CKR_ATTRIBUTE_VALUE_INVALID; + } + else { + FindAttributeType(pTemplate, ulAttributeCount, CKA_KEY_TYPE, + &typeAttr); + if (typeAttr != NULL && + *(CK_KEY_TYPE*)typeAttr->pValue == CKK_AES) + return CKR_TEMPLATE_INCOMPLETE; + } + if (reqLen == 0 || reqLen > WP11_MAX_SYM_KEY_SZ) + return CKR_KEY_SIZE_RANGE; + inherit = 1; + dataOnly = pMechanism->mechanism == CKM_CONCATENATE_DATA_AND_BASE && + reqLen <= addLen; + bLen = sizeof(CK_BBOOL); + if (WP11_Object_GetAttr(obj, CKA_WRAP_WITH_TRUSTED, &wrapTrusted, + &bLen) != 0) + wrapTrusted = CK_FALSE; + bLen = sizeof(CK_BBOOL); + if (otherKey != NULL && WP11_Object_GetAttr(otherKey, + CKA_WRAP_WITH_TRUSTED, &otherState, &bLen) == 0 && + otherState == CK_TRUE) + wrapTrusted = CK_TRUE; + + keyLen = (word32)reqLen; + derivedKey = (byte*)XMALLOC(keyLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (derivedKey == NULL) + return CKR_DEVICE_MEMORY; + XMEMSET(derivedKey, 0, keyLen); + + ret = WP11_Concat_Derive(obj, otherKey, + (strData != NULL) ? strData->pData : NULL, + (strData != NULL) ? (word32)strData->ulLen : 0, + pMechanism->mechanism == CKM_CONCATENATE_DATA_AND_BASE, + derivedKey, keyLen); + rv = ConcatKeyRv(session, ret); + break; + } default: (void)ulAttributeCount; return CKR_MECHANISM_INVALID; } -#ifdef WP11_DERIVE_SECRET_KEY if ((ret == 0) && (derivedKey != NULL)) { -#ifndef WOLFPKCS11_LEGACY_DERIVE_NO_INHERIT /* F-4533: read the base key's protection bits while `obj' still * refers to it, before CreateObject reuses `obj' for the new key. */ - bLen = sizeof(CK_BBOOL); - if (WP11_Object_GetAttr(obj, CKA_SENSITIVE, &baseSensitive, &bLen) != 0) - baseSensitive = CK_FALSE; - bLen = sizeof(CK_BBOOL); - if (WP11_Object_GetAttr(obj, CKA_EXTRACTABLE, &baseExtractable, - &bLen) != 0) - baseExtractable = CK_TRUE; -#endif + if (inherit) { + bLen = sizeof(CK_BBOOL); + if (WP11_Object_GetAttr(obj, CKA_SENSITIVE, &baseSensitive, + &bLen) != 0) + baseSensitive = CK_FALSE; + bLen = sizeof(CK_BBOOL); + if (WP11_Object_GetAttr(obj, CKA_EXTRACTABLE, &baseExtractable, + &bLen) != 0) + baseExtractable = CK_TRUE; + bLen = sizeof(CK_BBOOL); + if (otherKey != NULL && WP11_Object_GetAttr(otherKey, + CKA_SENSITIVE, &otherState, &bLen) == 0 && + otherState == CK_TRUE) + baseSensitive = CK_TRUE; + bLen = sizeof(CK_BBOOL); + if (otherKey != NULL && WP11_Object_GetAttr(otherKey, + CKA_EXTRACTABLE, &otherState, &bLen) == 0 && + otherState == CK_FALSE) + baseExtractable = CK_FALSE; + } histLen = sizeof(CK_BBOOL); if (WP11_Object_GetAttr(obj, CKA_ALWAYS_SENSITIVE, &baseAlwaysSensitive, &histLen) != 0) @@ -10830,6 +11018,22 @@ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, if (WP11_Object_GetAttr(obj, CKA_NEVER_EXTRACTABLE, &baseNeverExtractable, &histLen) != 0) baseNeverExtractable = CK_FALSE; + if (otherKey != NULL) { + histLen = sizeof(CK_BBOOL); + if (WP11_Object_GetAttr(otherKey, CKA_ALWAYS_SENSITIVE, + &otherState, &histLen) != 0 || + otherState != CK_TRUE) + baseAlwaysSensitive = CK_FALSE; + histLen = sizeof(CK_BBOOL); + if (WP11_Object_GetAttr(otherKey, CKA_NEVER_EXTRACTABLE, + &otherState, &histLen) != 0 || + otherState != CK_TRUE) + baseNeverExtractable = CK_FALSE; + } + if (dataOnly) { + baseAlwaysSensitive = CK_FALSE; + baseNeverExtractable = CK_FALSE; + } FindAttributeType(pTemplate, ulAttributeCount, CKA_VALUE_LEN, &valueLenAttr); if ((valueLenAttr != NULL) && (valueLenAttr->pValue != NULL) && @@ -10848,13 +11052,24 @@ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, #endif if (reqValueLen > keyLen) rv = CKR_ATTRIBUTE_VALUE_INVALID; +#if !defined(NO_AES) && !defined(WOLFPKCS11_NSS) + if (rv == CKR_OK && valueLenAttr == NULL) { + FindAttributeType(pTemplate, ulAttributeCount, CKA_KEY_TYPE, + &keyTypeAttr); + if (keyTypeAttr != NULL && + *(CK_KEY_TYPE*)keyTypeAttr->pValue == CKK_AES && + keyLen != AES_128_KEY_SIZE && keyLen != AES_192_KEY_SIZE && + keyLen != AES_256_KEY_SIZE) { + rv = CKR_TEMPLATE_INCOMPLETE; + } + } +#endif if (rv == CKR_OK) { rv = CreateObject(session, pTemplate, ulAttributeCount, CKO_SECRET_KEY, &obj); } if (rv == CKR_OK) { /* obj now refers to the newly created derived key. */ -#ifndef WOLFPKCS11_LEGACY_DERIVE_NO_INHERIT /* F-4533: PKCS#11 v3.0 5.5.5 - a derived key must be at least as * protected as its base key. Force the inherited attributes after * the caller template has been applied so a weaker template @@ -10871,9 +11086,14 @@ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, sizeof(bbFalse)) != 0) rv = CKR_FUNCTION_FAILED; } + if (rv == CKR_OK && wrapTrusted == CK_TRUE) { + CK_BBOOL bbTrue = CK_TRUE; + if (WP11_Object_SetAttr(obj, CKA_WRAP_WITH_TRUSTED, &bbTrue, + sizeof(bbTrue)) != 0) + rv = CKR_FUNCTION_FAILED; + } if (rv != CKR_OK) WP11_Object_Free(obj); -#endif } if (rv == CKR_OK) { ret = SymmKeyLen(obj, keyLen, &symmKeyLen); @@ -10912,7 +11132,6 @@ static CK_RV wp11_C_DeriveKey(CK_SESSION_HANDLE hSession, wc_ForceZero(derivedKey, keyLen); XFREE(derivedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); } -#endif return rv; } diff --git a/src/internal.c b/src/internal.c index 8efcee80..57715039 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7795,37 +7795,50 @@ static int XmssObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, #endif /* WOLFPKCS11_XMSS */ /** - * Decode the symmetric key - requires decryption. + * Get the length of the secret in a stored symmetric key record. * - * @param [in, out] object Symmetric key object. + * @param [in] object Symmetric key object. + * @param [out] len Length of the secret in bytes. * @return 0 on success. - * @return -ve on failure. + * @return BAD_FUNC_ARG when the record is shorter than the tag. + * @return BUFFER_E when the secret does not fit the key buffer. */ -static int wp11_Object_Decode_SymmKey(WP11_Object* object) +static int wp11_Object_SymmKeyLen(WP11_Object* object, word32* len) { - int ret = 0; - /* keyDataLen is signed and covers the encrypted payload plus the trailing * AES_BLOCK_SIZE tag. Reject lengths below the tag so the payload length * below cannot go negative when used as an unsigned length. A length of * exactly AES_BLOCK_SIZE is a valid zero-byte secret: the encoder writes * symmKey->len + AES_BLOCK_SIZE, so a zero-length key must still load. */ if (object->keyDataLen < AES_BLOCK_SIZE) - ret = BAD_FUNC_ARG; - if (ret == 0 && - (word32)(object->keyDataLen - AES_BLOCK_SIZE) > WP11_MAX_SYM_KEY_SZ) - ret = BUFFER_E; + return BAD_FUNC_ARG; + if ((word32)(object->keyDataLen - AES_BLOCK_SIZE) > WP11_MAX_SYM_KEY_SZ) + return BUFFER_E; + *len = (word32)(object->keyDataLen - AES_BLOCK_SIZE); + return 0; +} + +/** + * Decode the symmetric key - requires decryption. + * + * @param [in, out] object Symmetric key object. + * @return 0 on success. + * @return -ve on failure. + */ +static int wp11_Object_Decode_SymmKey(WP11_Object* object) +{ + int ret; + word32 len = 0; + + ret = wp11_Object_SymmKeyLen(object, &len); if (ret == 0) { ret = wp11_Object_DecryptKeyData(object, object->data.symmKey->data, - object->keyData, - object->keyDataLen - AES_BLOCK_SIZE); - if (ret != 0) { - wc_ForceZero(object->data.symmKey->data, - (word32)(object->keyDataLen - AES_BLOCK_SIZE)); - } + object->keyData, (int)len); + if (ret != 0) + wc_ForceZero(object->data.symmKey->data, len); } if (ret == 0) - object->data.symmKey->len = object->keyDataLen - AES_BLOCK_SIZE; + object->data.symmKey->len = len; object->encoded = (ret != 0); return ret; @@ -7876,6 +7889,7 @@ static int wp11_Object_Load_SymmKey(WP11_Object* object, int tokenId, int objId) { int ret; void* storage = NULL; + word32 len = 0; /* Open access to symmetric key. */ ret = wp11_storage_open_readonly(WOLFPKCS11_STORE_SYMMKEY, tokenId, objId, @@ -7886,6 +7900,9 @@ static int wp11_Object_Load_SymmKey(WP11_Object* object, int tokenId, int objId) &object->keyDataLen); wp11_storage_close(storage); } + /* CKA_VALUE_LEN is readable before the key is decoded. */ + if (ret == 0 && wp11_Object_SymmKeyLen(object, &len) == 0) + object->data.symmKey->len = len; return ret; } @@ -9359,6 +9376,10 @@ static int wp11_Token_Load(WP11_Slot* slot, int tokenId, WP11_Token* token) for (i = token->objCnt - 1; (ret == 0) && (i >= 0); i--) { /* Load the objects. */ ret = wp11_Object_Load(object, tokenId, i); + /* Objects not under the token key are usable before any login. */ + if (ret == 0 && !wp11_Object_IsEncrypted(object) && + wp11_Object_Decode(object) != 0) + object->undecoded = 1; /* Keep new token object ids above the stored ones, in case the * counter was not stored or was not usable. */ if (ret == 0 && (int)OBJ_HANDLE_OBJ_ID(object->handle) >= @@ -9381,7 +9402,8 @@ static int wp11_Token_Load(WP11_Slot* slot, int tokenId, WP11_Token* token) token->key, sizeof(token->key), slot); object = token->object; while (ret == 0 && object != NULL) { - ret = wp11_Object_Decode(object); + if (wp11_Object_IsEncrypted(object) || object->undecoded) + ret = wp11_Object_Decode(object); object = object->next; } #endif @@ -10215,6 +10237,9 @@ int WP11_Slot_OpenSession(WP11_Slot* slot, unsigned long flags, void* app, } static void wp11_Slot_Logout(WP11_Slot* slot); +#ifndef WOLFPKCS11_NO_STORE +static void wp11_Slot_ClearKeyOps(WP11_Slot* slot, WP11_Object* object); +#endif /** * Close a session associated with a slot. @@ -11166,7 +11191,8 @@ int WP11_Slot_UserLogin(WP11_Slot* slot, char* pin, int pinLen) XMEMCPY(token->key, d->key, sizeof(token->key)); object = token->object; while (ret == 0 && object != NULL) { - ret = wp11_Object_Decode(object); + if (wp11_Object_IsEncrypted(object) || object->undecoded) + ret = wp11_Object_Decode(object); if (ret != 0) failed = object; object = object->next; @@ -11694,6 +11720,11 @@ static void wp11_Slot_Logout(WP11_Slot* slot) /* Zero token key only on user logout — SO logout must preserve it * for subsequent object encryption (e.g., empty-PIN flow). */ wc_ForceZero(slot->token.key, sizeof(slot->token.key)); + for (object = slot->token.object; object != NULL; + object = object->next) { + if (object->encoded) + wp11_Slot_ClearKeyOps(slot, object); + } } #endif #ifndef WOLFPKCS11_NSS @@ -12065,7 +12096,11 @@ static int wp11_init_get_op_category(int init) static int wp11_mech_reads_key(CK_MECHANISM_TYPE mechanism) { return mechanism == CKM_AES_GCM || mechanism == CKM_AES_CCM || - mechanism == CKM_AES_ECB; + mechanism == CKM_AES_ECB || mechanism == CKM_TLS_MAC +#ifdef WOLFPKCS11_NSS + || mechanism == CKM_NSS_TLS_PRF_GENERAL_SHA256 +#endif + ; } /** @@ -12088,9 +12123,34 @@ int WP11_Session_IsOpCategoryInit(WP11_Session* session, int opCategory) return wp11_init_get_op_category(currentInit) == opCategory; } +/** + * Release the operation state of a session whose key was dropped by a destroy + * or a logout. + * + * @param session [in] Session object. + * @return Current object of the session, NULL when there is none. + */ +static WP11_Object* wp11_Session_ReleaseStaleOp(WP11_Session* session) +{ + WP11_Object* curr; + int op; + int abortOp; + + WP11_Lock_LockRO(&session->slot->lock); + curr = session->curr; + op = session->init & ~WP11_INIT_DIGEST_MASK; + abortOp = (curr == NULL && op != 0 && op != WP11_INIT_DIGEST); + WP11_Lock_UnlockRO(&session->slot->lock); + if (abortOp) + WP11_Session_AbortOp(session); + + return curr; +} + /** * Check whether the session has an active operation of the given category. * Per PKCS#11 spec, only operations of the same type block re-initialization. + * An operation whose key was dropped is released first, whatever its category. * * @param session [in] Session object. * @param opCategory [in] Operation category (WP11_OP_*). @@ -12099,10 +12159,7 @@ int WP11_Session_IsOpCategoryInit(WP11_Session* session, int opCategory) */ int WP11_Session_IsOpCategoryActive(WP11_Session* session, int opCategory) { - /* The key of this operation was destroyed so it can no longer run. */ - if (session->curr == NULL && wp11_mech_reads_key(session->mechanism)) - return 0; - + (void)wp11_Session_ReleaseStaleOp(session); return WP11_Session_IsOpCategoryInit(session, opCategory); } @@ -13475,24 +13532,40 @@ WP11_API int WP11_Test_SetObjectClass(CK_SESSION_HANDLE hSession, #endif /* DEBUG_WOLFPKCS11 */ /** - * Drop any session reference to an object that is about to be freed. - * - * The active object pointer (session->curr) is a raw pointer cached when an - * operation is initialized. A token object can be the active object of more - * than one session. Since this reaches into other sessions, session->curr is - * only accessed under the slot lock (see WP11_Session_GetObject()). + * Drop the session's reference to its operation key unless the operation + * copied the key at init. Caller holds the slot lock for writing. * - * Symmetric operations (AES, HMAC/generic-secret, HKDF) copy the key into the - * operation context during their *Init and run to completion without referring - * to the object again, so a caller may legitimately destroy the key before - * finishing the operation (wolfCrypt's PKCS#11 layer does exactly this for - * multi-part HMAC). Those operations are left untouched. AES-GCM, AES-CCM and - * AES-ECB read the key object when data is processed, so only their reference - * is dropped; the owning session releases the operation state itself. + * @param session [in] Session whose operation uses the key. + * @param symmetric [in] Whether the key is a secret key. + */ +static void wp11_Session_ClearActive(WP11_Session* session, int symmetric) +{ + if (!symmetric || wp11_mech_reads_key(session->mechanism)) + session->curr = NULL; +} + +#ifndef WOLFPKCS11_NO_STORE +/** + * Clear the running operations that use a key whose value logout scrubbed. + * Caller holds the slot lock for writing. * - * Asymmetric operations dereference the key object while running, so for those - * key types drop the active reference in every session that holds it and reset - * the operation state, ensuring a later step cannot use freed memory. + * @param slot [in] Slot whose sessions are scanned. + * @param object [in] Token object that is now encoded. + */ +static void wp11_Slot_ClearKeyOps(WP11_Slot* slot, WP11_Object* object) +{ + WP11_Session* sess; + int symmetric = WP11_KeyType_IsSecret(object->type); + + for (sess = slot->session; sess != NULL; sess = sess->next) { + if (sess->curr == object) + wp11_Session_ClearActive(sess, symmetric); + } +} +#endif + +/** + * Drop any session reference to an object that is about to be freed. * * @param slot [in] Slot whose sessions are scanned. * @param object [in] Object being destroyed. @@ -13500,37 +13573,17 @@ WP11_API int WP11_Test_SetObjectClass(CK_SESSION_HANDLE hSession, void WP11_Slot_ClearActiveObject(WP11_Slot* slot, WP11_Object* object) { WP11_Session* curr; - CK_KEY_TYPE keyType; int symmetric; if (slot == NULL || object == NULL) return; - keyType = WP11_Object_GetType(object); - symmetric = WP11_KeyType_IsSecret(keyType); + symmetric = WP11_KeyType_IsSecret(WP11_Object_GetType(object)); WP11_Lock_LockRW(&slot->lock); for (curr = slot->session; curr != NULL; curr = curr->next) { - if (curr->curr == object && symmetric) { - if (wp11_mech_reads_key(curr->mechanism)) - curr->curr = NULL; - } - else if (curr->curr == object) { -#if !defined(NO_RSA) && !defined(WC_NO_RSA_OAEP) - /* Release the operation-owned RSA-OAEP label before dropping the - * operation state. Otherwise a later init for a different mechanism - * overwrites the params union and the label can no longer be - * freed. */ - if (curr->mechanism == CKM_RSA_PKCS_OAEP && - curr->params.oaep.label != NULL) { - XFREE(curr->params.oaep.label, NULL, DYNAMIC_TYPE_TMP_BUFFER); - curr->params.oaep.label = NULL; - curr->params.oaep.labelSz = 0; - } -#endif - curr->curr = NULL; - curr->init = 0; - } + if (curr->curr == object) + wp11_Session_ClearActive(curr, symmetric); } WP11_Lock_UnlockRW(&slot->lock); } @@ -13546,18 +13599,7 @@ void WP11_Slot_ClearActiveObject(WP11_Slot* slot, WP11_Object* object) */ void WP11_Session_GetObject(WP11_Session* session, WP11_Object** object) { - WP11_Object* curr; - int abortOp; - - WP11_Lock_LockRO(&session->slot->lock); - curr = session->curr; - /* The key was destroyed: release the state its operation still holds. */ - abortOp = (curr == NULL && wp11_mech_reads_key(session->mechanism) && - (session->init & ~WP11_INIT_DIGEST_MASK) != 0); - WP11_Lock_UnlockRO(&session->slot->lock); - if (abortOp) - WP11_Session_AbortOp(session); - *object = curr; + *object = wp11_Session_ReleaseStaleOp(session); } /** @@ -14064,6 +14106,49 @@ CK_KEY_TYPE WP11_Object_GetType(WP11_Object* object) return object->type; } +/** + * Get the slot the object belongs to. + * + * @param object [in] Object object. + * @return Slot of the object. + */ +WP11_Slot* WP11_Object_GetSlot(WP11_Object* object) +{ + return object->slot; +} + +/* Call with the object lock held when the object is on the token. */ +static int wp11_Object_KeyStateLocked(WP11_Object* object) +{ +#ifndef WOLFPKCS11_NO_STORE + if (object->encoded || object->undecoded) + return BAD_STATE_E; +#else + (void)object; +#endif + return 0; +} + +/** + * Check that the key value of an object is decoded and can be used. + * + * @param object [in] Object object. + * @return BAD_STATE_E when the key value is not decoded. + * 0 otherwise. + */ +int WP11_Object_KeyState(WP11_Object* object) +{ + int ret; + + if (object->onToken) + WP11_Lock_LockRO(object->lock); + ret = wp11_Object_KeyStateLocked(object); + if (object->onToken) + WP11_Lock_UnlockRO(object->lock); + + return ret; +} + /** * Get the object's devId. * @@ -15399,13 +15484,19 @@ static int RsaObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, int ret = 0; int noPriv = (((object->opFlag & WP11_FLAG_SENSITIVE) != 0) || ((object->opFlag & WP11_FLAG_EXTRACTABLE) == 0)); + int noKey = (wp11_Object_KeyStateLocked(object) != 0); if (mp_iszero(&object->data.rsaKey->d)) noPriv = 1; switch (type) { case CKA_MODULUS: - ret = GetMPIData(&object->data.rsaKey->n, data, len); + if (noKey) { + *len = CK_UNAVAILABLE_INFORMATION; + ret = CKR_ATTRIBUTE_SENSITIVE; + } + else + ret = GetMPIData(&object->data.rsaKey->n, data, len); break; case CKA_PRIVATE_EXPONENT: if (noPriv) { @@ -15456,10 +15547,21 @@ static int RsaObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, ret = GetMPIData(&object->data.rsaKey->u, data, len); break; case CKA_PUBLIC_EXPONENT: - ret = GetMPIData(&object->data.rsaKey->e, data, len); + if (noKey) { + *len = CK_UNAVAILABLE_INFORMATION; + ret = CKR_ATTRIBUTE_SENSITIVE; + } + else + ret = GetMPIData(&object->data.rsaKey->e, data, len); break; case CKA_MODULUS_BITS: - ret = GetULong(mp_count_bits(&object->data.rsaKey->n), data, len); + if (noKey) { + *len = CK_UNAVAILABLE_INFORMATION; + ret = CKR_ATTRIBUTE_SENSITIVE; + } + else + ret = GetULong(mp_count_bits(&object->data.rsaKey->n), data, + len); break; case CKA_WRAP_TEMPLATE: case CKA_UNWRAP_TEMPLATE: @@ -15587,6 +15689,7 @@ static int EcObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, int noPriv = (((object->opFlag & WP11_FLAG_SENSITIVE) != 0) || ((object->opFlag & WP11_FLAG_EXTRACTABLE) == 0)); int noPub = 0; + int noKey = (wp11_Object_KeyStateLocked(object) != 0); if (object->data.ecKey->type == ECC_PUBLICKEY) noPriv = 1; @@ -15595,10 +15698,15 @@ static int EcObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, switch (type) { case CKA_EC_PARAMS: - ret = GetEcParams(object->data.ecKey, data, len); + if (noKey) { + *len = CK_UNAVAILABLE_INFORMATION; + ret = CKR_ATTRIBUTE_SENSITIVE; + } + else + ret = GetEcParams(object->data.ecKey, data, len); break; case CKA_VALUE: - if (noPriv) { + if (noPriv || noKey) { *len = CK_UNAVAILABLE_INFORMATION; ret = CKR_ATTRIBUTE_SENSITIVE; } @@ -15614,6 +15722,10 @@ static int EcObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, *len = CK_UNAVAILABLE_INFORMATION; ret = NOT_AVAILABLE_E; } + else if (noKey) { + *len = CK_UNAVAILABLE_INFORMATION; + ret = CKR_ATTRIBUTE_SENSITIVE; + } else ret = GetEcPoint(object->data.ecKey, data, len); break; @@ -15747,6 +15859,7 @@ static int MldsaObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, int noPriv = (((object->opFlag & WP11_FLAG_SENSITIVE) != 0) || ((object->opFlag & WP11_FLAG_EXTRACTABLE) == 0)); int noPub = 0; + int noKey = (wp11_Object_KeyStateLocked(object) != 0); if (!object->data.mldsaKey->prvKeySet) noPriv = 1; @@ -15755,7 +15868,12 @@ static int MldsaObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, switch (type) { case CKA_PARAMETER_SET: - ret = GetMldsaParams(object->data.mldsaKey, data, len); + if (noKey) { + *len = CK_UNAVAILABLE_INFORMATION; + ret = CKR_ATTRIBUTE_SENSITIVE; + } + else + ret = GetMldsaParams(object->data.mldsaKey, data, len); break; case CKA_SEED: *len = CK_UNAVAILABLE_INFORMATION; @@ -15763,7 +15881,7 @@ static int MldsaObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, break; case CKA_VALUE: if (object->objClass == CKO_PRIVATE_KEY) { - if (noPriv) { + if (noPriv || noKey) { *len = CK_UNAVAILABLE_INFORMATION; ret = CKR_ATTRIBUTE_SENSITIVE; } @@ -15819,7 +15937,8 @@ static int DhObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, /* Public key held in key when object class is CKO_PUBLIC_KEY and * private key when object class is CKO_PRIVATE_KEY. */ - if (object->objClass != CKO_PRIVATE_KEY || !noPriv) { + if (object->objClass != CKO_PRIVATE_KEY || + (!noPriv && wp11_Object_KeyStateLocked(object) == 0)) { ret = GetData(object->data.dhKey->key, object->data.dhKey->len, data, len); } @@ -15937,6 +16056,7 @@ static int MlKemObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, int noPriv = (((object->opFlag & WP11_FLAG_SENSITIVE) != 0) || ((object->opFlag & WP11_FLAG_EXTRACTABLE) == 0)); int noPub = 0; + int noKey = (wp11_Object_KeyStateLocked(object) != 0); if (!(object->data.mlKemKey->flags & MLKEM_FLAG_PRIV_SET)) noPriv = 1; @@ -15945,7 +16065,12 @@ static int MlKemObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, switch (type) { case CKA_PARAMETER_SET: - ret = GetMlKemParams(object->data.mlKemKey, data, len); + if (noKey) { + *len = CK_UNAVAILABLE_INFORMATION; + ret = CKR_ATTRIBUTE_SENSITIVE; + } + else + ret = GetMlKemParams(object->data.mlKemKey, data, len); break; case CKA_SEED: *len = CK_UNAVAILABLE_INFORMATION; @@ -15953,7 +16078,7 @@ static int MlKemObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, break; case CKA_VALUE: if (object->objClass == CKO_PRIVATE_KEY) { - if (noPriv) { + if (noPriv || noKey) { *len = CK_UNAVAILABLE_INFORMATION; ret = CKR_ATTRIBUTE_SENSITIVE; } @@ -16023,7 +16148,7 @@ static int SecretObject_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, switch (type) { case CKA_VALUE: - if (noPriv) { + if (noPriv || wp11_Object_KeyStateLocked(object) != 0) { *len = CK_UNAVAILABLE_INFORMATION; ret = CKR_ATTRIBUTE_SENSITIVE; } @@ -16332,6 +16457,11 @@ int WP11_Object_GetAttr(WP11_Object* object, CK_ATTRIBUTE_TYPE type, byte* data, ret = NOT_AVAILABLE_E; #endif } + else if (object->objClass == CKO_SECRET_KEY && + wp11_Object_KeyStateLocked(object) != 0) { + *len = CK_UNAVAILABLE_INFORMATION; + ret = CKR_ATTRIBUTE_SENSITIVE; + } else if (object->objClass == CKO_SECRET_KEY) ret = GetSecretKeyCheckValue(object, data, len); else @@ -16582,7 +16712,7 @@ static int wp11_Object_PolicyChanged(WP11_Object* object, (object->objClass != prevClass || ((object->opFlag ^ prevFlag) & ~(word32)WP11_FLAG_POLICY_EXCLUDED) != 0)) { - if (object->encoded || object->undecoded) { + if (wp11_Object_KeyStateLocked(object) != 0) { object->objClass = prevClass; object->opFlag = prevFlag; ret = BAD_STATE_E; @@ -17640,11 +17770,11 @@ int WP11_RsaOaep_PublicEncrypt(unsigned char* in, word32 inLen, if (ret >= 0) { *outLen = ret; ret = 0; - - if (oaep->label != NULL) { - XFREE(oaep->label, NULL, DYNAMIC_TYPE_TMP_BUFFER); - oaep->label = NULL; - } + } + /* The operation ends whatever the result. */ + if (oaep->label != NULL) { + XFREE(oaep->label, NULL, DYNAMIC_TYPE_TMP_BUFFER); + oaep->label = NULL; } return ret; @@ -17713,11 +17843,9 @@ int WP11_RsaOaep_PrivateDecrypt(unsigned char* in, word32 inLen, if (priv->onToken) WP11_Lock_UnlockRW(priv->lock); - if (ret == 0) { - if (oaep->label != NULL) { - XFREE(oaep->label, NULL, DYNAMIC_TYPE_TMP_BUFFER); - oaep->label = NULL; - } + if (oaep->label != NULL) { + XFREE(oaep->label, NULL, DYNAMIC_TYPE_TMP_BUFFER); + oaep->label = NULL; } (void)slot; @@ -19001,6 +19129,8 @@ int WP11_KDF_Derive(WP11_Session* session, CK_HKDF_PARAMS_PTR params, !WP11_KeyType_IsSecret(saltKey->type) || saltKey->data.symmKey == NULL) return CKR_MECHANISM_PARAM_INVALID; + if (WP11_Object_KeyState(saltKey) != 0) + return BAD_STATE_E; salt = saltKey->data.symmKey->data; saltLen = saltKey->data.symmKey->len; break; @@ -19044,6 +19174,127 @@ int WP11_KDF_Derive(WP11_Session* session, CK_HKDF_PARAMS_PTR params, #endif +/* Call with the object lock held when the key is on the token. */ +static int wp11_Concat_KeyState(WP11_Object* key) +{ + int ret; + + if (key->objClass != CKO_SECRET_KEY || key->data.symmKey == NULL) + ret = BAD_FUNC_ARG; + else + ret = wp11_Object_KeyStateLocked(key); +#ifdef WOLFSSL_STM32U5_DHUK + if (ret == 0 && key->dhukIvLen > 0) + ret = NOT_AVAILABLE_E; +#endif + + return ret; +} + +/** + * Get the length of a secret key's value for concatenation. + * + * @param key [in] Secret key object. + * @param len [out] Length of the key value in bytes. + * @return BAD_FUNC_ARG when the object is not a secret key. + * BAD_STATE_E when the key value is not decoded. + * NOT_AVAILABLE_E when the key value is wrapped by hardware. + * 0 on success. + */ +int WP11_Concat_KeyLen(WP11_Object* key, word32* len) +{ + int ret; + + if (key == NULL || len == NULL) + return BAD_FUNC_ARG; + + if (key->onToken) + WP11_Lock_LockRO(key->lock); + ret = wp11_Concat_KeyState(key); + if (ret == 0) + *len = key->data.symmKey->len; + if (key->onToken) + WP11_Lock_UnlockRO(key->lock); + + return ret; +} + +/* Append up to outLen leading bytes of a secret key's value to out. */ +static int wp11_Concat_Key(WP11_Object* key, byte* out, word32 outLen, + word32* used) +{ + int ret; + word32 len; + + if (key->onToken) + WP11_Lock_LockRO(key->lock); + ret = wp11_Concat_KeyState(key); + if (ret == 0) { + len = key->data.symmKey->len; + if (len > outLen) + len = outLen; + if (len > 0) + XMEMCPY(out, key->data.symmKey->data, len); + *used += len; + } + if (key->onToken) + WP11_Lock_UnlockRO(key->lock); + + return ret; +} + +/** + * Concatenate a secret key's value with another key's value or with data. + * + * @param base [in] Base secret key object. + * @param other [in] Key appended to the base key. NULL to use data. + * @param data [in] Data to concatenate with the base key. + * @param dataLen [in] Length of data in bytes. + * @param dataFirst [in] Data goes before the base key value when set. + * @param out [out] Buffer to hold the leading outLen bytes. + * @param outLen [in] Number of bytes to output. + * @return BAD_FUNC_ARG when an object is not a secret key or the + * concatenation is shorter than outLen. + * BAD_STATE_E when a key value is not decoded. + * NOT_AVAILABLE_E when a key value is wrapped by hardware. + * 0 on success. + */ +int WP11_Concat_Derive(WP11_Object* base, WP11_Object* other, + const byte* data, word32 dataLen, int dataFirst, + byte* out, word32 outLen) +{ + int ret; + word32 used = 0; + word32 len; + + if (base == NULL || out == NULL || + (other == NULL && data == NULL && dataLen > 0)) + return BAD_FUNC_ARG; + + if (other == NULL && dataFirst) { + len = (dataLen < outLen) ? dataLen : outLen; + if (len > 0) + XMEMCPY(out, data, len); + used = len; + } + ret = wp11_Concat_Key(base, out + used, outLen - used, &used); + if (ret == 0 && other != NULL) { + ret = wp11_Concat_Key(other, out + used, outLen - used, &used); + } + else if (ret == 0 && !dataFirst) { + len = outLen - used; + if (dataLen < len) + len = dataLen; + if (len > 0) + XMEMCPY(out + used, data, len); + used += len; + } + + if (ret == 0 && used != outLen) + ret = BAD_FUNC_ARG; + return ret; +} + #ifndef NO_DH /** * Generate an DH key pair. @@ -21485,6 +21736,7 @@ int WP11_Digest_Update(unsigned char* data, word32 dataLen, * @param key [in] Key to be digested. * @param session [in] Session object with the Digest object. * @return CKR_KEY_INDIGESTIBLE when the key is not a secret key value. +* BAD_STATE_E when the key value is not decoded. * -ve on failure. * 0 on success. */ @@ -21498,18 +21750,20 @@ int WP11_Digest_Key(WP11_Object* key, WP11_Session* session) !WP11_KeyType_IsSecret(key->type) || key->data.symmKey == NULL) { return (int)CKR_KEY_INDIGESTIBLE; } - if (key->encoded) - return BAD_FUNC_ARG; if (key->onToken) { WP11_Lock_LockRO(key->lock); } - ret = wc_HashUpdate(&digest->hash, digest->hashType, - key->data.symmKey->data, key->data.symmKey->len); + ret = wp11_Object_KeyStateLocked(key); + if (ret == 0) { + ret = wc_HashUpdate(&digest->hash, digest->hashType, + key->data.symmKey->data, key->data.symmKey->len); + /* A hash context holding key bytes must not leave the token. */ + if (ret == 0) + digest->keyDigested = 1; + } if (key->onToken) { WP11_Lock_UnlockRO(key->lock); } - /* The hash context now holds key bytes: it must not leave the token. */ - digest->keyDigested = 1; #else (void) session; (void) key; diff --git a/src/slot.c b/src/slot.c index 0ba5b84d..5816a361 100644 --- a/src/slot.c +++ b/src/slot.c @@ -497,6 +497,9 @@ static CK_MECHANISM_TYPE mechanismList[] = { CKM_TLS_MAC, #endif CKM_GENERIC_SECRET_KEY_GEN, + CKM_CONCATENATE_BASE_AND_KEY, + CKM_CONCATENATE_BASE_AND_DATA, + CKM_CONCATENATE_DATA_AND_BASE, #ifndef NO_HMAC CKM_PKCS5_PBKD2 #endif @@ -909,6 +912,9 @@ static CK_MECHANISM_INFO sha3MechInfo = { static CK_MECHANISM_INFO genSecKeyGenMechInfo = { 8, WP11_MAX_SYM_KEY_SZ * 8, CKF_GENERATE }; +static CK_MECHANISM_INFO concatMechInfo = { + 8, WP11_MAX_SYM_KEY_SZ * 8, CKF_DERIVE +}; #ifndef NO_HMAC static CK_MECHANISM_INFO pkcs5Pbkdf2MechInfo = { @@ -1293,6 +1299,11 @@ CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, XMEMCPY(pInfo, &genSecKeyGenMechInfo, sizeof(CK_MECHANISM_INFO)); break; + case CKM_CONCATENATE_BASE_AND_KEY: + case CKM_CONCATENATE_BASE_AND_DATA: + case CKM_CONCATENATE_DATA_AND_BASE: + XMEMCPY(pInfo, &concatMechInfo, sizeof(CK_MECHANISM_INFO)); + break; #ifndef NO_HMAC case CKM_PKCS5_PBKD2: XMEMCPY(pInfo, &pkcs5Pbkdf2MechInfo, diff --git a/tests/pkcs11str.c b/tests/pkcs11str.c index 8fe2de79..b0b5d74d 100644 --- a/tests/pkcs11str.c +++ b/tests/pkcs11str.c @@ -961,6 +961,268 @@ static CK_RV find_mlkem_pub_key(CK_SESSION_HANDLE session, } #endif /* WOLFPKCS11_MLKEM */ +#ifndef WOLFPKCS11_NO_STORE +static unsigned char secretKeyId[] = "123secretkey"; + +static CK_RV create_public_secret_key(CK_SESSION_HANDLE session) +{ + CK_RV ret; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_BBOOL ckFalse = CK_FALSE; + unsigned char value[16] = { 0 }; + CK_OBJECT_HANDLE key; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + { CKA_ID, secretKeyId, sizeof(secretKeyId) - 1 }, + { CKA_VALUE, value, sizeof(value) }, + }; + + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &key); + CHECK_CKR(ret, "Create public secret key"); + + return ret; +} + +#if defined(HAVE_ECC) || !defined(NO_DH) +#ifdef HAVE_ECC +static unsigned char ecPublicId[] = "123ecpublic"; +#endif +#ifndef NO_DH +static unsigned char dhPublicId[] = "123dhpublic"; +#endif + +static CK_RV create_public_asym_keys(CK_SESSION_HANDLE session) +{ + CK_RV ret = CKR_OK; + CK_BBOOL ckFalse = CK_FALSE; + CK_OBJECT_HANDLE key; +#ifdef HAVE_ECC + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, + { CKA_KEY_TYPE, &eccKeyType, sizeof(eccKeyType) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params) }, + { CKA_VALUE, ecc_p256_priv, sizeof(ecc_p256_priv) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_ID, ecPublicId, sizeof(ecPublicId) - 1 }, + }; + CK_ATTRIBUTE pubTmpl[] = { + { CKA_CLASS, &pubKeyClass, sizeof(pubKeyClass) }, + { CKA_KEY_TYPE, &eccKeyType, sizeof(eccKeyType) }, + { CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params) }, + { CKA_EC_POINT, ecc_p256_pub, sizeof(ecc_p256_pub) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_ID, ecPublicId, sizeof(ecPublicId) - 1 }, + }; +#endif +#ifndef NO_DH + CK_ATTRIBUTE dhTmpl[] = { + { CKA_CLASS, &privKeyClass, sizeof(privKeyClass) }, + { CKA_KEY_TYPE, &dhKeyType, sizeof(dhKeyType) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_PRIME, dh_ffdhe2048_p, sizeof(dh_ffdhe2048_p) }, + { CKA_BASE, dh_ffdhe2048_g, sizeof(dh_ffdhe2048_g) }, + { CKA_VALUE, dh_2048_priv, sizeof(dh_2048_priv) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_ID, dhPublicId, sizeof(dhPublicId) - 1 }, + }; +#endif + +#ifdef HAVE_ECC + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &key); + CHECK_CKR(ret, "Create public EC private key"); + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, pubTmpl, + sizeof(pubTmpl) / sizeof(*pubTmpl), + &key); + CHECK_CKR(ret, "Create EC public key"); + } +#endif +#ifndef NO_DH + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, dhTmpl, + sizeof(dhTmpl) / sizeof(*dhTmpl), &key); + CHECK_CKR(ret, "Create public DH private key"); + } +#endif + + return ret; +} + +static CK_RV find_public_object(CK_SESSION_HANDLE session, + CK_OBJECT_CLASS objClass, unsigned char* id, + CK_ULONG idLen, CK_OBJECT_HANDLE* obj) +{ + CK_RV ret; + CK_ULONG count = 0; + CK_ATTRIBUTE findTmpl[] = { + { CKA_CLASS, &objClass, sizeof(objClass) }, + { CKA_ID, id, idLen }, + }; + + ret = funcList->C_FindObjectsInit(session, findTmpl, + sizeof(findTmpl) / sizeof(*findTmpl)); + CHECK_CKR(ret, "Find public object init"); + if (ret == CKR_OK) { + ret = funcList->C_FindObjects(session, obj, 1, &count); + CHECK_CKR(ret, "Find public object"); + funcList->C_FindObjectsFinal(session); + } + if (ret == CKR_OK && count != 1) { + ret = -1; + CHECK_CKR(ret, "Find public object count"); + } + + return ret; +} +#endif + +static CK_RV undecoded_key_before_login(void) +{ + CK_RV ret; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_BBOOL ckFalse = CK_FALSE; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE key = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE derived = CK_INVALID_HANDLE; + CK_ULONG count = 0; + unsigned char data[4] = { 0xd0, 0xd1, 0xd2, 0xd3 }; + CK_KEY_DERIVATION_STRING_DATA params = { data, sizeof(data) }; + CK_MECHANISM mech = { CKM_CONCATENATE_BASE_AND_DATA, ¶ms, + sizeof(params) }; +#ifndef NO_HMAC + CK_MECHANISM macMech = { CKM_SHA256_HMAC, NULL, 0 }; +#endif + CK_ATTRIBUTE findTmpl[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_ID, secretKeyId, sizeof(secretKeyId) - 1 }, + }; +#ifdef HAVE_ECC + CK_OBJECT_HANDLE ecKey = CK_INVALID_HANDLE; + unsigned char ecParams[16]; + CK_ATTRIBUTE paramsTmpl = { CKA_EC_PARAMS, ecParams, sizeof(ecParams) }; + CK_OBJECT_HANDLE ecPub = CK_INVALID_HANDLE; + unsigned char ecPoint[sizeof(ecc_p256_pub)]; + CK_ATTRIBUTE pointTmpl = { CKA_EC_POINT, ecPoint, sizeof(ecPoint) }; +#endif +#ifndef NO_DH + CK_OBJECT_HANDLE dhKey = CK_INVALID_HANDLE; + unsigned char prime[sizeof(dh_ffdhe2048_p)]; + unsigned char dhValue[sizeof(dh_2048_priv)]; + CK_ATTRIBUTE primeTmpl = { CKA_PRIME, prime, sizeof(prime) }; + CK_ATTRIBUTE dhValueTmpl = { CKA_VALUE, dhValue, sizeof(dhValue) }; +#endif + CK_ULONG valueLen = 16 + sizeof(data); + CK_ULONG keyLen = 0; + CK_ATTRIBUTE lenTmpl = { CKA_VALUE_LEN, &keyLen, sizeof(keyLen) }; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_VALUE_LEN, &valueLen, sizeof(valueLen) }, + }; + + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &session); + CHECK_CKR(ret, "Open session before login"); + if (ret == CKR_OK) { + ret = funcList->C_FindObjectsInit(session, findTmpl, + sizeof(findTmpl) / sizeof(*findTmpl)); + CHECK_CKR(ret, "Find public secret key init"); + } + if (ret == CKR_OK) { + ret = funcList->C_FindObjects(session, &key, 1, &count); + CHECK_CKR(ret, "Find public secret key"); + funcList->C_FindObjectsFinal(session); + } + if (ret == CKR_OK && count != 1) { + ret = -1; + CHECK_CKR(ret, "Find public secret key count"); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, key, &lenTmpl, 1); + CHECK_CKR(ret, "Key length of undecoded key before login"); + } + CHECK_COND(ret != CKR_OK || keyLen == 16, ret, + "Key length value before login"); + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &mech, key, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &derived); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Concatenate undecoded key before login"); + } +#ifndef NO_HMAC + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &macMech, key); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "HMAC sign with undecoded key before login"); + } +#endif +#ifdef HAVE_ECC + if (ret == CKR_OK) { + ret = find_public_object(session, CKO_PRIVATE_KEY, ecPublicId, + sizeof(ecPublicId) - 1, &ecKey); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, ecKey, ¶msTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "EC parameters of undecoded key before login"); + } + if (ret == CKR_OK) { + ret = find_public_object(session, CKO_PUBLIC_KEY, ecPublicId, + sizeof(ecPublicId) - 1, &ecPub); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, ecPub, &pointTmpl, 1); + CHECK_CKR(ret, "EC point of public key before login"); + } + CHECK_COND(ret != CKR_OK || + (pointTmpl.ulValueLen == sizeof(ecc_p256_pub) && + XMEMCMP(ecPoint, ecc_p256_pub, sizeof(ecPoint)) == 0), ret, + "EC point value before login"); + if (ret == CKR_OK) { + paramsTmpl.ulValueLen = sizeof(ecParams); + ret = funcList->C_GetAttributeValue(session, ecPub, ¶msTmpl, 1); + CHECK_CKR(ret, "EC parameters of public key before login"); + } + CHECK_COND(ret != CKR_OK || + (paramsTmpl.ulValueLen == sizeof(ecc_p256_params) && + XMEMCMP(ecParams, ecc_p256_params, + sizeof(ecc_p256_params)) == 0), ret, + "EC parameters value before login"); +#endif +#ifndef NO_DH + if (ret == CKR_OK) { + ret = find_public_object(session, CKO_PRIVATE_KEY, dhPublicId, + sizeof(dhPublicId) - 1, &dhKey); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, dhKey, &primeTmpl, 1); + CHECK_CKR(ret, "DH prime of undecoded key before login"); + } + CHECK_COND(ret != CKR_OK || (primeTmpl.ulValueLen == sizeof(prime) && + XMEMCMP(prime, dh_ffdhe2048_p, sizeof(prime)) == 0), ret, + "DH prime value before login"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, dhKey, &dhValueTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "DH value of undecoded key before login"); + } +#endif + if (session != CK_INVALID_HANDLE) + funcList->C_CloseSession(session); + + return ret; +} +#endif + static CK_RV pkcs11_test(int slotId, int setPin, int closeDl) { CK_RV ret; @@ -1131,6 +1393,24 @@ static CK_RV pkcs11_test(int slotId, int setPin, int closeDl) printf("Done\n"); } } +#endif +#ifndef WOLFPKCS11_NO_STORE + if (ret == CKR_OK && userPinLen != 0) { + printf("Create public secret key ... "); + ret = create_public_secret_key(session); + if (ret == CKR_OK) { + printf("Done\n"); + } + } +#if defined(HAVE_ECC) || !defined(NO_DH) + if (ret == CKR_OK && userPinLen != 0) { + printf("Create public asymmetric keys ... "); + ret = create_public_asym_keys(session); + if (ret == CKR_OK) { + printf("Done\n"); + } + } +#endif #endif pkcs11_close_session(session); } @@ -1155,6 +1435,13 @@ static CK_RV pkcs11_test(int slotId, int setPin, int closeDl) printf("Done\n"); } } + if (ret == CKR_OK && userPinLen != 0) { + printf("Use undecoded key before login ... "); + ret = undecoded_key_before_login(); + if (ret == CKR_OK) { + printf("Done\n"); + } + } #endif if (ret == CKR_OK) { inited = 1; diff --git a/tests/pkcs11test.c b/tests/pkcs11test.c index c1e2d532..f37c3c41 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -6705,10 +6705,12 @@ static CK_RV test_wrap_key_wrap_with_trusted(void* args) 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 trustedTokenKey = CK_INVALID_HANDLE; CK_OBJECT_HANDLE key = CK_INVALID_HANDLE; byte wrappedKey[40], keyData[16]; CK_ULONG wrappedKeyLen; CK_BBOOL ckTrusted = CK_TRUE; + CK_BBOOL onToken = CK_FALSE; CK_ATTRIBUTE untrustedWrapTmpl[] = { { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, { CKA_KEY_TYPE, &aesKeyType, sizeof(aesKeyType) }, @@ -6718,14 +6720,14 @@ static CK_RV test_wrap_key_wrap_with_trusted(void* args) CK_ULONG untrustedWrapTmplCnt = sizeof(untrustedWrapTmpl) / sizeof(*untrustedWrapTmpl); /* CKA_TRUSTED may only be set by the SO, so the trusted wrapping key is - * provisioned as a public token object under an SO session. */ + * provisioned as a public session object under an SO session. */ 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) }, - { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &onToken, sizeof(onToken) }, { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, }; CK_ULONG trustedWrapTmplCnt = sizeof(trustedWrapTmpl) / @@ -6743,7 +6745,7 @@ static CK_RV test_wrap_key_wrap_with_trusted(void* args) /* Provision the trusted wrapping key as the SO. The token has a single * login state, so log the harness user out, log in as SO to create the - * public token key, then restore the user session. */ + * public session key, then restore the user session. */ ret = funcList->C_Logout(session); CHECK_CKR(ret, "Logout user before SO provisioning"); if (ret == CKR_OK) { @@ -6755,6 +6757,12 @@ static CK_RV test_wrap_key_wrap_with_trusted(void* args) trustedWrapTmplCnt, &trustedKey); CHECK_CKR(ret, "Create trusted AES wrapping key (SO)"); } + if (ret == CKR_OK) { + onToken = CK_TRUE; + ret = funcList->C_CreateObject(session, trustedWrapTmpl, + trustedWrapTmplCnt, &trustedTokenKey); + CHECK_CKR(ret, "Create trusted AES wrapping token key (SO)"); + } if (ret == CKR_OK) { ret = funcList->C_Logout(session); CHECK_CKR(ret, "Logout SO after provisioning"); @@ -6799,9 +6807,69 @@ static CK_RV test_wrap_key_wrap_with_trusted(void* args) wrappedKey, &wrappedKeyLen); CHECK_CKR(ret, "Wrap CKA_WRAP_WITH_TRUSTED key with trusted wrapping key"); } + /* A token key the SO created does not decode for the user. */ + if (ret == CKR_OK) { + wrappedKeyLen = sizeof(wrappedKey); + ret = funcList->C_WrapKey(session, &mech, trustedTokenKey, key, + wrappedKey, &wrappedKeyLen); + CHECK_CKR_FAIL(ret, CKR_FUNCTION_FAILED, + "Wrap with trusted token key created by SO"); + } +#ifndef NO_SHA256 + if (ret == CKR_OK) { + CK_MECHANISM digestMech = { CKM_SHA256, NULL, 0 }; + + ret = funcList->C_DigestInit(session, &digestMech); + CHECK_CKR(ret, "Digest init for token key created by SO"); + if (ret == CKR_OK) { + ret = funcList->C_DigestKey(session, trustedTokenKey); + CHECK_CKR_FAIL(ret, CKR_FUNCTION_FAILED, + "Digest token key created by SO"); + } + } +#endif +#ifdef WOLFPKCS11_HKDF + if (ret == CKR_OK) { + CK_OBJECT_HANDLE base = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE derived = CK_INVALID_HANDLE; + CK_ULONG outLen = 32; + CK_HKDF_PARAMS hkdf; + CK_MECHANISM hkdfMech = { CKM_HKDF_DERIVE, &hkdf, sizeof(hkdf) }; + CK_ATTRIBUTE baseTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE, keyData, sizeof(keyData) }, + { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, + }; + CK_ATTRIBUTE outTmpl[] = { + { CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass) }, + { CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType) }, + { CKA_VALUE_LEN, &outLen, sizeof(outLen) }, + }; + + XMEMSET(&hkdf, 0, sizeof(hkdf)); + hkdf.bExtract = CK_TRUE; + hkdf.prfHashMechanism = CKM_SHA256_HMAC; + hkdf.ulSaltType = CKF_HKDF_SALT_KEY; + hkdf.hSaltKey = trustedTokenKey; + ret = funcList->C_CreateObject(session, baseTmpl, + sizeof(baseTmpl) / sizeof(*baseTmpl), + &base); + CHECK_CKR(ret, "Create HKDF base key"); + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &hkdfMech, base, outTmpl, + sizeof(outTmpl) / sizeof(*outTmpl), + &derived); + CHECK_CKR_FAIL(ret, CKR_FUNCTION_FAILED, + "HKDF with salt token key created by SO"); + funcList->C_DestroyObject(session, base); + } + } +#endif funcList->C_DestroyObject(session, untrustedKey); funcList->C_DestroyObject(session, trustedKey); + funcList->C_DestroyObject(session, trustedTokenKey); funcList->C_DestroyObject(session, key); return ret; @@ -15997,239 +16065,2220 @@ static CK_RV test_hkdf_derive_implied_class(void* args) } #endif -#ifndef NO_SHA -static CK_RV test_x509_check_value(void* args) +static CK_RV concat_create_key(CK_SESSION_HANDLE session, CK_BYTE* value, + CK_ULONG len, CK_BBOOL sensitive, + CK_BBOOL extractable, CK_BBOOL derive, + CK_BBOOL token, CK_OBJECT_HANDLE* key) { - CK_RV ret = CKR_OK; - CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; - CK_CERTIFICATE_TYPE certType = CKC_X_509; - CK_UTF8CHAR label[] = "A certificate object"; - CK_BYTE subject[] = "C = US, ST = Montana, L = Bozeman, O = wolfSSL, " - "OU = Support, CN = www.wolfssl.com, emailAddress = info@wolfssl.com"; - CK_BYTE id[] = {0x27, 0x8E, 0x67, 0x11, 0x74, 0xC3, 0x26, 0x1D, 0x3F, 0xED, - 0x33, 0x63, 0xB3, 0xA4, 0xD8, 0x1D, 0x30, 0xE5, 0xE8, 0xD5 - }; - CK_BYTE certificate[] = { /* ./certs/server-cert.der, 2048-bit */ - 0x30, 0x82, 0x04, 0xE8, 0x30, 0x82, 0x03, 0xD0, 0xA0, 0x03, - 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0D, 0x06, 0x09, - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, - 0x00, 0x30, 0x81, 0x94, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, - 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, - 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 0x6F, - 0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 0x06, - 0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 0x65, - 0x6D, 0x61, 0x6E, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, - 0x04, 0x0A, 0x0C, 0x08, 0x53, 0x61, 0x77, 0x74, 0x6F, 0x6F, - 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, - 0x0B, 0x0C, 0x0A, 0x43, 0x6F, 0x6E, 0x73, 0x75, 0x6C, 0x74, - 0x69, 0x6E, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, - 0x04, 0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, - 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, - 0x1F, 0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, - 0x40, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, - 0x6F, 0x6D, 0x30, 0x1E, 0x17, 0x0D, 0x32, 0x33, 0x31, 0x32, - 0x31, 0x33, 0x32, 0x32, 0x31, 0x39, 0x32, 0x38, 0x5A, 0x17, - 0x0D, 0x32, 0x36, 0x30, 0x39, 0x30, 0x38, 0x32, 0x32, 0x31, - 0x39, 0x32, 0x38, 0x5A, 0x30, 0x81, 0x90, 0x31, 0x0B, 0x30, - 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, - 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, - 0x07, 0x4D, 0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, - 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, - 0x6F, 0x7A, 0x65, 0x6D, 0x61, 0x6E, 0x31, 0x10, 0x30, 0x0E, - 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x07, 0x77, 0x6F, 0x6C, - 0x66, 0x53, 0x53, 0x4C, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, - 0x55, 0x04, 0x0B, 0x0C, 0x07, 0x53, 0x75, 0x70, 0x70, 0x6F, - 0x72, 0x74, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, - 0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, - 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, - 0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, - 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, - 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, - 0x6D, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, - 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, - 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, - 0x82, 0x01, 0x01, 0x00, 0xC0, 0x95, 0x08, 0xE1, 0x57, 0x41, - 0xF2, 0x71, 0x6D, 0xB7, 0xD2, 0x45, 0x41, 0x27, 0x01, 0x65, - 0xC6, 0x45, 0xAE, 0xF2, 0xBC, 0x24, 0x30, 0xB8, 0x95, 0xCE, - 0x2F, 0x4E, 0xD6, 0xF6, 0x1C, 0x88, 0xBC, 0x7C, 0x9F, 0xFB, - 0xA8, 0x67, 0x7F, 0xFE, 0x5C, 0x9C, 0x51, 0x75, 0xF7, 0x8A, - 0xCA, 0x07, 0xE7, 0x35, 0x2F, 0x8F, 0xE1, 0xBD, 0x7B, 0xC0, - 0x2F, 0x7C, 0xAB, 0x64, 0xA8, 0x17, 0xFC, 0xCA, 0x5D, 0x7B, - 0xBA, 0xE0, 0x21, 0xE5, 0x72, 0x2E, 0x6F, 0x2E, 0x86, 0xD8, - 0x95, 0x73, 0xDA, 0xAC, 0x1B, 0x53, 0xB9, 0x5F, 0x3F, 0xD7, - 0x19, 0x0D, 0x25, 0x4F, 0xE1, 0x63, 0x63, 0x51, 0x8B, 0x0B, - 0x64, 0x3F, 0xAD, 0x43, 0xB8, 0xA5, 0x1C, 0x5C, 0x34, 0xB3, - 0xAE, 0x00, 0xA0, 0x63, 0xC5, 0xF6, 0x7F, 0x0B, 0x59, 0x68, - 0x78, 0x73, 0xA6, 0x8C, 0x18, 0xA9, 0x02, 0x6D, 0xAF, 0xC3, - 0x19, 0x01, 0x2E, 0xB8, 0x10, 0xE3, 0xC6, 0xCC, 0x40, 0xB4, - 0x69, 0xA3, 0x46, 0x33, 0x69, 0x87, 0x6E, 0xC4, 0xBB, 0x17, - 0xA6, 0xF3, 0xE8, 0xDD, 0xAD, 0x73, 0xBC, 0x7B, 0x2F, 0x21, - 0xB5, 0xFD, 0x66, 0x51, 0x0C, 0xBD, 0x54, 0xB3, 0xE1, 0x6D, - 0x5F, 0x1C, 0xBC, 0x23, 0x73, 0xD1, 0x09, 0x03, 0x89, 0x14, - 0xD2, 0x10, 0xB9, 0x64, 0xC3, 0x2A, 0xD0, 0xA1, 0x96, 0x4A, - 0xBC, 0xE1, 0xD4, 0x1A, 0x5B, 0xC7, 0xA0, 0xC0, 0xC1, 0x63, - 0x78, 0x0F, 0x44, 0x37, 0x30, 0x32, 0x96, 0x80, 0x32, 0x23, - 0x95, 0xA1, 0x77, 0xBA, 0x13, 0xD2, 0x97, 0x73, 0xE2, 0x5D, - 0x25, 0xC9, 0x6A, 0x0D, 0xC3, 0x39, 0x60, 0xA4, 0xB4, 0xB0, - 0x69, 0x42, 0x42, 0x09, 0xE9, 0xD8, 0x08, 0xBC, 0x33, 0x20, - 0xB3, 0x58, 0x22, 0xA7, 0xAA, 0xEB, 0xC4, 0xE1, 0xE6, 0x61, - 0x83, 0xC5, 0xD2, 0x96, 0xDF, 0xD9, 0xD0, 0x4F, 0xAD, 0xD7, - 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x82, 0x01, 0x45, 0x30, - 0x82, 0x01, 0x41, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, - 0x04, 0x16, 0x04, 0x14, 0xB3, 0x11, 0x32, 0xC9, 0x92, 0x98, - 0x84, 0xE2, 0xC9, 0xF8, 0xD0, 0x3B, 0x6E, 0x03, 0x42, 0xCA, - 0x1F, 0x0E, 0x8E, 0x3C, 0x30, 0x81, 0xD4, 0x06, 0x03, 0x55, - 0x1D, 0x23, 0x04, 0x81, 0xCC, 0x30, 0x81, 0xC9, 0x80, 0x14, - 0x27, 0x8E, 0x67, 0x11, 0x74, 0xC3, 0x26, 0x1D, 0x3F, 0xED, - 0x33, 0x63, 0xB3, 0xA4, 0xD8, 0x1D, 0x30, 0xE5, 0xE8, 0xD5, - 0xA1, 0x81, 0x9A, 0xA4, 0x81, 0x97, 0x30, 0x81, 0x94, 0x31, - 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, - 0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, - 0x08, 0x0C, 0x07, 0x4D, 0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, - 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, - 0x07, 0x42, 0x6F, 0x7A, 0x65, 0x6D, 0x61, 0x6E, 0x31, 0x11, - 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x08, 0x53, - 0x61, 0x77, 0x74, 0x6F, 0x6F, 0x74, 0x68, 0x31, 0x13, 0x30, - 0x11, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x0A, 0x43, 0x6F, - 0x6E, 0x73, 0x75, 0x6C, 0x74, 0x69, 0x6E, 0x67, 0x31, 0x18, - 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x77, - 0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, - 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, 0x30, 0x1D, 0x06, 0x09, - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, - 0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, 0x77, 0x6F, 0x6C, 0x66, - 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x82, 0x14, 0x33, - 0x44, 0x1A, 0xA8, 0x6C, 0x01, 0xEC, 0xF6, 0x60, 0xF2, 0x70, - 0x51, 0x0A, 0x4C, 0xD1, 0x14, 0xFA, 0xBC, 0xE9, 0x44, 0x30, - 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x05, 0x30, 0x03, - 0x01, 0x01, 0xFF, 0x30, 0x1C, 0x06, 0x03, 0x55, 0x1D, 0x11, - 0x04, 0x15, 0x30, 0x13, 0x82, 0x0B, 0x65, 0x78, 0x61, 0x6D, - 0x70, 0x6C, 0x65, 0x2E, 0x63, 0x6F, 0x6D, 0x87, 0x04, 0x7F, - 0x00, 0x00, 0x01, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x25, - 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, - 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, - 0x05, 0x07, 0x03, 0x02, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, - 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, - 0x82, 0x01, 0x01, 0x00, 0x4A, 0xFF, 0xB9, 0xE5, 0x85, 0x9B, - 0xDA, 0x53, 0x66, 0x7F, 0x07, 0x22, 0xBF, 0xB6, 0x19, 0xEA, - 0x42, 0xEB, 0xA4, 0x11, 0x07, 0x62, 0xFF, 0x39, 0x5F, 0x33, - 0x37, 0x3A, 0x87, 0x26, 0x71, 0x3D, 0x13, 0xB2, 0xCA, 0xB8, - 0x64, 0x38, 0x7B, 0x8A, 0x99, 0x48, 0x0E, 0xA5, 0xA4, 0x6B, - 0xB1, 0x99, 0x6E, 0xE0, 0x46, 0x51, 0xBD, 0x19, 0x52, 0xAD, - 0xBC, 0xA6, 0x7E, 0x2A, 0x7A, 0x7C, 0x23, 0xA7, 0xCC, 0xDB, - 0x5E, 0x43, 0x7D, 0x6B, 0x04, 0xC8, 0xB7, 0xDD, 0x95, 0xAD, - 0xF0, 0x91, 0x80, 0x59, 0xC5, 0x19, 0x91, 0x26, 0x27, 0x91, - 0xB8, 0x48, 0x1C, 0xEB, 0x55, 0xB6, 0xAA, 0x7D, 0xA4, 0x38, - 0xF1, 0x03, 0xBC, 0x6C, 0x8B, 0xAA, 0x94, 0xD6, 0x3C, 0x05, - 0x7A, 0x96, 0xC5, 0x06, 0xF1, 0x26, 0x14, 0x2E, 0x75, 0xFB, - 0xDD, 0xE5, 0x35, 0xB3, 0x01, 0x2C, 0xB3, 0xAD, 0x62, 0x5A, - 0x21, 0x9A, 0x08, 0xBE, 0x56, 0xFC, 0xF9, 0xA2, 0x42, 0x87, - 0x86, 0xE5, 0xA9, 0xC5, 0x99, 0xCF, 0xAE, 0x14, 0xBE, 0xE0, - 0xB9, 0x08, 0x24, 0x0D, 0x1D, 0x5C, 0xD6, 0x14, 0xE1, 0x4C, - 0x9F, 0x40, 0xB3, 0xA9, 0xE9, 0x2D, 0x52, 0x8B, 0x4C, 0xBF, - 0xAC, 0x44, 0x31, 0x67, 0xC1, 0x8D, 0x06, 0x85, 0xEC, 0x0F, - 0xE4, 0x99, 0xD7, 0x4B, 0x7B, 0x21, 0x06, 0x66, 0xD4, 0xE4, - 0xF5, 0x9D, 0xFF, 0x8E, 0xF0, 0x86, 0x39, 0x58, 0x1D, 0xA4, - 0x5B, 0xE2, 0x63, 0xEF, 0x7C, 0xC9, 0x18, 0x87, 0xA8, 0x02, - 0x25, 0x10, 0x3E, 0x87, 0x28, 0xF9, 0xF5, 0xEF, 0x47, 0x9E, - 0xA5, 0x80, 0x08, 0x11, 0x90, 0x68, 0xFE, 0xD1, 0xA3, 0xA8, - 0x51, 0xB9, 0x37, 0xFF, 0xD5, 0xCA, 0x7C, 0x87, 0x7F, 0x6B, - 0xBC, 0x2C, 0x12, 0xC8, 0xC5, 0x85, 0x8B, 0xFC, 0x0C, 0xC6, - 0xB9, 0x86, 0xB8, 0xC9, 0x04, 0xC3, 0x51, 0x37, 0xD2, 0x4F + CK_ATTRIBUTE tmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_TOKEN, &token, sizeof(token)}, + {CKA_SENSITIVE, &sensitive, sizeof(sensitive)}, + {CKA_EXTRACTABLE, &extractable, sizeof(extractable)}, + {CKA_DERIVE, &derive, sizeof(derive)}, + {CKA_SIGN, &ckTrue, sizeof(ckTrue)}, + {CKA_VALUE, value, len}, }; - /* Expected check value - first 3 bytes of SHA-1 hash of the certificate */ - CK_BYTE expectedCheckValue[] = {0xB6, 0x38, 0x75}; + return funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), key); +} + +static CK_RV concat_derive(CK_SESSION_HANDLE session, CK_MECHANISM* mech, + CK_OBJECT_HANDLE base, CK_KEY_TYPE keyType, + CK_ULONG valueLen, CK_OBJECT_HANDLE* key) +{ CK_ATTRIBUTE tmpl[] = { - {CKA_CLASS, &certificateClass, sizeof(certificateClass)}, - {CKA_CERTIFICATE_TYPE, &certType, sizeof(certType)}, - {CKA_TOKEN, &ckTrue, sizeof(ckTrue)}, - {CKA_LABEL, label, sizeof(label)-1}, - {CKA_SUBJECT, subject, sizeof(subject)-1}, - {CKA_ID, id, sizeof(id)}, - {CKA_VALUE, certificate, sizeof(certificate)} - }; - CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); - CK_OBJECT_HANDLE obj; - CK_ATTRIBUTE checkValueTmpl[] = { - { CKA_CHECK_VALUE, NULL, 0 } + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + {CKA_SENSITIVE, &ckFalse, sizeof(ckFalse)}, + {CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_SIGN, &ckTrue, sizeof(ckTrue)}, + {CKA_VALUE_LEN, &valueLen, sizeof(valueLen)}, }; - CK_ULONG checkValueTmplCnt = sizeof(checkValueTmpl) / sizeof(*checkValueTmpl); - CK_BYTE checkValue[3]; + CK_ULONG cnt = sizeof(tmpl) / sizeof(*tmpl); - /* Create certificate object */ - ret = funcList->C_CreateObject(session, tmpl, tmplCnt, &obj); - CHECK_CKR(ret, "Create certificate object"); + if (valueLen == 0) + cnt--; + *key = CK_INVALID_HANDLE; + return funcList->C_DeriveKey(session, mech, base, tmpl, cnt, key); +} - if (ret == CKR_OK) { - /* Get the length of the check value first */ - ret = funcList->C_GetAttributeValue(session, obj, checkValueTmpl, checkValueTmplCnt); - CHECK_CKR(ret, "C_GetAttributeValue for check value length"); - } +static CK_RV concat_check_value(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE key, CK_BYTE* exp, + CK_ULONG expLen) +{ + CK_RV ret; + CK_BYTE value[64]; + CK_ATTRIBUTE attr = {CKA_VALUE, value, sizeof(value)}; - if (ret == CKR_OK) { - /* Verify expected check value length is 3 bytes */ - if (checkValueTmpl[0].ulValueLen != 3) { - ret = CKR_GENERAL_ERROR; - CHECK_CKR(ret, "Check value length should be 3 bytes"); - } + ret = funcList->C_GetAttributeValue(session, key, &attr, 1); + CHECK_CKR(ret, "Get concatenated value"); + if (ret == CKR_OK && (attr.ulValueLen != expLen || + XMEMCMP(value, exp, expLen) != 0)) { + ret = CKR_DATA_INVALID; + CHECK_CKR(ret, "Concatenated value"); } + funcList->C_DestroyObject(session, key); - if (ret == CKR_OK) { - /* Get the actual check value */ - checkValueTmpl[0].pValue = checkValue; - checkValueTmpl[0].ulValueLen = sizeof(checkValue); + return ret; +} - ret = funcList->C_GetAttributeValue(session, obj, checkValueTmpl, checkValueTmplCnt); - CHECK_CKR(ret, "C_GetAttributeValue for check value"); +static CK_RV concat_check_bools(CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE key, CK_BBOOL sensitive, + CK_BBOOL extractable, + CK_BBOOL alwaysSensitive, + CK_BBOOL neverExtractable) +{ + CK_RV ret; + CK_BBOOL got[4]; + CK_ATTRIBUTE attrs[] = { + {CKA_SENSITIVE, &got[0], sizeof(CK_BBOOL)}, + {CKA_EXTRACTABLE, &got[1], sizeof(CK_BBOOL)}, + {CKA_ALWAYS_SENSITIVE, &got[2], sizeof(CK_BBOOL)}, + {CKA_NEVER_EXTRACTABLE, &got[3], sizeof(CK_BBOOL)}, + }; - if (ret == CKR_OK) { - /* Verify the check value matches expected value */ - if (XMEMCMP(checkValue, expectedCheckValue, 3) != 0) { - ret = CKR_GENERAL_ERROR; - CHECK_CKR(ret, "Check value doesn't match expected SHA-1 hash prefix"); - } - } + ret = funcList->C_GetAttributeValue(session, key, attrs, 4); + CHECK_CKR(ret, "Get derived key protection"); + if (ret == CKR_OK && (got[0] != sensitive || got[1] != extractable || + got[2] != alwaysSensitive || got[3] != neverExtractable)) { + ret = CKR_DATA_INVALID; + CHECK_CKR(ret, "Derived key protection"); } - - /* Clean up the object */ - funcList->C_DestroyObject(session, obj); + funcList->C_DestroyObject(session, key); return ret; } -#endif -static CK_RV test_random(void* args) +static CK_RV test_concatenate_base_and_key(void* args) { CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; CK_RV ret; - unsigned char* seed = (unsigned char *)"Test"; - int seedLen = 4; - unsigned char data1[32]; - unsigned char data2[32]; - int i; - unsigned char b; + CK_BYTE a[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + }; + CK_BYTE b[8] = { 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7 }; + CK_BYTE ab[24]; + CK_BYTE aa[32]; + CK_OBJECT_HANDLE hA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hB = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hOther = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey; + CK_MECHANISM mech = { CKM_CONCATENATE_BASE_AND_KEY, &hOther, + sizeof(hOther) }; - XMEMSET(data1, 0, sizeof(data1)); - XMEMSET(data2, 0, sizeof(data2)); + XMEMCPY(ab, a, sizeof(a)); + XMEMCPY(ab + sizeof(a), b, sizeof(b)); + XMEMCPY(aa, a, sizeof(a)); + XMEMCPY(aa + sizeof(a), a, sizeof(a)); - ret = funcList->C_SeedRandom(session, seed, seedLen); - CHECK_CKR(ret, "Seed Random 1"); + ret = concat_create_key(session, a, sizeof(a), CK_FALSE, CK_TRUE, CK_TRUE, + CK_FALSE, &hA); + CHECK_CKR(ret, "Create base key"); if (ret == CKR_OK) { - ret = funcList->C_GenerateRandom(session, data1, sizeof(data1)); - CHECK_CKR(ret, "Generate Random 1"); + ret = concat_create_key(session, b, sizeof(b), CK_FALSE, CK_TRUE, + CK_TRUE, CK_TRUE, &hB); + CHECK_CKR(ret, "Create token key"); } if (ret == CKR_OK) { - b = 0; - for (i = 0; i < (int)sizeof(data1); i++) - b |= data1[i]; - if (b == 0) - ret = -1; - CHECK_CKR(ret, "Generated non-zero 1"); + hOther = hB; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate base and key"); } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, ab, sizeof(ab)); if (ret == CKR_OK) { - ret = funcList->C_SeedRandom(session, seed, seedLen); - CHECK_CKR(ret, "Seed Random 2"); + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 20, &hKey); + CHECK_CKR(ret, "Concatenate base and key, shorter length"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, ab, 20); + if (ret == CKR_OK) { + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, + sizeof(ab) + 1, &hKey); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "Concatenate base and key, length too long"); + } + if (ret == CKR_OK) { + hOther = hA; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate base key with itself"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, aa, sizeof(aa)); +#ifndef NO_AES + if (ret == CKR_OK) { + hOther = hB; + ret = concat_derive(session, &mech, hA, CKK_AES, 0, &hKey); + CHECK_CKR_FAIL(ret, CKR_TEMPLATE_INCOMPLETE, + "Concatenate to AES key without length"); + } + if (ret == CKR_OK) { + ret = concat_derive(session, &mech, hA, CKK_AES, sizeof(ab), &hKey); + CHECK_CKR(ret, "Concatenate to AES-192 key"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, ab, sizeof(ab)); +#endif + + if (hB != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hB); + if (hA != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hA); + + return ret; +} + +static CK_RV test_concatenate_data(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_BYTE a[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; + CK_BYTE d[4] = { 0xd0, 0xd1, 0xd2, 0xd3 }; + CK_BYTE ad[12] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xd0, 0xd1, 0xd2, 0xd3 + }; + CK_BYTE da[12] = { + 0xd0, 0xd1, 0xd2, 0xd3, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef + }; + CK_OBJECT_HANDLE hA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey; + CK_KEY_DERIVATION_STRING_DATA params = { d, sizeof(d) }; + CK_MECHANISM mech = { CKM_CONCATENATE_BASE_AND_DATA, ¶ms, + sizeof(params) }; +#ifndef NO_AES + CK_BYTE aes[16] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + CK_BYTE aesD[20]; + CK_OBJECT_HANDLE hAes = CK_INVALID_HANDLE; + CK_ATTRIBUTE aesTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &aesKeyType, sizeof(aesKeyType)}, + {CKA_SENSITIVE, &ckFalse, sizeof(ckFalse)}, + {CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_VALUE, aes, sizeof(aes)}, + }; + + XMEMCPY(aesD, aes, sizeof(aes)); + XMEMCPY(aesD + sizeof(aes), d, sizeof(d)); +#endif + + ret = concat_create_key(session, a, sizeof(a), CK_FALSE, CK_TRUE, CK_TRUE, + CK_FALSE, &hA); + CHECK_CKR(ret, "Create base key"); + if (ret == CKR_OK) { + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate base and data"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, ad, sizeof(ad)); + if (ret == CKR_OK) { + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 10, &hKey); + CHECK_CKR(ret, "Concatenate base and data, shorter length"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, ad, 10); + if (ret == CKR_OK) { + mech.mechanism = CKM_CONCATENATE_DATA_AND_BASE; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate data and base"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, da, sizeof(da)); +#ifdef WOLFPKCS11_HKDF + if (ret == CKR_OK) { + ret = concat_derive(session, &mech, hA, CKK_HKDF, 0, &hKey); + CHECK_CKR(ret, "Concatenate data and base to HKDF key"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, da, sizeof(da)); +#endif + if (ret == CKR_OK) { + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 6, &hKey); + CHECK_CKR(ret, "Concatenate data and base, shorter length"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, da, 6); + if (ret == CKR_OK) { + params.ulLen = 0; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate empty data and base"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, a, sizeof(a)); +#ifndef NO_AES + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, aesTmpl, + sizeof(aesTmpl) / sizeof(*aesTmpl), + &hAes); + CHECK_CKR(ret, "Create AES base key"); + } + if (ret == CKR_OK) { + mech.mechanism = CKM_CONCATENATE_BASE_AND_DATA; + params.ulLen = sizeof(d); + ret = concat_derive(session, &mech, hAes, CKK_GENERIC_SECRET, 0, + &hKey); + CHECK_CKR(ret, "Concatenate AES base key and data"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, aesD, sizeof(aesD)); + if (hAes != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hAes); +#endif + + if (hA != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hA); + + return ret; +} + +static CK_RV test_concatenate_protection(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_BYTE a[16] = { 0 }; + CK_ULONG genLen = 16; + CK_OBJECT_HANDLE hA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hG1 = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hG2 = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hOther = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey; + CK_MECHANISM genMech = { CKM_GENERIC_SECRET_KEY_GEN, NULL, 0 }; + CK_MECHANISM mech = { CKM_CONCATENATE_BASE_AND_KEY, &hOther, + sizeof(hOther) }; + CK_KEY_DERIVATION_STRING_DATA params = { a, sizeof(a) }; + CK_MECHANISM dataMech = { CKM_CONCATENATE_BASE_AND_DATA, ¶ms, + sizeof(params) }; + CK_ATTRIBUTE genTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_SENSITIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_VALUE_LEN, &genLen, sizeof(genLen)}, + }; + CK_ULONG genCnt = sizeof(genTmpl) / sizeof(*genTmpl); + + ret = concat_create_key(session, a, sizeof(a), CK_FALSE, CK_TRUE, CK_TRUE, + CK_FALSE, &hA); + CHECK_CKR(ret, "Create plain key"); + if (ret == CKR_OK) { + ret = funcList->C_GenerateKey(session, &genMech, genTmpl, genCnt, + &hG1); + CHECK_CKR(ret, "Generate protected key 1"); + } + if (ret == CKR_OK) { + ret = funcList->C_GenerateKey(session, &genMech, genTmpl, genCnt, + &hG2); + CHECK_CKR(ret, "Generate protected key 2"); + } + if (ret == CKR_OK) { + hOther = hG1; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate plain base and protected key"); + } + if (ret == CKR_OK) { + ret = concat_check_bools(session, hKey, CK_TRUE, CK_FALSE, CK_FALSE, + CK_FALSE); + } + if (ret == CKR_OK) { + hOther = hA; + ret = concat_derive(session, &mech, hG1, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate protected base and plain key"); + } + if (ret == CKR_OK) { + ret = concat_check_bools(session, hKey, CK_TRUE, CK_FALSE, CK_FALSE, + CK_FALSE); + } + if (ret == CKR_OK) { + hOther = hG2; + ret = concat_derive(session, &mech, hG1, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate two protected keys"); + } + if (ret == CKR_OK) { + ret = concat_check_bools(session, hKey, CK_TRUE, CK_FALSE, CK_TRUE, + CK_TRUE); + } + if (ret == CKR_OK) { + ret = concat_derive(session, &dataMech, hG1, CKK_GENERIC_SECRET, 0, + &hKey); + CHECK_CKR(ret, "Concatenate protected base and data"); + } + if (ret == CKR_OK) { + ret = concat_check_bools(session, hKey, CK_TRUE, CK_FALSE, CK_TRUE, + CK_TRUE); + } + if (ret == CKR_OK) { + dataMech.mechanism = CKM_CONCATENATE_DATA_AND_BASE; + ret = concat_derive(session, &dataMech, hG1, CKK_GENERIC_SECRET, + sizeof(a), &hKey); + CHECK_CKR(ret, "Concatenate data and protected base, data only"); + } + if (ret == CKR_OK) { + ret = concat_check_bools(session, hKey, CK_TRUE, CK_FALSE, CK_FALSE, + CK_FALSE); + } + if (ret == CKR_OK) { + ret = concat_derive(session, &dataMech, hG1, CKK_GENERIC_SECRET, + sizeof(a) + 1, &hKey); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "Concatenate data and one protected base byte"); + } + if (ret == CKR_OK) { + dataMech.mechanism = CKM_CONCATENATE_BASE_AND_DATA; + ret = concat_derive(session, &dataMech, hG1, CKK_GENERIC_SECRET, + genLen - 1, &hKey); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "Concatenate truncated protected base and data"); + } + if (ret == CKR_OK) { + hOther = hG1; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, + sizeof(a) + 1, &hKey); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "Concatenate plain base and one protected key byte"); + } + if (ret == CKR_OK) { + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, + sizeof(a) - 1, &hKey); + CHECK_CKR(ret, "Concatenate truncated plain base, protected key " + "dropped"); + } + if (ret == CKR_OK) { + ret = concat_check_bools(session, hKey, CK_TRUE, CK_FALSE, CK_FALSE, + CK_FALSE); + } + + if (hG2 != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hG2); + if (hG1 != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hG1); + if (hA != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hA); + + return ret; +} + +static CK_RV test_concatenate_errors(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_BYTE a[16] = { 0 }; + CK_OBJECT_HANDLE hA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hNoDerive = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hData = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hOther = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey; + CK_MECHANISM mech = { CKM_CONCATENATE_BASE_AND_KEY, &hOther, + sizeof(hOther) }; + CK_KEY_DERIVATION_STRING_DATA params = { NULL, 4 }; + CK_MECHANISM dataMech = { CKM_CONCATENATE_DATA_AND_BASE, ¶ms, + sizeof(params) }; + CK_MECHANISM_INFO info; + CK_ATTRIBUTE dataTmpl[] = { + {CKA_CLASS, &dataClass, sizeof(dataClass)}, + {CKA_VALUE, a, sizeof(a)}, + }; + CK_ULONG valueLen = 0; + CK_ATTRIBUTE lenTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_VALUE_LEN, &valueLen, sizeof(valueLen)}, + }; + CK_ULONG lenCnt = sizeof(lenTmpl) / sizeof(*lenTmpl); + CK_BYTE* big = NULL; + CK_ULONG maxLen = 0; + CK_OBJECT_HANDLE hBig = CK_INVALID_HANDLE; +#ifdef HAVE_ECC + CK_OBJECT_HANDLE hEcPub = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hEcPriv = CK_INVALID_HANDLE; +#endif +#ifndef NO_AES + CK_BYTE zero[24] = { 0 }; +#endif + + ret = funcList->C_GetMechanismInfo(slot, CKM_CONCATENATE_BASE_AND_KEY, + &info); + CHECK_CKR(ret, "Concatenate mechanism info"); + if (ret == CKR_OK && ((info.flags & CKF_DERIVE) == 0 || + info.ulMinKeySize != 8 || info.ulMaxKeySize % 8 != 0 || + info.ulMaxKeySize < 64 * 8)) { + ret = CKR_MECHANISM_INVALID; + CHECK_CKR(ret, "Concatenate mechanism info values"); + } + if (ret == CKR_OK) { + maxLen = info.ulMaxKeySize / 8; + big = (CK_BYTE*)XMALLOC(maxLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (big == NULL) + ret = CKR_DEVICE_MEMORY; + CHECK_CKR(ret, "Allocate maximum length data"); + } + if (ret == CKR_OK) + XMEMSET(big, 0x5a, maxLen + 1); + if (ret == CKR_OK) { + ret = concat_create_key(session, a, sizeof(a), CK_FALSE, CK_TRUE, + CK_TRUE, CK_FALSE, &hA); + CHECK_CKR(ret, "Create base key"); + } + if (ret == CKR_OK) { + ret = concat_create_key(session, a, sizeof(a), CK_FALSE, CK_TRUE, + CK_FALSE, CK_FALSE, &hNoDerive); + CHECK_CKR(ret, "Create key without derive"); + } + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, dataTmpl, + sizeof(dataTmpl) / sizeof(*dataTmpl), + &hData); + CHECK_CKR(ret, "Create data object"); + } + if (ret == CKR_OK) { + hOther = hA + 1000; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR_FAIL(ret, CKR_KEY_HANDLE_INVALID, "Unknown other key"); + } + if (ret == CKR_OK) { + hOther = hData; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR_FAIL(ret, CKR_KEY_TYPE_INCONSISTENT, "Other key is data"); + } +#ifdef HAVE_ECC + if (ret == CKR_OK) { + ret = gen_ec_keys(session, ecc_p256_params, sizeof(ecc_p256_params), + &hEcPub, &hEcPriv, NULL, 0, NULL, 0, 0); + } + if (ret == CKR_OK) { + hOther = hA; + ret = concat_derive(session, &mech, hEcPriv, CKK_GENERIC_SECRET, 0, + &hKey); + CHECK_CKR_FAIL(ret, CKR_KEY_TYPE_INCONSISTENT, "Base key is EC"); + } +#endif + if (ret == CKR_OK) { + hOther = hA; + mech.pParameter = NULL; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, "NULL parameter"); + mech.pParameter = &hOther; + } + if (ret == CKR_OK) { + valueLen = 0; + ret = funcList->C_DeriveKey(session, &mech, hA, lenTmpl, lenCnt, + &hKey); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, "Zero length"); + } + if (ret == CKR_OK) { + valueLen = 16; + lenTmpl[2].ulValueLen = sizeof(valueLen) - 1; + ret = funcList->C_DeriveKey(session, &mech, hA, lenTmpl, lenCnt, + &hKey); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, "Malformed length"); + lenTmpl[2].ulValueLen = sizeof(valueLen); + } +#if !defined(WOLFPKCS11_NSS) && !defined(WP11_NSS_PERMISSIVE_KEY_DEFAULTS) + if (ret == CKR_OK) { + hOther = hNoDerive; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR_FAIL(ret, CKR_KEY_FUNCTION_NOT_PERMITTED, + "Other key without derive"); + } +#endif + if (ret == CKR_OK) { + hOther = hA; + mech.ulParameterLen = sizeof(hOther) - 1; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, + "Bad other key parameter length"); + mech.ulParameterLen = sizeof(hOther); + } + if (ret == CKR_OK) { + ret = concat_derive(session, &dataMech, hA, CKK_GENERIC_SECRET, 0, + &hKey); + CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, "NULL data"); + } + if (ret == CKR_OK) { + params.pData = a; + dataMech.ulParameterLen = sizeof(params) - 1; + ret = concat_derive(session, &dataMech, hA, CKK_GENERIC_SECRET, 0, + &hKey); + CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, + "Bad data parameter length"); + dataMech.ulParameterLen = sizeof(params); + } + if (ret == CKR_OK) { + params.pData = big; + params.ulLen = (CK_ULONG)-1; + ret = concat_derive(session, &dataMech, hA, CKK_GENERIC_SECRET, 16, + &hKey); + CHECK_CKR_FAIL(ret, CKR_KEY_SIZE_RANGE, "Data length overflow"); + } + if (ret == CKR_OK) { + params.ulLen = maxLen + 1; + ret = concat_derive(session, &dataMech, hA, CKK_GENERIC_SECRET, 16, + &hKey); + CHECK_CKR(ret, "Data longer than a key, truncated"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, big, 16); + if (ret == CKR_OK) { + ret = concat_create_key(session, big, maxLen / 2 + 1, CK_FALSE, + CK_TRUE, CK_TRUE, CK_FALSE, &hBig); + CHECK_CKR(ret, "Create half maximum length key"); + } + if (ret == CKR_OK) { + hOther = hBig; + ret = concat_derive(session, &mech, hBig, CKK_GENERIC_SECRET, 0, + &hKey); + CHECK_CKR_FAIL(ret, CKR_KEY_SIZE_RANGE, "Two keys too long"); + } + if (ret == CKR_OK) { + params.ulLen = maxLen; + ret = concat_derive(session, &dataMech, hA, CKK_GENERIC_SECRET, 0, + &hKey); + CHECK_CKR_FAIL(ret, CKR_KEY_SIZE_RANGE, "Concatenation too long"); + } + if (ret == CKR_OK) { + ret = concat_derive(session, &dataMech, hA, CKK_GENERIC_SECRET, 32, + &hKey); + CHECK_CKR(ret, "Concatenation too long, truncated"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, big, 32); + params.pData = a; + params.ulLen = sizeof(a); +#ifndef NO_AES + if (ret == CKR_OK) { + params.ulLen = 4; + ret = concat_derive(session, &dataMech, hA, CKK_AES, 0, &hKey); + CHECK_CKR_FAIL(ret, CKR_TEMPLATE_INCOMPLETE, + "AES key without length from 20 bytes"); + } +#ifndef WOLFPKCS11_NSS + if (ret == CKR_OK) { + ret = concat_derive(session, &dataMech, hA, CKK_AES, 20, &hKey); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_VALUE_INVALID, + "AES key of 20 bytes"); + } +#endif + params.ulLen = sizeof(a); + if (ret == CKR_OK) { + ret = concat_derive(session, &dataMech, hA, CKK_AES, 24, &hKey); + CHECK_CKR(ret, "AES-192 key from 32 bytes"); + } + if (ret == CKR_OK) + ret = concat_check_value(session, hKey, zero, sizeof(zero)); +#endif + +#ifdef HAVE_ECC + if (hEcPriv != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hEcPriv); + if (hEcPub != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hEcPub); +#endif + if (hBig != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hBig); + XFREE(big, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (hData != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hData); + if (hNoDerive != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hNoDerive); + if (hA != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hA); + + return ret; +} + +static CK_RV test_concatenate_wrap_with_trusted(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_BYTE a[16] = { 0 }; + CK_BBOOL trusted; + CK_OBJECT_HANDLE hA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hT = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hOther = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey; + CK_MECHANISM mech = { CKM_CONCATENATE_BASE_AND_KEY, &hOther, + sizeof(hOther) }; + CK_KEY_DERIVATION_STRING_DATA params = { NULL, 0 }; + CK_MECHANISM dataMech = { CKM_CONCATENATE_BASE_AND_DATA, ¶ms, + sizeof(params) }; + CK_ATTRIBUTE tmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_WRAP_WITH_TRUSTED, &ckTrue, sizeof(ckTrue)}, + {CKA_VALUE, a, sizeof(a)}, + }; + CK_ATTRIBUTE attr = { CKA_WRAP_WITH_TRUSTED, &trusted, sizeof(trusted) }; + + ret = concat_create_key(session, a, sizeof(a), CK_FALSE, CK_TRUE, CK_TRUE, + CK_FALSE, &hA); + CHECK_CKR(ret, "Create plain key"); + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &hT); + CHECK_CKR(ret, "Create wrap with trusted key"); + } + if (ret == CKR_OK) { + ret = concat_derive(session, &dataMech, hT, CKK_GENERIC_SECRET, 0, + &hKey); + CHECK_CKR(ret, "Copy wrap with trusted key"); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, hKey, &attr, 1); + CHECK_CKR(ret, "Get copy wrap with trusted"); + funcList->C_DestroyObject(session, hKey); + } + CHECK_COND(ret != CKR_OK || trusted == CK_TRUE, ret, + "Copy keeps wrap with trusted"); + if (ret == CKR_OK) { + hOther = hT; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate plain key and wrap with trusted key"); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, hKey, &attr, 1); + CHECK_CKR(ret, "Get concatenation wrap with trusted"); + funcList->C_DestroyObject(session, hKey); + } + CHECK_COND(ret != CKR_OK || trusted == CK_TRUE, ret, + "Concatenation keeps wrap with trusted of other key"); + if (ret == CKR_OK) { + hOther = hA; + ret = concat_derive(session, &mech, hA, CKK_GENERIC_SECRET, 0, &hKey); + CHECK_CKR(ret, "Concatenate plain keys"); + } + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, hKey, &attr, 1); + CHECK_CKR(ret, "Get plain concatenation wrap with trusted"); + funcList->C_DestroyObject(session, hKey); + } + CHECK_COND(ret != CKR_OK || trusted == CK_FALSE, ret, + "Plain concatenation has no wrap with trusted"); + + if (hT != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hT); + if (hA != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hA); + + return ret; +} + +#ifndef WOLFPKCS11_NO_STORE +static CK_RV test_concatenate_logged_out(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_RV loginRet; + CK_BYTE a[16] = { 0 }; + CK_BYTE d[4] = { 0xd0, 0xd1, 0xd2, 0xd3 }; + CK_OBJECT_HANDLE hA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hS = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; + CK_KEY_DERIVATION_STRING_DATA params = { d, sizeof(d) }; + CK_MECHANISM mech = { CKM_CONCATENATE_BASE_AND_DATA, ¶ms, + sizeof(params) }; + CK_MECHANISM keyMech = { CKM_CONCATENATE_BASE_AND_KEY, &hA, sizeof(hA) }; + CK_ATTRIBUTE sessTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_PRIVATE, &ckFalse, sizeof(ckFalse)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_VALUE, d, sizeof(d)}, + }; + CK_ATTRIBUTE keyTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_TOKEN, &ckTrue, sizeof(ckTrue)}, + {CKA_PRIVATE, &ckFalse, sizeof(ckFalse)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_VALUE, a, sizeof(a)}, + }; + CK_ATTRIBUTE tmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_PRIVATE, &ckFalse, sizeof(ckFalse)}, + }; + + if (userPinLen == 0) + return CKR_SKIPPED; + + ret = funcList->C_CreateObject(session, keyTmpl, + sizeof(keyTmpl) / sizeof(*keyTmpl), &hA); + CHECK_CKR(ret, "Create public token key"); + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, sessTmpl, + sizeof(sessTmpl) / sizeof(*sessTmpl), + &hS); + CHECK_CKR(ret, "Create public session key"); + } + if (ret == CKR_OK) { + ret = funcList->C_Logout(session); + CHECK_CKR(ret, "Logout"); + } + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &mech, hA, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &hKey); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Concatenate encoded key after logout"); + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &keyMech, hS, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &hKey); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Concatenate encoded other key after logout"); + } + loginRet = funcList->C_Login(session, CKU_USER, userPin, userPinLen); + CHECK_CKR(loginRet, "Login again"); + if (ret == CKR_OK) + ret = loginRet; + } + + if (hKey != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hKey); + if (hS != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hS); + if (hA != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hA); + + return ret; +} +#endif + +#if defined(HAVE_ECC) && !defined(NO_SHA256) +static CK_RV stale_key_digest(CK_SESSION_HANDLE session, CK_BBOOL token) +{ + CK_RV ret; + CK_RV loginRet; + CK_OBJECT_HANDLE hEcPub = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hEcPriv = CK_INVALID_HANDLE; + CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 }; + CK_BYTE data[32]; + CK_BYTE sig[128]; + CK_ULONG sigLen; + CK_BYTE hash[WC_SHA256_DIGEST_SIZE]; + CK_ULONG hashLen; + CK_ATTRIBUTE ecPubTmpl[] = { + {CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params)}, + {CKA_VERIFY, &ckTrue, sizeof(ckTrue)}, + }; + CK_ATTRIBUTE ecPrivTmpl[] = { + {CKA_SIGN, &ckTrue, sizeof(ckTrue)}, + {CKA_TOKEN, &token, sizeof(token)}, + }; + + memset(data, 9, sizeof(data)); + + ret = funcList->C_GenerateKeyPair(session, &mech, ecPubTmpl, + sizeof(ecPubTmpl) / sizeof(*ecPubTmpl), ecPrivTmpl, + sizeof(ecPrivTmpl) / sizeof(*ecPrivTmpl), &hEcPub, &hEcPriv); + CHECK_CKR(ret, "Generate EC key pair"); + mech.mechanism = CKM_ECDSA; + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &mech, hEcPriv); + CHECK_CKR(ret, "ECDSA sign init"); + } + if (ret == CKR_OK) { + sigLen = sizeof(sig); + ret = funcList->C_Sign(session, data, sizeof(data), sig, &sigLen); + CHECK_CKR(ret, "ECDSA sign"); + } + mech.mechanism = CKM_SHA256; + if (ret == CKR_OK) { + ret = funcList->C_DigestInit(session, &mech); + CHECK_CKR(ret, "Digest init"); + } + if (ret == CKR_OK) { + ret = funcList->C_DigestUpdate(session, data, sizeof(data)); + CHECK_CKR(ret, "Digest update"); + } + if (ret == CKR_OK && token) { + ret = funcList->C_Logout(session); + CHECK_CKR(ret, "Logout during digest"); + if (ret == CKR_OK) { + ret = funcList->C_DigestInit(session, &mech); + CHECK_CKR_FAIL(ret, CKR_OPERATION_ACTIVE, + "Digest init again after logout"); + if (ret == CKR_OK) { + hashLen = sizeof(hash); + ret = funcList->C_DigestFinal(session, hash, &hashLen); + CHECK_CKR(ret, "Digest final after logout"); + } + loginRet = funcList->C_Login(session, CKU_USER, userPin, + userPinLen); + CHECK_CKR(loginRet, "Login again"); + if (ret == CKR_OK) + ret = loginRet; + } + } + else if (ret == CKR_OK) { + ret = funcList->C_DestroyObject(session, hEcPriv); + CHECK_CKR(ret, "Destroy key of completed sign during digest"); + hEcPriv = CK_INVALID_HANDLE; + if (ret == CKR_OK) { + ret = funcList->C_DigestInit(session, &mech); + CHECK_CKR_FAIL(ret, CKR_OPERATION_ACTIVE, + "Digest init again after destroy"); + } + if (ret == CKR_OK) { + hashLen = sizeof(hash); + ret = funcList->C_DigestFinal(session, hash, &hashLen); + CHECK_CKR(ret, "Digest final after destroy"); + } + } + + if (hEcPriv != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hEcPriv); + if (hEcPub != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hEcPub); + + return ret; +} + +static CK_RV test_completed_op_stale_key(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + + ret = stale_key_digest(session, CK_FALSE); +#ifndef WOLFPKCS11_NO_STORE + if (ret == CKR_OK && userPinLen != 0) + ret = stale_key_digest(session, CK_TRUE); +#endif + + return ret; +} +#endif + +#if !defined(NO_RSA) && !defined(WC_NO_RSA_OAEP) && !defined(NO_SHA256) +static CK_ATTRIBUTE oaepRsaTmpl[] = { + {CKA_CLASS, &privKeyClass, sizeof(privKeyClass)}, + {CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType)}, + {CKA_DECRYPT, &ckTrue, sizeof(ckTrue)}, + {CKA_MODULUS, rsa_2048_modulus, sizeof(rsa_2048_modulus)}, + {CKA_PRIVATE_EXPONENT, rsa_2048_priv_exp, sizeof(rsa_2048_priv_exp)}, + {CKA_PRIME_1, rsa_2048_p, sizeof(rsa_2048_p)}, + {CKA_PRIME_2, rsa_2048_q, sizeof(rsa_2048_q)}, + {CKA_EXPONENT_1, rsa_2048_dP, sizeof(rsa_2048_dP)}, + {CKA_EXPONENT_2, rsa_2048_dQ, sizeof(rsa_2048_dQ)}, + {CKA_COEFFICIENT, rsa_2048_u, sizeof(rsa_2048_u)}, + {CKA_PUBLIC_EXPONENT, rsa_2048_pub_exp, sizeof(rsa_2048_pub_exp)}, + {CKA_TOKEN, &ckTrue, sizeof(ckTrue)}, +}; +#define OAEP_RSA_TMPL_CNT (sizeof(oaepRsaTmpl) / sizeof(*oaepRsaTmpl)) + +static CK_RV test_oaep_failed_decrypt(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_OBJECT_HANDLE hRsa = CK_INVALID_HANDLE; + CK_BYTE label[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + CK_BYTE enc[256]; + CK_BYTE dec[256]; + CK_ULONG decLen = sizeof(dec); + CK_RSA_PKCS_OAEP_PARAMS oaep; + CK_MECHANISM mech = { CKM_RSA_PKCS_OAEP, &oaep, sizeof(oaep) }; + CK_MECHANISM pkcsMech = { CKM_RSA_PKCS, NULL, 0 }; + + XMEMSET(enc, 0, sizeof(enc)); + oaep.hashAlg = CKM_SHA256; + oaep.mgf = CKG_MGF1_SHA256; + oaep.source = CKZ_DATA_SPECIFIED; + oaep.pSourceData = label; + oaep.ulSourceDataLen = sizeof(label); + + ret = funcList->C_CreateObject(session, oaepRsaTmpl, OAEP_RSA_TMPL_CNT - 1, + &hRsa); + CHECK_CKR(ret, "Create session RSA private key"); + if (ret == CKR_OK) { + ret = funcList->C_DecryptInit(session, &mech, hRsa); + CHECK_CKR(ret, "RSA-OAEP decrypt init"); + } + if (ret == CKR_OK) { + ret = funcList->C_Decrypt(session, enc, sizeof(enc), dec, &decLen); + CHECK_CKR_FAIL(ret, CKR_ENCRYPTED_DATA_INVALID, + "RSA-OAEP decrypt of invalid data"); + } + if (ret == CKR_OK) { + ret = funcList->C_DecryptInit(session, &pkcsMech, hRsa); + CHECK_CKR(ret, "RSA decrypt init after failed RSA-OAEP decrypt"); + } + if (ret == CKR_OK) { + decLen = sizeof(dec); + ret = funcList->C_Decrypt(session, enc, sizeof(enc), dec, &decLen); + CHECK_CKR_FAIL(ret, CKR_ENCRYPTED_DATA_INVALID, + "RSA decrypt of invalid data"); + } + + if (hRsa != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hRsa); + + return ret; +} + +static CK_RV test_oaep_key_destroyed(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_SESSION_HANDLE other = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hRsa = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hRsaSess = CK_INVALID_HANDLE; + CK_BYTE label[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + CK_BYTE enc[256]; + CK_BYTE dec[256]; + CK_ULONG decLen = sizeof(dec); + CK_RSA_PKCS_OAEP_PARAMS oaep; + CK_MECHANISM mech = { CKM_RSA_PKCS_OAEP, &oaep, sizeof(oaep) }; + + XMEMSET(enc, 0, sizeof(enc)); + oaep.hashAlg = CKM_SHA256; + oaep.mgf = CKG_MGF1_SHA256; + oaep.source = CKZ_DATA_SPECIFIED; + oaep.pSourceData = label; + oaep.ulSourceDataLen = sizeof(label); + + ret = funcList->C_CreateObject(session, oaepRsaTmpl, OAEP_RSA_TMPL_CNT, + &hRsa); + CHECK_CKR(ret, "Create token RSA private key"); + if (ret == CKR_OK) { + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &other); + CHECK_CKR(ret, "Open second session"); + } + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(other, oaepRsaTmpl, + OAEP_RSA_TMPL_CNT - 1, &hRsaSess); + CHECK_CKR(ret, "Create session RSA private key"); + } + if (ret == CKR_OK) { + ret = funcList->C_DecryptInit(other, &mech, hRsa); + CHECK_CKR(ret, "RSA-OAEP decrypt init"); + } + if (ret == CKR_OK) { + ret = funcList->C_DestroyObject(session, hRsa); + CHECK_CKR(ret, "Destroy key from another session"); + if (ret == CKR_OK) + hRsa = CK_INVALID_HANDLE; + } + if (ret == CKR_OK) { + ret = funcList->C_Decrypt(other, enc, sizeof(enc), dec, &decLen); + CHECK_CKR_FAIL(ret, CKR_OPERATION_NOT_INITIALIZED, + "RSA-OAEP decrypt after key destroyed"); + } + if (ret == CKR_OK) { + ret = funcList->C_DecryptInit(other, &mech, hRsaSess); + CHECK_CKR(ret, "RSA-OAEP decrypt init after key destroyed"); + } + + if (other != CK_INVALID_HANDLE) + funcList->C_CloseSession(other); + if (hRsa != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hRsa); + + return ret; +} +#endif + +#ifndef WOLFPKCS11_NO_STORE +static CK_RV test_key_use_logged_out(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_RV loginRet; + int loggedOut = 0; + CK_BYTE macKey[32]; + CK_OBJECT_HANDLE hTok = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hSess = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hAes = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hAesSess = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hEcPub = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hEcPriv = CK_INVALID_HANDLE; +#if !defined(NO_RSA) && !defined(WC_NO_RSA_OAEP) && !defined(NO_SHA256) + CK_OBJECT_HANDLE hRsa = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hRsaSess = CK_INVALID_HANDLE; + CK_SESSION_HANDLE oaepSession = CK_INVALID_HANDLE; + CK_BYTE label[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + CK_RSA_PKCS_OAEP_PARAMS oaep; + CK_ATTRIBUTE_TYPE rsaAttrs[] = { + CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_MODULUS_BITS + }; + int i; + CK_ATTRIBUTE rsaTmpl[] = { + {CKA_CLASS, &privKeyClass, sizeof(privKeyClass)}, + {CKA_KEY_TYPE, &rsaKeyType, sizeof(rsaKeyType)}, + {CKA_PRIVATE, &ckFalse, sizeof(ckFalse)}, + {CKA_DECRYPT, &ckTrue, sizeof(ckTrue)}, + {CKA_MODULUS, rsa_2048_modulus, sizeof(rsa_2048_modulus)}, + {CKA_PRIVATE_EXPONENT, rsa_2048_priv_exp, sizeof(rsa_2048_priv_exp)}, + {CKA_PRIME_1, rsa_2048_p, sizeof(rsa_2048_p)}, + {CKA_PRIME_2, rsa_2048_q, sizeof(rsa_2048_q)}, + {CKA_EXPONENT_1, rsa_2048_dP, sizeof(rsa_2048_dP)}, + {CKA_EXPONENT_2, rsa_2048_dQ, sizeof(rsa_2048_dQ)}, + {CKA_COEFFICIENT, rsa_2048_u, sizeof(rsa_2048_u)}, + {CKA_PUBLIC_EXPONENT, rsa_2048_pub_exp, sizeof(rsa_2048_pub_exp)}, + {CKA_TOKEN, &ckTrue, sizeof(ckTrue)}, + }; + CK_ULONG rsaCnt = sizeof(rsaTmpl) / sizeof(*rsaTmpl); +#endif +#ifndef NO_DH + CK_OBJECT_HANDLE hDh = CK_INVALID_HANDLE; + CK_BYTE prime[sizeof(dh_ffdhe2048_p)]; + CK_ATTRIBUTE primeTmpl = { CKA_PRIME, prime, sizeof(prime) }; + CK_ATTRIBUTE dhTmpl[] = { + {CKA_CLASS, &privKeyClass, sizeof(privKeyClass)}, + {CKA_KEY_TYPE, &dhKeyType, sizeof(dhKeyType)}, + {CKA_PRIVATE, &ckFalse, sizeof(ckFalse)}, + {CKA_SENSITIVE, &ckFalse, sizeof(ckFalse)}, + {CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_PRIME, dh_ffdhe2048_p, sizeof(dh_ffdhe2048_p)}, + {CKA_BASE, dh_ffdhe2048_g, sizeof(dh_ffdhe2048_g)}, + {CKA_VALUE, dh_2048_priv, sizeof(dh_2048_priv)}, + {CKA_TOKEN, &ckTrue, sizeof(ckTrue)}, + }; +#endif + CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hCopy = CK_INVALID_HANDLE; + CK_MECHANISM mech; + CK_BYTE value[32]; + CK_ATTRIBUTE getTmpl = { CKA_VALUE, value, sizeof(value) }; + CK_ULONG valueLen = 0; + CK_ATTRIBUTE lenTmpl = { CKA_VALUE_LEN, &valueLen, sizeof(valueLen) }; +#if defined(HAVE_ECC) || defined(HAVE_AES_CBC) || defined(HAVE_AESGCM) || \ + defined(WOLFSSL_HAVE_PRF) || defined(HAVE_AESECB) + CK_BYTE in[16] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; + CK_BYTE out[128]; + CK_ULONG outSz; +#endif +#ifndef NO_HMAC + CK_BYTE data[16] = { 0 }; + CK_BYTE mac[WC_SHA256_DIGEST_SIZE]; + CK_BYTE macSess[WC_SHA256_DIGEST_SIZE]; + CK_ULONG macLen; +#endif +#ifdef HAVE_AES_CBC + CK_BYTE iv[16] = { 0 }; + CK_BYTE cbcOut[16]; + CK_BYTE cbcSessOut[16]; + CK_SESSION_HANDLE cbcSession = CK_INVALID_HANDLE; +#endif +#ifdef HAVE_AESECB + CK_SESSION_HANDLE ecbSession = CK_INVALID_HANDLE; +#endif +#ifdef HAVE_AESGCM + CK_BYTE gcmIv[12] = { 0 }; + CK_GCM_PARAMS gcm; + CK_SESSION_HANDLE gcmSession = CK_INVALID_HANDLE; +#endif +#if defined(WOLFSSL_HAVE_PRF) && !defined(NO_SHA256) + CK_TLS_MAC_PARAMS tlsMac; + CK_SESSION_HANDLE tlsSession = CK_INVALID_HANDLE; +#endif +#if defined(WOLFPKCS11_NSS) && defined(WOLFSSL_HAVE_PRF) + CK_SESSION_HANDLE prfSession = CK_INVALID_HANDLE; +#endif +#ifdef HAVE_AES_KEYWRAP + CK_BYTE wrapped[40]; + CK_ULONG wrappedLen; + CK_ULONG unwrapLen = 16; + CK_ATTRIBUTE unwrapTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_VALUE_LEN, &unwrapLen, sizeof(unwrapLen)}, + }; +#endif +#if !defined(NO_DH) || defined(HAVE_ECC) + CK_ULONG deriveLen = 32; + CK_ATTRIBUTE deriveTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_VALUE_LEN, &deriveLen, sizeof(deriveLen)}, + }; +#endif +#ifndef NO_DH + CK_BYTE dhPeer[sizeof(dh_ffdhe2048_p)]; +#endif +#ifdef HAVE_ECC + CK_ECDH1_DERIVE_PARAMS ecdh; +#endif +#ifdef WOLFPKCS11_HKDF + CK_HKDF_PARAMS hkdf; + CK_ULONG outLen = 32; + CK_ATTRIBUTE outTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_PRIVATE, &ckFalse, sizeof(ckFalse)}, + {CKA_VALUE_LEN, &outLen, sizeof(outLen)}, + }; +#endif +#ifndef NO_SHA256 + CK_BYTE hash[WC_SHA256_DIGEST_SIZE]; + CK_ULONG hashLen; +#endif + CK_ATTRIBUTE tokTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_PRIVATE, &ckFalse, sizeof(ckFalse)}, + {CKA_SIGN, &ckTrue, sizeof(ckTrue)}, + {CKA_VERIFY, &ckTrue, sizeof(ckTrue)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_VALUE, macKey, sizeof(macKey)}, + {CKA_TOKEN, &ckTrue, sizeof(ckTrue)}, + }; + CK_ULONG tokCnt = sizeof(tokTmpl) / sizeof(*tokTmpl); + CK_ATTRIBUTE aesTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &aesKeyType, sizeof(aesKeyType)}, + {CKA_PRIVATE, &ckFalse, sizeof(ckFalse)}, + {CKA_ENCRYPT, &ckTrue, sizeof(ckTrue)}, + {CKA_DECRYPT, &ckTrue, sizeof(ckTrue)}, + {CKA_WRAP, &ckTrue, sizeof(ckTrue)}, + {CKA_UNWRAP, &ckTrue, sizeof(ckTrue)}, + {CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue)}, + {CKA_SENSITIVE, &ckFalse, sizeof(ckFalse)}, + {CKA_VALUE, aes_128_key, sizeof(aes_128_key)}, + {CKA_TOKEN, &ckTrue, sizeof(ckTrue)}, + }; + CK_ULONG aesCnt = sizeof(aesTmpl) / sizeof(*aesTmpl); +#ifdef HAVE_ECC + CK_ATTRIBUTE ecPubTmpl[] = { + {CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params)}, + {CKA_VERIFY, &ckTrue, sizeof(ckTrue)}, + }; + CK_ATTRIBUTE ecPrivTmpl[] = { + {CKA_SIGN, &ckTrue, sizeof(ckTrue)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_PRIVATE, &ckFalse, sizeof(ckFalse)}, + {CKA_SENSITIVE, &ckFalse, sizeof(ckFalse)}, + {CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue)}, + {CKA_TOKEN, &ckTrue, sizeof(ckTrue)}, + }; +#endif + + if (userPinLen == 0) + return CKR_SKIPPED; + + memset(macKey, 0x5a, sizeof(macKey)); + + ret = funcList->C_CreateObject(session, tokTmpl, tokCnt, &hTok); + CHECK_CKR(ret, "Create public token secret key"); + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, tokTmpl, tokCnt - 1, &hSess); + CHECK_CKR(ret, "Create public session secret key"); + } + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, aesTmpl, aesCnt, &hAes); + CHECK_CKR(ret, "Create public token AES key"); + } + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, aesTmpl, aesCnt - 1, + &hAesSess); + CHECK_CKR(ret, "Create public session AES key"); + } +#if !defined(NO_RSA) && !defined(WC_NO_RSA_OAEP) && !defined(NO_SHA256) + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, rsaTmpl, rsaCnt, &hRsa); + CHECK_CKR(ret, "Create public token RSA private key"); + } +#endif +#ifndef NO_DH + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(session, dhTmpl, + sizeof(dhTmpl) / sizeof(*dhTmpl), &hDh); + CHECK_CKR(ret, "Create public token DH private key"); + } +#endif +#ifdef HAVE_ECC + if (ret == CKR_OK) { + mech.mechanism = CKM_EC_KEY_PAIR_GEN; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + ret = funcList->C_GenerateKeyPair(session, &mech, ecPubTmpl, + sizeof(ecPubTmpl) / sizeof(*ecPubTmpl), ecPrivTmpl, + sizeof(ecPrivTmpl) / sizeof(*ecPrivTmpl), &hEcPub, &hEcPriv); + CHECK_CKR(ret, "Generate public token EC private key"); + } + mech.mechanism = CKM_ECDSA; + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &mech, hEcPriv); + CHECK_CKR(ret, "ECDSA sign init before logout"); + } +#endif +#ifdef HAVE_AES_CBC + mech.mechanism = CKM_AES_CBC; + mech.pParameter = iv; + mech.ulParameterLen = sizeof(iv); + if (ret == CKR_OK) { + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &cbcSession); + CHECK_CKR(ret, "Open session for AES-CBC"); + } + if (ret == CKR_OK) { + ret = funcList->C_EncryptInit(cbcSession, &mech, hAes); + CHECK_CKR(ret, "AES-CBC encrypt init before logout"); + } +#endif +#ifdef HAVE_AESGCM + XMEMSET(&gcm, 0, sizeof(gcm)); + gcm.pIv = gcmIv; + gcm.ulIvLen = sizeof(gcmIv); + gcm.ulTagBits = 128; + mech.mechanism = CKM_AES_GCM; + mech.pParameter = &gcm; + mech.ulParameterLen = sizeof(gcm); + if (ret == CKR_OK) { + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &gcmSession); + CHECK_CKR(ret, "Open session for AES-GCM"); + } + if (ret == CKR_OK) { + ret = funcList->C_EncryptInit(gcmSession, &mech, hAes); + CHECK_CKR(ret, "AES-GCM encrypt init before logout"); + } +#endif +#ifdef HAVE_AESECB + mech.mechanism = CKM_AES_ECB; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + if (ret == CKR_OK) { + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &ecbSession); + CHECK_CKR(ret, "Open session for AES-ECB"); + } + if (ret == CKR_OK) { + ret = funcList->C_EncryptInit(ecbSession, &mech, hAes); + CHECK_CKR(ret, "AES-ECB encrypt init before logout"); + } +#endif +#if defined(WOLFSSL_HAVE_PRF) && !defined(NO_SHA256) + tlsMac.prfHashMechanism = CKM_SHA256; + tlsMac.ulMacLength = 12; + tlsMac.ulServerOrClient = 1; + mech.mechanism = CKM_TLS_MAC; + mech.pParameter = &tlsMac; + mech.ulParameterLen = sizeof(tlsMac); + if (ret == CKR_OK) { + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &tlsSession); + CHECK_CKR(ret, "Open session for TLS MAC"); + } + if (ret == CKR_OK) { + ret = funcList->C_SignInit(tlsSession, &mech, hTok); + CHECK_CKR(ret, "TLS MAC sign init before logout"); + } +#endif +#if !defined(NO_RSA) && !defined(WC_NO_RSA_OAEP) && !defined(NO_SHA256) + oaep.hashAlg = CKM_SHA256; + oaep.mgf = CKG_MGF1_SHA256; + oaep.source = CKZ_DATA_SPECIFIED; + oaep.pSourceData = label; + oaep.ulSourceDataLen = sizeof(label); + mech.mechanism = CKM_RSA_PKCS_OAEP; + mech.pParameter = &oaep; + mech.ulParameterLen = sizeof(oaep); + if (ret == CKR_OK) { + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &oaepSession); + CHECK_CKR(ret, "Open session for RSA-OAEP"); + } + if (ret == CKR_OK) { + ret = funcList->C_CreateObject(oaepSession, rsaTmpl, rsaCnt - 1, + &hRsaSess); + CHECK_CKR(ret, "Create public session RSA private key"); + } + if (ret == CKR_OK) { + ret = funcList->C_DecryptInit(oaepSession, &mech, hRsa); + CHECK_CKR(ret, "RSA-OAEP decrypt init before logout"); + } +#endif +#if defined(WOLFPKCS11_NSS) && defined(WOLFSSL_HAVE_PRF) + mech.mechanism = CKM_NSS_TLS_PRF_GENERAL_SHA256; + mech.pParameter = NULL; + mech.ulParameterLen = 0; + if (ret == CKR_OK) { + ret = funcList->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, + NULL, NULL, &prfSession); + CHECK_CKR(ret, "Open session for NSS TLS PRF"); + } + if (ret == CKR_OK) { + ret = funcList->C_SignInit(prfSession, &mech, hTok); + CHECK_CKR(ret, "NSS TLS PRF sign init before logout"); + } +#endif + if (ret == CKR_OK) { + ret = funcList->C_Logout(session); + CHECK_CKR(ret, "Logout"); + loggedOut = (ret == CKR_OK); + } +#ifdef HAVE_ECC + if (ret == CKR_OK) { + outSz = sizeof(out); + ret = funcList->C_Sign(session, in, sizeof(in), out, &outSz); + CHECK_CKR_FAIL(ret, CKR_OPERATION_NOT_INITIALIZED, + "ECDSA sign started before logout"); + } +#endif +#ifdef HAVE_AES_CBC + if (ret == CKR_OK) { + outSz = sizeof(cbcOut); + ret = funcList->C_Encrypt(cbcSession, in, sizeof(in), cbcOut, &outSz); + CHECK_CKR(ret, "AES-CBC encrypt started before logout"); + } +#endif +#ifdef HAVE_AESGCM + if (ret == CKR_OK) { + outSz = sizeof(out); + ret = funcList->C_Encrypt(gcmSession, in, sizeof(in), out, &outSz); + CHECK_CKR_FAIL(ret, CKR_OPERATION_NOT_INITIALIZED, + "AES-GCM encrypt started before logout"); + } +#endif +#ifdef HAVE_AESECB + if (ret == CKR_OK) { + outSz = sizeof(out); + ret = funcList->C_Encrypt(ecbSession, in, sizeof(in), out, &outSz); + CHECK_CKR_FAIL(ret, CKR_OPERATION_NOT_INITIALIZED, + "AES-ECB encrypt started before logout"); + } +#endif +#if defined(WOLFSSL_HAVE_PRF) && !defined(NO_SHA256) + if (ret == CKR_OK) { + outSz = sizeof(out); + ret = funcList->C_Sign(tlsSession, in, sizeof(in), out, &outSz); + CHECK_CKR_FAIL(ret, CKR_OPERATION_NOT_INITIALIZED, + "TLS MAC sign started before logout"); + } +#endif +#if defined(WOLFPKCS11_NSS) && defined(WOLFSSL_HAVE_PRF) + if (ret == CKR_OK) { + outSz = sizeof(out); + ret = funcList->C_Sign(prfSession, in, sizeof(in), out, &outSz); + CHECK_CKR_FAIL(ret, CKR_OPERATION_NOT_INITIALIZED, + "NSS TLS PRF sign started before logout"); + } +#endif +#if !defined(NO_RSA) && !defined(WC_NO_RSA_OAEP) && !defined(NO_SHA256) + mech.mechanism = CKM_RSA_PKCS_OAEP; + mech.pParameter = &oaep; + mech.ulParameterLen = sizeof(oaep); + if (ret == CKR_OK) { + ret = funcList->C_DecryptInit(oaepSession, &mech, hRsaSess); + CHECK_CKR(ret, "RSA-OAEP decrypt init after logout"); + } + for (i = 0; ret == CKR_OK && i < (int)(sizeof(rsaAttrs) / + sizeof(*rsaAttrs)); i++) { + getTmpl.type = rsaAttrs[i]; + getTmpl.ulValueLen = sizeof(value); + ret = funcList->C_GetAttributeValue(session, hRsa, &getTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Get RSA key attribute after logout"); + } +#endif + if (ret == CKR_OK) { + getTmpl.type = CKA_VALUE; + getTmpl.ulValueLen = sizeof(value); + ret = funcList->C_GetAttributeValue(session, hAes, &getTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Get token key value after logout"); + } + CHECK_COND(ret != CKR_OK || + getTmpl.ulValueLen == CK_UNAVAILABLE_INFORMATION, ret, + "Token key value unavailable after logout"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, hAes, &lenTmpl, 1); + CHECK_CKR(ret, "Get token key length after logout"); + } + CHECK_COND(ret != CKR_OK || valueLen == sizeof(aes_128_key), ret, + "Token key length after logout"); + if (ret == CKR_OK) { + getTmpl.type = CKA_MODULUS; + getTmpl.ulValueLen = sizeof(value); + ret = funcList->C_GetAttributeValue(session, hAes, &getTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_TYPE_INVALID, + "Get modulus of token AES key after logout"); + } +#ifdef HAVE_ECC + if (ret == CKR_OK) { + getTmpl.type = CKA_EC_PARAMS; + getTmpl.ulValueLen = sizeof(value); + ret = funcList->C_GetAttributeValue(session, hEcPriv, &getTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Get EC parameters of token private key after logout"); + } + if (ret == CKR_OK) { + getTmpl.type = CKA_VALUE; + getTmpl.ulValueLen = sizeof(value); + ret = funcList->C_GetAttributeValue(session, hEcPriv, &getTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Get value of token EC private key after logout"); + } + if (ret == CKR_OK) { + getTmpl.type = CKA_EC_POINT; + getTmpl.ulValueLen = sizeof(value); + ret = funcList->C_GetAttributeValue(session, hEcPriv, &getTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Get EC point of token private key after logout"); + } + if (ret == CKR_OK) { + getTmpl.type = CKA_MODULUS; + getTmpl.ulValueLen = sizeof(value); + ret = funcList->C_GetAttributeValue(session, hEcPriv, &getTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_TYPE_INVALID, + "Get modulus of token EC private key after logout"); + } +#endif +#ifndef NO_DH + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, hDh, &primeTmpl, 1); + CHECK_CKR(ret, "Get DH prime after logout"); + } + CHECK_COND(ret != CKR_OK || (primeTmpl.ulValueLen == sizeof(prime) && + XMEMCMP(prime, dh_ffdhe2048_p, sizeof(prime)) == 0), ret, + "DH prime after logout"); + if (ret == CKR_OK) { + getTmpl.type = CKA_VALUE; + getTmpl.ulValueLen = sizeof(value); + ret = funcList->C_GetAttributeValue(session, hDh, &getTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Get DH private value after logout"); + } +#endif +#ifndef NO_SHA + if (ret == CKR_OK) { + getTmpl.type = CKA_CHECK_VALUE; + getTmpl.ulValueLen = sizeof(value); + ret = funcList->C_GetAttributeValue(session, hTok, &getTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Get token key check value after logout"); + } +#endif + if (ret == CKR_OK) { + ret = funcList->C_CopyObject(session, hAes, NULL, 0, &hCopy); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Copy token key after logout"); + } + + mech.pParameter = NULL; + mech.ulParameterLen = 0; +#ifndef NO_HMAC + mech.mechanism = CKM_SHA256_HMAC; + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &mech, hTok); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, "HMAC sign after logout"); + } + if (ret == CKR_OK) { + ret = funcList->C_VerifyInit(session, &mech, hTok); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "HMAC verify after logout"); + } +#endif +#ifdef HAVE_AES_CBC + mech.mechanism = CKM_AES_CBC; + mech.pParameter = iv; + mech.ulParameterLen = sizeof(iv); + if (ret == CKR_OK) { + ret = funcList->C_EncryptInit(session, &mech, hAes); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "AES encrypt after logout"); + } + if (ret == CKR_OK) { + ret = funcList->C_DecryptInit(session, &mech, hAes); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "AES decrypt after logout"); + } + mech.pParameter = NULL; + mech.ulParameterLen = 0; +#endif +#ifdef HAVE_AES_KEYWRAP + mech.mechanism = CKM_AES_KEY_WRAP; + if (ret == CKR_OK) { + wrappedLen = sizeof(wrapped); + ret = funcList->C_WrapKey(session, &mech, hAes, hAesSess, wrapped, + &wrappedLen); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Wrap with token key after logout"); + } + if (ret == CKR_OK) { + wrappedLen = sizeof(wrapped); + ret = funcList->C_WrapKey(session, &mech, hAesSess, hAes, wrapped, + &wrappedLen); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Wrap token key after logout"); + } + if (ret == CKR_OK) { + XMEMSET(wrapped, 0, sizeof(wrapped)); + ret = funcList->C_UnwrapKey(session, &mech, hAes, wrapped, 24, + unwrapTmpl, + sizeof(unwrapTmpl) / sizeof(*unwrapTmpl), + &hKey); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Unwrap with token key after logout"); + } +#endif +#ifdef WOLFPKCS11_HKDF + XMEMSET(&hkdf, 0, sizeof(hkdf)); + hkdf.bExtract = CK_TRUE; + hkdf.prfHashMechanism = CKM_SHA256_HMAC; + hkdf.ulSaltType = CKF_HKDF_SALT_NULL; + mech.mechanism = CKM_HKDF_DERIVE; + mech.pParameter = &hkdf; + mech.ulParameterLen = sizeof(hkdf); + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &mech, hTok, outTmpl, + sizeof(outTmpl) / sizeof(*outTmpl), &hKey); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "HKDF from token key after logout"); + } + if (ret == CKR_OK) { + hkdf.ulSaltType = CKF_HKDF_SALT_KEY; + hkdf.hSaltKey = hTok; + ret = funcList->C_DeriveKey(session, &mech, hSess, outTmpl, + sizeof(outTmpl) / sizeof(*outTmpl), &hKey); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "HKDF with token salt key after logout"); + } +#ifdef HAVE_ECC + if (ret == CKR_OK) { + hkdf.hSaltKey = hEcPriv; + ret = funcList->C_DeriveKey(session, &mech, hSess, outTmpl, + sizeof(outTmpl) / sizeof(*outTmpl), &hKey); + CHECK_CKR_FAIL(ret, CKR_MECHANISM_PARAM_INVALID, + "HKDF with private key salt after logout"); + } +#endif + mech.pParameter = NULL; + mech.ulParameterLen = 0; +#endif +#ifdef HAVE_ECC + mech.mechanism = CKM_ECDSA; + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &mech, hEcPriv); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "ECDSA sign after logout"); + } + XMEMSET(&ecdh, 0, sizeof(ecdh)); + ecdh.kdf = CKD_NULL; + ecdh.pPublicData = ecc_p256_point; + ecdh.ulPublicDataLen = sizeof(ecc_p256_point); + mech.mechanism = CKM_ECDH1_DERIVE; + mech.pParameter = &ecdh; + mech.ulParameterLen = sizeof(ecdh); + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &mech, hEcPriv, deriveTmpl, + sizeof(deriveTmpl) / sizeof(*deriveTmpl), + &hKey); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, "ECDH after logout"); + } + mech.pParameter = NULL; + mech.ulParameterLen = 0; +#endif +#ifndef NO_DH + XMEMSET(dhPeer, 0x07, sizeof(dhPeer)); + mech.mechanism = CKM_DH_PKCS_DERIVE; + mech.pParameter = dhPeer; + mech.ulParameterLen = sizeof(dhPeer); + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &mech, hDh, deriveTmpl, + sizeof(deriveTmpl) / sizeof(*deriveTmpl), + &hKey); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, "DH derive after logout"); + } + mech.pParameter = NULL; + mech.ulParameterLen = 0; +#endif +#ifndef NO_HMAC + mech.mechanism = CKM_SHA256_HMAC; + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &mech, hAes); + CHECK_CKR_FAIL(ret, CKR_KEY_FUNCTION_NOT_PERMITTED, + "Sign with token key lacking CKA_SIGN after logout"); + } +#endif +#ifndef NO_SHA256 + mech.mechanism = CKM_SHA256; + if (ret == CKR_OK) { + ret = funcList->C_DigestInit(session, &mech); + CHECK_CKR(ret, "Digest init after logout"); + } + if (ret == CKR_OK) { + ret = funcList->C_DigestKey(session, hTok); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Digest token key after logout"); + } + if (ret == CKR_OK) { + ret = funcList->C_DigestInit(session, &mech); + CHECK_CKR(ret, "Digest init after failed digest key"); + } + if (ret == CKR_OK) { + hashLen = sizeof(hash); + ret = funcList->C_DigestFinal(session, hash, &hashLen); + CHECK_CKR(ret, "Digest final"); + } +#endif + + if (loggedOut) { + loginRet = funcList->C_Login(session, CKU_USER, userPin, userPinLen); + CHECK_CKR(loginRet, "Login again"); + if (ret == CKR_OK) + ret = loginRet; + } + +#ifndef NO_HMAC + mech.mechanism = CKM_SHA256_HMAC; + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &mech, hTok); + CHECK_CKR(ret, "HMAC sign init after login"); + } + if (ret == CKR_OK) { + macLen = sizeof(mac); + ret = funcList->C_Sign(session, data, sizeof(data), mac, &macLen); + CHECK_CKR(ret, "HMAC sign with token key"); + } + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &mech, hSess); + CHECK_CKR(ret, "HMAC sign init with session key"); + } + if (ret == CKR_OK) { + macLen = sizeof(macSess); + ret = funcList->C_Sign(session, data, sizeof(data), macSess, &macLen); + CHECK_CKR(ret, "HMAC sign with session key"); + } + CHECK_COND(ret != CKR_OK || XMEMCMP(mac, macSess, sizeof(mac)) == 0, ret, + "Token key decoded after login"); +#endif +#ifdef HAVE_AES_CBC + mech.mechanism = CKM_AES_CBC; + mech.pParameter = iv; + mech.ulParameterLen = sizeof(iv); + if (ret == CKR_OK) { + ret = funcList->C_EncryptInit(session, &mech, hAesSess); + CHECK_CKR(ret, "AES-CBC encrypt init with session key"); + } + if (ret == CKR_OK) { + outSz = sizeof(cbcSessOut); + ret = funcList->C_Encrypt(session, in, sizeof(in), cbcSessOut, &outSz); + CHECK_CKR(ret, "AES-CBC encrypt with session key"); + } + CHECK_COND(ret != CKR_OK || + XMEMCMP(cbcOut, cbcSessOut, sizeof(cbcOut)) == 0, ret, + "AES-CBC across logout used the key value"); + if (cbcSession != CK_INVALID_HANDLE) + funcList->C_CloseSession(cbcSession); +#endif +#ifdef HAVE_AESGCM + if (gcmSession != CK_INVALID_HANDLE) + funcList->C_CloseSession(gcmSession); +#endif +#ifdef HAVE_AESECB + if (ecbSession != CK_INVALID_HANDLE) + funcList->C_CloseSession(ecbSession); +#endif +#if defined(WOLFSSL_HAVE_PRF) && !defined(NO_SHA256) + if (tlsSession != CK_INVALID_HANDLE) + funcList->C_CloseSession(tlsSession); +#endif +#if !defined(NO_RSA) && !defined(WC_NO_RSA_OAEP) && !defined(NO_SHA256) + if (oaepSession != CK_INVALID_HANDLE) + funcList->C_CloseSession(oaepSession); + if (hRsa != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hRsa); +#endif +#if defined(WOLFPKCS11_NSS) && defined(WOLFSSL_HAVE_PRF) + if (prfSession != CK_INVALID_HANDLE) + funcList->C_CloseSession(prfSession); +#endif + + if (hCopy != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hCopy); + if (hKey != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hKey); +#ifndef NO_DH + if (hDh != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hDh); +#endif + if (hEcPriv != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hEcPriv); + if (hEcPub != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hEcPub); + if (hAesSess != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hAesSess); + if (hAes != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hAes); + if (hSess != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hSess); + if (hTok != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hTok); + + return ret; +} +#endif + +#if defined(HAVE_ECC) && (defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)) && \ + !defined(NO_AES) && !defined(WOLFPKCS11_NSS) +static CK_RV test_ecdh_derive_aes_no_value_len(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_BYTE p384Params[] = { 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22 }; + CK_OBJECT_HANDLE hPub = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hPriv = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; + CK_BYTE point[128]; + CK_ATTRIBUTE pointAttr = { CKA_EC_POINT, point, sizeof(point) }; + CK_ECDH1_DERIVE_PARAMS params; + CK_MECHANISM mech = { CKM_ECDH1_DERIVE, ¶ms, sizeof(params) }; + CK_ULONG valueLen = 32; + CK_ATTRIBUTE tmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &aesKeyType, sizeof(aesKeyType)}, + {CKA_VALUE_LEN, &valueLen, sizeof(valueLen)}, + }; + CK_ULONG cnt = sizeof(tmpl) / sizeof(*tmpl); + + ret = gen_ec_keys(session, p384Params, sizeof(p384Params), &hPub, &hPriv, + NULL, 0, NULL, 0, 0); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, hPub, &pointAttr, 1); + CHECK_CKR(ret, "Get P-384 point"); + } + if (ret == CKR_OK) { + params.kdf = CKD_NULL; + params.pSharedData = NULL; + params.ulSharedDataLen = 0; + params.pPublicData = point; + params.ulPublicDataLen = pointAttr.ulValueLen; + ret = funcList->C_DeriveKey(session, &mech, hPriv, tmpl, cnt - 1, + &hKey); + CHECK_CKR_FAIL(ret, CKR_TEMPLATE_INCOMPLETE, + "AES key without length from P-384 secret"); + } + if (ret == CKR_OK) { + tmpl[2].ulValueLen = sizeof(valueLen) - 1; + ret = funcList->C_DeriveKey(session, &mech, hPriv, tmpl, cnt, &hKey); + CHECK_CKR_FAIL(ret, CKR_BUFFER_TOO_SMALL, + "AES key with short length from P-384 secret"); + tmpl[2].ulValueLen = sizeof(valueLen); + } + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &mech, hPriv, tmpl, cnt, &hKey); + CHECK_CKR(ret, "AES-256 key from P-384 secret"); + } + + if (hKey != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hKey); + if (hPriv != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hPriv); + if (hPub != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hPub); + + return ret; +} +#endif + +#if defined(WOLFPKCS11_HKDF) && defined(WOLFSSL_SHA384) && !defined(NO_AES) && \ + !defined(WOLFPKCS11_NSS) +static CK_RV test_hkdf_derive_aes_no_value_len(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_BYTE ikm[32] = { 0 }; + CK_BYTE salt[16] = { 0 }; + CK_OBJECT_HANDLE hBase = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; + CK_HKDF_PARAMS params = { + CK_TRUE, CK_FALSE, CKM_SHA384_HMAC, CKF_HKDF_SALT_DATA, + salt, sizeof(salt), CK_INVALID_HANDLE, NULL, 0 + }; + CK_MECHANISM mech = { CKM_HKDF_DERIVE, ¶ms, sizeof(params) }; + CK_ATTRIBUTE tmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &aesKeyType, sizeof(aesKeyType)}, + }; + CK_ULONG cnt = sizeof(tmpl) / sizeof(*tmpl); + + ret = concat_create_key(session, ikm, sizeof(ikm), CK_FALSE, CK_TRUE, + CK_TRUE, CK_FALSE, &hBase); + CHECK_CKR(ret, "Create HKDF base key"); + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &mech, hBase, tmpl, cnt, &hKey); + CHECK_CKR_FAIL(ret, CKR_TEMPLATE_INCOMPLETE, + "AES key without length from SHA-384 extract"); + } + if (ret == CKR_OK) { + params.prfHashMechanism = CKM_SHA256_HMAC; + ret = funcList->C_DeriveKey(session, &mech, hBase, tmpl, cnt, &hKey); + CHECK_CKR(ret, "AES-256 key from SHA-256 extract"); + } + + if (hKey != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hKey); + if (hBase != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hBase); + + return ret; +} +#endif + +#if defined(WOLFPKCS11_HKDF) && !defined(NO_HMAC) +static CK_RV test_concatenate_hybrid_hkdf(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_BYTE zEcdh[32] = { 0 }; + CK_BYTE zMlkem[32]; + CK_BYTE salt[16]; + CK_BYTE info[10]; + CK_BYTE msg[16]; + CK_BYTE mac[32]; + CK_ULONG macLen = sizeof(mac); + CK_BYTE expMac[32] = { + 0x71, 0xe9, 0x0f, 0x7e, 0xea, 0xec, 0x0f, 0x44, + 0x08, 0x5b, 0x7d, 0x7e, 0xed, 0x2a, 0x38, 0x39, + 0xf6, 0x5b, 0xb9, 0xd1, 0x7d, 0x3a, 0x8e, 0x0a, + 0x4c, 0xbd, 0x84, 0xcf, 0x3b, 0xac, 0xb0, 0x7c + }; + CK_ULONG okmLen = 32; + CK_OBJECT_HANDLE hEcdh = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hMlkem = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hIkm = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hOkm = CK_INVALID_HANDLE; + CK_MECHANISM concatMech = { CKM_CONCATENATE_BASE_AND_KEY, &hMlkem, + sizeof(hMlkem) }; + CK_HKDF_PARAMS hkdfParams = { + CK_TRUE, CK_TRUE, CKM_SHA256_HMAC, CKF_HKDF_SALT_DATA, + salt, sizeof(salt), CK_INVALID_HANDLE, info, sizeof(info) + }; + CK_MECHANISM hkdfMech = { CKM_HKDF_DERIVE, &hkdfParams, + sizeof(hkdfParams) }; + CK_MECHANISM macMech = { CKM_SHA256_HMAC, NULL, 0 }; + CK_ATTRIBUTE ikmTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_SENSITIVE, &ckTrue, sizeof(ckTrue)}, + {CKA_EXTRACTABLE, &ckFalse, sizeof(ckFalse)}, + {CKA_DERIVE, &ckTrue, sizeof(ckTrue)}, + }; + CK_ATTRIBUTE okmTmpl[] = { + {CKA_CLASS, &secretKeyClass, sizeof(secretKeyClass)}, + {CKA_KEY_TYPE, &genericKeyType, sizeof(genericKeyType)}, + {CKA_SIGN, &ckTrue, sizeof(ckTrue)}, + {CKA_VALUE_LEN, &okmLen, sizeof(okmLen)}, + }; +#if !defined(WOLFPKCS11_LEGACY_DERIVE_NO_INHERIT) && !defined(WOLFPKCS11_NSS) + CK_BBOOL got[2]; + CK_ATTRIBUTE protAttrs[] = { + {CKA_SENSITIVE, &got[0], sizeof(CK_BBOOL)}, + {CKA_EXTRACTABLE, &got[1], sizeof(CK_BBOOL)}, + }; +#endif + CK_ULONG i; + + for (i = 0; i < sizeof(zMlkem); i++) + zMlkem[i] = (CK_BYTE)(i + 1); + for (i = 0; i < sizeof(salt); i++) + salt[i] = (CK_BYTE)(0x10 + i); + for (i = 0; i < sizeof(info); i++) + info[i] = (CK_BYTE)(0xf0 + i); + for (i = 0; i < sizeof(msg); i++) + msg[i] = (CK_BYTE)(0x40 + i); + + ret = concat_create_key(session, zEcdh, sizeof(zEcdh), CK_TRUE, CK_FALSE, + CK_TRUE, CK_FALSE, &hEcdh); + CHECK_CKR(ret, "Create ECDH secret"); + if (ret == CKR_OK) { + ret = concat_create_key(session, zMlkem, sizeof(zMlkem), CK_TRUE, + CK_FALSE, CK_TRUE, CK_FALSE, &hMlkem); + CHECK_CKR(ret, "Create ML-KEM secret"); + } + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &concatMech, hEcdh, ikmTmpl, + sizeof(ikmTmpl) / sizeof(*ikmTmpl), &hIkm); + CHECK_CKR(ret, "Concatenate hybrid secrets"); + } + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &hkdfMech, hIkm, okmTmpl, + sizeof(okmTmpl) / sizeof(*okmTmpl), &hOkm); + CHECK_CKR(ret, "HKDF from concatenated secret"); + } +#if !defined(WOLFPKCS11_LEGACY_DERIVE_NO_INHERIT) && !defined(WOLFPKCS11_NSS) + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, hOkm, protAttrs, 2); + CHECK_CKR(ret, "Get HKDF key protection"); + } + if (ret == CKR_OK && (got[0] != CK_TRUE || got[1] != CK_FALSE)) { + ret = CKR_DATA_INVALID; + CHECK_CKR(ret, "HKDF key inherits protection"); + } +#endif + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &macMech, hOkm); + CHECK_CKR(ret, "HMAC sign init"); + } + if (ret == CKR_OK) { + ret = funcList->C_Sign(session, msg, sizeof(msg), mac, &macLen); + CHECK_CKR(ret, "HMAC sign"); + } + if (ret == CKR_OK && (macLen != sizeof(expMac) || + XMEMCMP(mac, expMac, sizeof(expMac)) != 0)) { + ret = CKR_DATA_INVALID; + CHECK_CKR(ret, "HMAC with hybrid HKDF key"); + } + + if (hOkm != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hOkm); + if (hIkm != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hIkm); + if (hMlkem != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hMlkem); + if (hEcdh != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, hEcdh); + + return ret; +} +#endif + +#ifndef NO_SHA +static CK_RV test_x509_check_value(void* args) +{ + CK_RV ret = CKR_OK; + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_CERTIFICATE_TYPE certType = CKC_X_509; + CK_UTF8CHAR label[] = "A certificate object"; + CK_BYTE subject[] = "C = US, ST = Montana, L = Bozeman, O = wolfSSL, " + "OU = Support, CN = www.wolfssl.com, emailAddress = info@wolfssl.com"; + CK_BYTE id[] = {0x27, 0x8E, 0x67, 0x11, 0x74, 0xC3, 0x26, 0x1D, 0x3F, 0xED, + 0x33, 0x63, 0xB3, 0xA4, 0xD8, 0x1D, 0x30, 0xE5, 0xE8, 0xD5 + }; + CK_BYTE certificate[] = { /* ./certs/server-cert.der, 2048-bit */ + 0x30, 0x82, 0x04, 0xE8, 0x30, 0x82, 0x03, 0xD0, 0xA0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, 0x30, 0x0D, 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, + 0x00, 0x30, 0x81, 0x94, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, + 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, 0x07, 0x4D, 0x6F, + 0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, 0x30, 0x0E, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, 0x6F, 0x7A, 0x65, + 0x6D, 0x61, 0x6E, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, + 0x04, 0x0A, 0x0C, 0x08, 0x53, 0x61, 0x77, 0x74, 0x6F, 0x6F, + 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x0B, 0x0C, 0x0A, 0x43, 0x6F, 0x6E, 0x73, 0x75, 0x6C, 0x74, + 0x69, 0x6E, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, + 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, + 0x1F, 0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, + 0x0D, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, + 0x40, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, + 0x6F, 0x6D, 0x30, 0x1E, 0x17, 0x0D, 0x32, 0x33, 0x31, 0x32, + 0x31, 0x33, 0x32, 0x32, 0x31, 0x39, 0x32, 0x38, 0x5A, 0x17, + 0x0D, 0x32, 0x36, 0x30, 0x39, 0x30, 0x38, 0x32, 0x32, 0x31, + 0x39, 0x32, 0x38, 0x5A, 0x30, 0x81, 0x90, 0x31, 0x0B, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0C, + 0x07, 0x4D, 0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, 0x31, 0x10, + 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x07, 0x42, + 0x6F, 0x7A, 0x65, 0x6D, 0x61, 0x6E, 0x31, 0x10, 0x30, 0x0E, + 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x07, 0x77, 0x6F, 0x6C, + 0x66, 0x53, 0x53, 0x4C, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, + 0x55, 0x04, 0x0B, 0x0C, 0x07, 0x53, 0x75, 0x70, 0x70, 0x6F, + 0x72, 0x74, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0C, 0x0F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, + 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, + 0x30, 0x1D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, + 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, + 0x6D, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, + 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82, 0x01, 0x0A, 0x02, + 0x82, 0x01, 0x01, 0x00, 0xC0, 0x95, 0x08, 0xE1, 0x57, 0x41, + 0xF2, 0x71, 0x6D, 0xB7, 0xD2, 0x45, 0x41, 0x27, 0x01, 0x65, + 0xC6, 0x45, 0xAE, 0xF2, 0xBC, 0x24, 0x30, 0xB8, 0x95, 0xCE, + 0x2F, 0x4E, 0xD6, 0xF6, 0x1C, 0x88, 0xBC, 0x7C, 0x9F, 0xFB, + 0xA8, 0x67, 0x7F, 0xFE, 0x5C, 0x9C, 0x51, 0x75, 0xF7, 0x8A, + 0xCA, 0x07, 0xE7, 0x35, 0x2F, 0x8F, 0xE1, 0xBD, 0x7B, 0xC0, + 0x2F, 0x7C, 0xAB, 0x64, 0xA8, 0x17, 0xFC, 0xCA, 0x5D, 0x7B, + 0xBA, 0xE0, 0x21, 0xE5, 0x72, 0x2E, 0x6F, 0x2E, 0x86, 0xD8, + 0x95, 0x73, 0xDA, 0xAC, 0x1B, 0x53, 0xB9, 0x5F, 0x3F, 0xD7, + 0x19, 0x0D, 0x25, 0x4F, 0xE1, 0x63, 0x63, 0x51, 0x8B, 0x0B, + 0x64, 0x3F, 0xAD, 0x43, 0xB8, 0xA5, 0x1C, 0x5C, 0x34, 0xB3, + 0xAE, 0x00, 0xA0, 0x63, 0xC5, 0xF6, 0x7F, 0x0B, 0x59, 0x68, + 0x78, 0x73, 0xA6, 0x8C, 0x18, 0xA9, 0x02, 0x6D, 0xAF, 0xC3, + 0x19, 0x01, 0x2E, 0xB8, 0x10, 0xE3, 0xC6, 0xCC, 0x40, 0xB4, + 0x69, 0xA3, 0x46, 0x33, 0x69, 0x87, 0x6E, 0xC4, 0xBB, 0x17, + 0xA6, 0xF3, 0xE8, 0xDD, 0xAD, 0x73, 0xBC, 0x7B, 0x2F, 0x21, + 0xB5, 0xFD, 0x66, 0x51, 0x0C, 0xBD, 0x54, 0xB3, 0xE1, 0x6D, + 0x5F, 0x1C, 0xBC, 0x23, 0x73, 0xD1, 0x09, 0x03, 0x89, 0x14, + 0xD2, 0x10, 0xB9, 0x64, 0xC3, 0x2A, 0xD0, 0xA1, 0x96, 0x4A, + 0xBC, 0xE1, 0xD4, 0x1A, 0x5B, 0xC7, 0xA0, 0xC0, 0xC1, 0x63, + 0x78, 0x0F, 0x44, 0x37, 0x30, 0x32, 0x96, 0x80, 0x32, 0x23, + 0x95, 0xA1, 0x77, 0xBA, 0x13, 0xD2, 0x97, 0x73, 0xE2, 0x5D, + 0x25, 0xC9, 0x6A, 0x0D, 0xC3, 0x39, 0x60, 0xA4, 0xB4, 0xB0, + 0x69, 0x42, 0x42, 0x09, 0xE9, 0xD8, 0x08, 0xBC, 0x33, 0x20, + 0xB3, 0x58, 0x22, 0xA7, 0xAA, 0xEB, 0xC4, 0xE1, 0xE6, 0x61, + 0x83, 0xC5, 0xD2, 0x96, 0xDF, 0xD9, 0xD0, 0x4F, 0xAD, 0xD7, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x82, 0x01, 0x45, 0x30, + 0x82, 0x01, 0x41, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, + 0x04, 0x16, 0x04, 0x14, 0xB3, 0x11, 0x32, 0xC9, 0x92, 0x98, + 0x84, 0xE2, 0xC9, 0xF8, 0xD0, 0x3B, 0x6E, 0x03, 0x42, 0xCA, + 0x1F, 0x0E, 0x8E, 0x3C, 0x30, 0x81, 0xD4, 0x06, 0x03, 0x55, + 0x1D, 0x23, 0x04, 0x81, 0xCC, 0x30, 0x81, 0xC9, 0x80, 0x14, + 0x27, 0x8E, 0x67, 0x11, 0x74, 0xC3, 0x26, 0x1D, 0x3F, 0xED, + 0x33, 0x63, 0xB3, 0xA4, 0xD8, 0x1D, 0x30, 0xE5, 0xE8, 0xD5, + 0xA1, 0x81, 0x9A, 0xA4, 0x81, 0x97, 0x30, 0x81, 0x94, 0x31, + 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0C, 0x07, 0x4D, 0x6F, 0x6E, 0x74, 0x61, 0x6E, 0x61, + 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, + 0x07, 0x42, 0x6F, 0x7A, 0x65, 0x6D, 0x61, 0x6E, 0x31, 0x11, + 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x08, 0x53, + 0x61, 0x77, 0x74, 0x6F, 0x6F, 0x74, 0x68, 0x31, 0x13, 0x30, + 0x11, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x0A, 0x43, 0x6F, + 0x6E, 0x73, 0x75, 0x6C, 0x74, 0x69, 0x6E, 0x67, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x77, + 0x77, 0x77, 0x2E, 0x77, 0x6F, 0x6C, 0x66, 0x73, 0x73, 0x6C, + 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x1F, 0x30, 0x1D, 0x06, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, + 0x10, 0x69, 0x6E, 0x66, 0x6F, 0x40, 0x77, 0x6F, 0x6C, 0x66, + 0x73, 0x73, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x82, 0x14, 0x33, + 0x44, 0x1A, 0xA8, 0x6C, 0x01, 0xEC, 0xF6, 0x60, 0xF2, 0x70, + 0x51, 0x0A, 0x4C, 0xD1, 0x14, 0xFA, 0xBC, 0xE9, 0x44, 0x30, + 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x05, 0x30, 0x03, + 0x01, 0x01, 0xFF, 0x30, 0x1C, 0x06, 0x03, 0x55, 0x1D, 0x11, + 0x04, 0x15, 0x30, 0x13, 0x82, 0x0B, 0x65, 0x78, 0x61, 0x6D, + 0x70, 0x6C, 0x65, 0x2E, 0x63, 0x6F, 0x6D, 0x87, 0x04, 0x7F, + 0x00, 0x00, 0x01, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x25, + 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x02, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x4A, 0xFF, 0xB9, 0xE5, 0x85, 0x9B, + 0xDA, 0x53, 0x66, 0x7F, 0x07, 0x22, 0xBF, 0xB6, 0x19, 0xEA, + 0x42, 0xEB, 0xA4, 0x11, 0x07, 0x62, 0xFF, 0x39, 0x5F, 0x33, + 0x37, 0x3A, 0x87, 0x26, 0x71, 0x3D, 0x13, 0xB2, 0xCA, 0xB8, + 0x64, 0x38, 0x7B, 0x8A, 0x99, 0x48, 0x0E, 0xA5, 0xA4, 0x6B, + 0xB1, 0x99, 0x6E, 0xE0, 0x46, 0x51, 0xBD, 0x19, 0x52, 0xAD, + 0xBC, 0xA6, 0x7E, 0x2A, 0x7A, 0x7C, 0x23, 0xA7, 0xCC, 0xDB, + 0x5E, 0x43, 0x7D, 0x6B, 0x04, 0xC8, 0xB7, 0xDD, 0x95, 0xAD, + 0xF0, 0x91, 0x80, 0x59, 0xC5, 0x19, 0x91, 0x26, 0x27, 0x91, + 0xB8, 0x48, 0x1C, 0xEB, 0x55, 0xB6, 0xAA, 0x7D, 0xA4, 0x38, + 0xF1, 0x03, 0xBC, 0x6C, 0x8B, 0xAA, 0x94, 0xD6, 0x3C, 0x05, + 0x7A, 0x96, 0xC5, 0x06, 0xF1, 0x26, 0x14, 0x2E, 0x75, 0xFB, + 0xDD, 0xE5, 0x35, 0xB3, 0x01, 0x2C, 0xB3, 0xAD, 0x62, 0x5A, + 0x21, 0x9A, 0x08, 0xBE, 0x56, 0xFC, 0xF9, 0xA2, 0x42, 0x87, + 0x86, 0xE5, 0xA9, 0xC5, 0x99, 0xCF, 0xAE, 0x14, 0xBE, 0xE0, + 0xB9, 0x08, 0x24, 0x0D, 0x1D, 0x5C, 0xD6, 0x14, 0xE1, 0x4C, + 0x9F, 0x40, 0xB3, 0xA9, 0xE9, 0x2D, 0x52, 0x8B, 0x4C, 0xBF, + 0xAC, 0x44, 0x31, 0x67, 0xC1, 0x8D, 0x06, 0x85, 0xEC, 0x0F, + 0xE4, 0x99, 0xD7, 0x4B, 0x7B, 0x21, 0x06, 0x66, 0xD4, 0xE4, + 0xF5, 0x9D, 0xFF, 0x8E, 0xF0, 0x86, 0x39, 0x58, 0x1D, 0xA4, + 0x5B, 0xE2, 0x63, 0xEF, 0x7C, 0xC9, 0x18, 0x87, 0xA8, 0x02, + 0x25, 0x10, 0x3E, 0x87, 0x28, 0xF9, 0xF5, 0xEF, 0x47, 0x9E, + 0xA5, 0x80, 0x08, 0x11, 0x90, 0x68, 0xFE, 0xD1, 0xA3, 0xA8, + 0x51, 0xB9, 0x37, 0xFF, 0xD5, 0xCA, 0x7C, 0x87, 0x7F, 0x6B, + 0xBC, 0x2C, 0x12, 0xC8, 0xC5, 0x85, 0x8B, 0xFC, 0x0C, 0xC6, + 0xB9, 0x86, 0xB8, 0xC9, 0x04, 0xC3, 0x51, 0x37, 0xD2, 0x4F + }; + /* Expected check value - first 3 bytes of SHA-1 hash of the certificate */ + CK_BYTE expectedCheckValue[] = {0xB6, 0x38, 0x75}; + + CK_ATTRIBUTE tmpl[] = { + {CKA_CLASS, &certificateClass, sizeof(certificateClass)}, + {CKA_CERTIFICATE_TYPE, &certType, sizeof(certType)}, + {CKA_TOKEN, &ckTrue, sizeof(ckTrue)}, + {CKA_LABEL, label, sizeof(label)-1}, + {CKA_SUBJECT, subject, sizeof(subject)-1}, + {CKA_ID, id, sizeof(id)}, + {CKA_VALUE, certificate, sizeof(certificate)} + }; + CK_ULONG tmplCnt = sizeof(tmpl) / sizeof(*tmpl); + CK_OBJECT_HANDLE obj; + CK_ATTRIBUTE checkValueTmpl[] = { + { CKA_CHECK_VALUE, NULL, 0 } + }; + CK_ULONG checkValueTmplCnt = sizeof(checkValueTmpl) / sizeof(*checkValueTmpl); + CK_BYTE checkValue[3]; + + /* Create certificate object */ + ret = funcList->C_CreateObject(session, tmpl, tmplCnt, &obj); + CHECK_CKR(ret, "Create certificate object"); + + if (ret == CKR_OK) { + /* Get the length of the check value first */ + ret = funcList->C_GetAttributeValue(session, obj, checkValueTmpl, checkValueTmplCnt); + CHECK_CKR(ret, "C_GetAttributeValue for check value length"); + } + + if (ret == CKR_OK) { + /* Verify expected check value length is 3 bytes */ + if (checkValueTmpl[0].ulValueLen != 3) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "Check value length should be 3 bytes"); + } + } + + if (ret == CKR_OK) { + /* Get the actual check value */ + checkValueTmpl[0].pValue = checkValue; + checkValueTmpl[0].ulValueLen = sizeof(checkValue); + + ret = funcList->C_GetAttributeValue(session, obj, checkValueTmpl, checkValueTmplCnt); + CHECK_CKR(ret, "C_GetAttributeValue for check value"); + + if (ret == CKR_OK) { + /* Verify the check value matches expected value */ + if (XMEMCMP(checkValue, expectedCheckValue, 3) != 0) { + ret = CKR_GENERAL_ERROR; + CHECK_CKR(ret, "Check value doesn't match expected SHA-1 hash prefix"); + } + } + } + + /* Clean up the object */ + funcList->C_DestroyObject(session, obj); + + return ret; +} +#endif + +static CK_RV test_random(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + unsigned char* seed = (unsigned char *)"Test"; + int seedLen = 4; + unsigned char data1[32]; + unsigned char data2[32]; + int i; + unsigned char b; + + XMEMSET(data1, 0, sizeof(data1)); + XMEMSET(data2, 0, sizeof(data2)); + + ret = funcList->C_SeedRandom(session, seed, seedLen); + CHECK_CKR(ret, "Seed Random 1"); + if (ret == CKR_OK) { + ret = funcList->C_GenerateRandom(session, data1, sizeof(data1)); + CHECK_CKR(ret, "Generate Random 1"); + } + if (ret == CKR_OK) { + b = 0; + for (i = 0; i < (int)sizeof(data1); i++) + b |= data1[i]; + if (b == 0) + ret = -1; + CHECK_CKR(ret, "Generated non-zero 1"); + } + if (ret == CKR_OK) { + ret = funcList->C_SeedRandom(session, seed, seedLen); + CHECK_CKR(ret, "Seed Random 2"); } if (ret == CKR_OK) { ret = funcList->C_GenerateRandom(session, data2, sizeof(data2)); @@ -19236,6 +21285,35 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_hkdf_gen_key), PKCS11TEST_FUNC_SESS_DECL(test_hkdf_derive_expand_null_value_len), PKCS11TEST_FUNC_SESS_DECL(test_hkdf_derive_implied_class), +#endif + PKCS11TEST_FUNC_SESS_DECL(test_concatenate_base_and_key), + PKCS11TEST_FUNC_SESS_DECL(test_concatenate_data), + PKCS11TEST_FUNC_SESS_DECL(test_concatenate_protection), + PKCS11TEST_FUNC_SESS_DECL(test_concatenate_errors), + PKCS11TEST_FUNC_SESS_DECL(test_concatenate_wrap_with_trusted), +#ifndef WOLFPKCS11_NO_STORE + PKCS11TEST_FUNC_SESS_DECL(test_concatenate_logged_out), +#endif +#ifndef WOLFPKCS11_NO_STORE + PKCS11TEST_FUNC_SESS_DECL(test_key_use_logged_out), +#endif +#if defined(HAVE_ECC) && !defined(NO_SHA256) + PKCS11TEST_FUNC_SESS_DECL(test_completed_op_stale_key), +#endif +#if !defined(NO_RSA) && !defined(WC_NO_RSA_OAEP) && !defined(NO_SHA256) + PKCS11TEST_FUNC_SESS_DECL(test_oaep_failed_decrypt), + PKCS11TEST_FUNC_SESS_DECL(test_oaep_key_destroyed), +#endif +#if defined(HAVE_ECC) && (defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)) && \ + !defined(NO_AES) && !defined(WOLFPKCS11_NSS) + PKCS11TEST_FUNC_SESS_DECL(test_ecdh_derive_aes_no_value_len), +#endif +#if defined(WOLFPKCS11_HKDF) && defined(WOLFSSL_SHA384) && !defined(NO_AES) && \ + !defined(WOLFPKCS11_NSS) + PKCS11TEST_FUNC_SESS_DECL(test_hkdf_derive_aes_no_value_len), +#endif +#if defined(WOLFPKCS11_HKDF) && !defined(NO_HMAC) + PKCS11TEST_FUNC_SESS_DECL(test_concatenate_hybrid_hkdf), #endif #ifdef WOLFSSL_HAVE_PRF #ifndef NO_MD5 diff --git a/tests/pkcs11v3test.c b/tests/pkcs11v3test.c index 3b3857a6..aa86b541 100644 --- a/tests/pkcs11v3test.c +++ b/tests/pkcs11v3test.c @@ -2423,6 +2423,257 @@ static CK_RV test_copy_object_mlkem_key(void* args) return ret; } + +#if defined(HAVE_ECC) && defined(WOLFPKCS11_HKDF) && !defined(NO_HMAC) +static CK_OBJECT_CLASS hybridSecretClass = CKO_SECRET_KEY; +static CK_KEY_TYPE hybridGenericType = CKK_GENERIC_SECRET; +static CK_BBOOL hybridFalse = CK_FALSE; + +static CK_RV hybrid_ec_pair(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE* priv, + CK_BYTE* point, CK_ULONG* pointLen) +{ + CK_RV ret; + CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; + CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 }; + CK_ATTRIBUTE pubTmpl[] = { + { CKA_EC_PARAMS, ecc_p256_params, sizeof(ecc_p256_params) }, + }; + CK_ATTRIBUTE privTmpl[] = { + { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, + }; + CK_ATTRIBUTE pointTmpl = { CKA_EC_POINT, point, *pointLen }; + + ret = funcList->C_GenerateKeyPair(session, &mech, pubTmpl, 1, privTmpl, 1, + &pub, priv); + CHECK_CKR(ret, "Generate EC key pair"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, pub, &pointTmpl, 1); + CHECK_CKR(ret, "Get EC point"); + } + if (pub != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, pub); + /* ECDH takes the raw point, so drop the DER OCTET STRING header. */ + if (ret == CKR_OK) { + CHECK_COND(pointTmpl.ulValueLen > 2 && point[0] == 0x04 && + point[1] == pointTmpl.ulValueLen - 2, ret, + "EC point is a DER OCTET STRING"); + } + if (ret == CKR_OK) { + *pointLen = pointTmpl.ulValueLen - 2; + XMEMMOVE(point, point + 2, *pointLen); + } + + return ret; +} + +static CK_RV hybrid_concat(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE base, + CK_OBJECT_HANDLE other, CK_OBJECT_HANDLE* key) +{ + CK_RV ret; + CK_MECHANISM mech = { CKM_CONCATENATE_BASE_AND_KEY, &other, + sizeof(other) }; + CK_ATTRIBUTE tmpl[] = { + { CKA_CLASS, &hybridSecretClass, sizeof(hybridSecretClass) }, + { CKA_KEY_TYPE, &hybridGenericType, sizeof(hybridGenericType) }, + { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, + }; + + ret = funcList->C_DeriveKey(session, &mech, base, tmpl, + sizeof(tmpl) / sizeof(*tmpl), key); + CHECK_CKR(ret, "Concatenate base and key"); + + return ret; +} + +static CK_RV hybrid_party_mac(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE psk, + CK_OBJECT_HANDLE ecPriv, CK_BYTE* peerPoint, + CK_ULONG peerPointLen, CK_OBJECT_HANDLE kemSecret, + CK_BYTE* mac, CK_ULONG* macLen) +{ + CK_RV ret; + CK_OBJECT_HANDLE zEcdh = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE pskEcdh = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE ikm = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE okm = CK_INVALID_HANDLE; + CK_ULONG ecdhLen = 32; + CK_ULONG okmLen = 32; + CK_ULONG ikmLen = 0; + CK_BYTE value[96]; + CK_BYTE salt[16] = { 0x73, 0x61, 0x6c, 0x74 }; + CK_BYTE info[8] = { 0x69, 0x6e, 0x66, 0x6f }; + CK_BYTE msg[16] = { 0x6d, 0x73, 0x67 }; + CK_ECDH1_DERIVE_PARAMS ecdh; + CK_MECHANISM ecdhMech = { CKM_ECDH1_DERIVE, &ecdh, sizeof(ecdh) }; + CK_HKDF_PARAMS hkdf; + CK_MECHANISM hkdfMech = { CKM_HKDF_DERIVE, &hkdf, sizeof(hkdf) }; + CK_MECHANISM macMech = { CKM_SHA256_HMAC, NULL, 0 }; + CK_ATTRIBUTE ecdhTmpl[] = { + { CKA_CLASS, &hybridSecretClass, sizeof(hybridSecretClass) }, + { CKA_KEY_TYPE, &hybridGenericType, sizeof(hybridGenericType) }, + { CKA_VALUE_LEN, &ecdhLen, sizeof(ecdhLen) }, + { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &hybridFalse, sizeof(hybridFalse) }, + }; + CK_ATTRIBUTE okmTmpl[] = { + { CKA_CLASS, &hybridSecretClass, sizeof(hybridSecretClass) }, + { CKA_KEY_TYPE, &hybridGenericType, sizeof(hybridGenericType) }, + { CKA_VALUE_LEN, &okmLen, sizeof(okmLen) }, + { CKA_SIGN, &ckTrue, sizeof(ckTrue) }, + }; + CK_ATTRIBUTE lenTmpl = { CKA_VALUE_LEN, &ikmLen, sizeof(ikmLen) }; + CK_ATTRIBUTE valueTmpl = { CKA_VALUE, value, sizeof(value) }; + + XMEMSET(&ecdh, 0, sizeof(ecdh)); + ecdh.kdf = CKD_NULL; + ecdh.pPublicData = peerPoint; + ecdh.ulPublicDataLen = peerPointLen; + XMEMSET(&hkdf, 0, sizeof(hkdf)); + hkdf.bExtract = CK_TRUE; + hkdf.bExpand = CK_TRUE; + hkdf.prfHashMechanism = CKM_SHA256_HMAC; + hkdf.ulSaltType = CKF_HKDF_SALT_DATA; + hkdf.pSalt = salt; + hkdf.ulSaltLen = sizeof(salt); + hkdf.pInfo = info; + hkdf.ulInfoLen = sizeof(info); + + ret = funcList->C_DeriveKey(session, &ecdhMech, ecPriv, ecdhTmpl, + sizeof(ecdhTmpl) / sizeof(*ecdhTmpl), &zEcdh); + CHECK_CKR(ret, "ECDH derive"); + if (ret == CKR_OK) + ret = hybrid_concat(session, psk, zEcdh, &pskEcdh); + if (zEcdh != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, zEcdh); + if (ret == CKR_OK) + ret = hybrid_concat(session, pskEcdh, kemSecret, &ikm); + if (pskEcdh != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, pskEcdh); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, ikm, &lenTmpl, 1); + CHECK_CKR(ret, "Get hybrid IKM length"); + } + CHECK_COND(ret != CKR_OK || ikmLen == 96, ret, "Hybrid IKM is 96 bytes"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, ikm, &valueTmpl, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Hybrid IKM value is not readable"); + } + if (ret == CKR_OK) { + ret = funcList->C_DeriveKey(session, &hkdfMech, ikm, okmTmpl, + sizeof(okmTmpl) / sizeof(*okmTmpl), &okm); + CHECK_CKR(ret, "HKDF from hybrid IKM"); + } + if (ikm != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, ikm); + if (ret == CKR_OK) { + ret = funcList->C_SignInit(session, &macMech, okm); + CHECK_CKR(ret, "HMAC sign init with OKM"); + } + if (ret == CKR_OK) { + ret = funcList->C_Sign(session, msg, sizeof(msg), mac, macLen); + CHECK_CKR(ret, "HMAC sign with OKM"); + } + + if (okm != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, okm); + + return ret; +} + +static CK_RV test_concatenate_hybrid_agreement(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + CK_FUNCTION_LIST_3_2* funcListExt = (CK_FUNCTION_LIST_3_2*)funcList; + CK_OBJECT_HANDLE psk = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE ecPrivA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE ecPrivB = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE kemPub = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE kemPriv = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE ssA = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE ssB = CK_INVALID_HANDLE; + CK_BYTE pointA[80]; + CK_BYTE pointB[80]; + CK_ULONG pointALen = sizeof(pointA); + CK_ULONG pointBLen = sizeof(pointB); + CK_BYTE ct[WC_ML_KEM_512_CIPHER_TEXT_SIZE]; + CK_ULONG ctLen = sizeof(ct); + CK_BYTE pskValue[32]; + CK_BYTE macA[32]; + CK_BYTE macB[32]; + CK_ULONG macALen = sizeof(macA); + CK_ULONG macBLen = sizeof(macB); + CK_MECHANISM kemMech = { CKM_ML_KEM, NULL, 0 }; + CK_ATTRIBUTE pskTmpl[] = { + { CKA_CLASS, &hybridSecretClass, sizeof(hybridSecretClass) }, + { CKA_KEY_TYPE, &hybridGenericType, sizeof(hybridGenericType) }, + { CKA_VALUE, pskValue, sizeof(pskValue) }, + { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &hybridFalse, sizeof(hybridFalse) }, + }; + CK_ATTRIBUTE ssTmpl[] = { + { CKA_CLASS, &hybridSecretClass, sizeof(hybridSecretClass) }, + { CKA_KEY_TYPE, &hybridGenericType, sizeof(hybridGenericType) }, + { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_SENSITIVE, &ckTrue, sizeof(ckTrue) }, + { CKA_EXTRACTABLE, &hybridFalse, sizeof(hybridFalse) }, + }; + CK_ULONG ssCnt = sizeof(ssTmpl) / sizeof(*ssTmpl); + + XMEMSET(pskValue, 0x5a, sizeof(pskValue)); + ret = funcList->C_CreateObject(session, pskTmpl, + sizeof(pskTmpl) / sizeof(*pskTmpl), &psk); + CHECK_CKR(ret, "Create PSK"); + if (ret == CKR_OK) + ret = hybrid_ec_pair(session, &ecPrivA, pointA, &pointALen); + if (ret == CKR_OK) + ret = hybrid_ec_pair(session, &ecPrivB, pointB, &pointBLen); + if (ret == CKR_OK) { + ret = gen_mlkem_keys(session, CKP_ML_KEM_512, &kemPub, &kemPriv, NULL, + 0, NULL, 0, 0); + } + if (ret == CKR_OK) { + ret = funcListExt->C_EncapsulateKey(session, &kemMech, kemPub, ssTmpl, + ssCnt, ct, &ctLen, &ssA); + CHECK_CKR(ret, "ML-KEM encapsulate"); + } + if (ret == CKR_OK) { + ret = funcListExt->C_DecapsulateKey(session, &kemMech, kemPriv, ssTmpl, + ssCnt, ct, ctLen, &ssB); + CHECK_CKR(ret, "ML-KEM decapsulate"); + } + if (kemPriv != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, kemPriv); + if (kemPub != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, kemPub); + if (ret == CKR_OK) { + ret = hybrid_party_mac(session, psk, ecPrivA, pointB, pointBLen, ssA, + macA, &macALen); + } + if (ret == CKR_OK) { + ret = hybrid_party_mac(session, psk, ecPrivB, pointA, pointALen, ssB, + macB, &macBLen); + } + CHECK_COND(ret != CKR_OK || (macALen == macBLen && + XMEMCMP(macA, macB, macALen) == 0), ret, + "Both parties derive the same key"); + + if (ssB != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, ssB); + if (ssA != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, ssA); + if (ecPrivB != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, ecPrivB); + if (ecPrivA != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, ecPrivA); + if (psk != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, psk); + + return ret; +} +#endif #endif /* WOLFPKCS11_MLKEM */ #endif /* WOLFPKCS11_PKCS11_V3_2 */ @@ -4005,6 +4256,128 @@ static CK_RV test_xmss_paramset_setattr_rejected(void* args) #endif /* WOLFPKCS11_XMSS */ +#if defined(WOLFPKCS11_PKCS11_V3_2) && !defined(WOLFPKCS11_NO_STORE) && \ + (defined(WOLFPKCS11_MLDSA) || defined(WOLFPKCS11_MLKEM)) +static CK_RV pqc_attrs_logged_out(CK_SESSION_HANDLE session, + CK_MECHANISM_TYPE genMech, CK_ULONG paramSet, + CK_ATTRIBUTE_TYPE useAttr, + CK_MECHANISM_TYPE useMech) +{ + CK_RV ret; + CK_RV loginRet; + CK_BBOOL ckFalse = CK_FALSE; + CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; + CK_MECHANISM mech = { genMech, NULL, 0 }; + CK_MECHANISM opMech = { useMech, NULL, 0 }; + CK_ULONG gotSet = 0; + CK_BYTE value[64]; + CK_ATTRIBUTE setAttr = { CKA_PARAMETER_SET, &gotSet, sizeof(gotSet) }; + CK_ATTRIBUTE valueAttr = { CKA_VALUE, value, sizeof(value) }; + CK_ATTRIBUTE pubTmpl[] = { + { CKA_PARAMETER_SET, ¶mSet, sizeof(paramSet) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + }; + CK_ATTRIBUTE privTmpl[] = { + { useAttr, &ckTrue, sizeof(ckTrue) }, + { CKA_PRIVATE, &ckFalse, sizeof(ckFalse) }, + { CKA_SENSITIVE, &ckFalse, sizeof(ckFalse) }, + { CKA_EXTRACTABLE, &ckTrue, sizeof(ckTrue) }, + { CKA_TOKEN, &ckTrue, sizeof(ckTrue) }, + }; + + if (userPinLen == 0) + return CKR_SKIPPED; + + ret = funcList->C_GenerateKeyPair(session, &mech, pubTmpl, + sizeof(pubTmpl) / sizeof(*pubTmpl), + privTmpl, + sizeof(privTmpl) / sizeof(*privTmpl), + &pub, &priv); + CHECK_CKR(ret, "Generate public token key pair"); + if (ret == CKR_OK) { + ret = funcList->C_Logout(session); + CHECK_CKR(ret, "Logout"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, priv, &valueAttr, 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Private key value after logout"); + if (ret == CKR_OK) { + ret = funcList->C_GetAttributeValue(session, priv, &setAttr, + 1); + CHECK_CKR_FAIL(ret, CKR_ATTRIBUTE_SENSITIVE, + "Private key parameter set after logout"); + } + if (ret == CKR_OK) { + setAttr.ulValueLen = sizeof(gotSet); + ret = funcList->C_GetAttributeValue(session, pub, &setAttr, 1); + CHECK_CKR(ret, "Public key parameter set after logout"); + CHECK_COND(ret != CKR_OK || gotSet == paramSet, ret, + "Public key parameter set value after logout"); + } + if (ret == CKR_OK && useAttr == CKA_SIGN) { + ret = funcList->C_SignInit(session, &opMech, priv); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Sign with private key after logout"); + } +#ifdef WOLFPKCS11_MLKEM + if (ret == CKR_OK && useAttr == CKA_DECAPSULATE) { + CK_FUNCTION_LIST_3_2* funcListExt = + (CK_FUNCTION_LIST_3_2*)funcList; + CK_OBJECT_HANDLE secret = CK_INVALID_HANDLE; + CK_OBJECT_CLASS secretClass = CKO_SECRET_KEY; + CK_KEY_TYPE genericType = CKK_GENERIC_SECRET; + CK_BYTE ct[WC_ML_KEM_512_CIPHER_TEXT_SIZE]; + CK_ATTRIBUTE secretTmpl[] = { + { CKA_CLASS, &secretClass, sizeof(secretClass) }, + { CKA_KEY_TYPE, &genericType, sizeof(genericType) }, + }; + + XMEMSET(ct, 0, sizeof(ct)); + ret = funcListExt->C_DecapsulateKey(session, &opMech, priv, + secretTmpl, sizeof(secretTmpl) / sizeof(*secretTmpl), + ct, sizeof(ct), &secret); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Decapsulate with private key after logout"); + } +#endif + loginRet = funcList->C_Login(session, CKU_USER, userPin, + userPinLen); + CHECK_CKR(loginRet, "Login again"); + if (ret == CKR_OK) + ret = loginRet; + } + } + if (priv != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, priv); + if (pub != CK_INVALID_HANDLE) + funcList->C_DestroyObject(session, pub); + + return ret; +} + +#ifdef WOLFPKCS11_MLDSA +static CK_RV test_mldsa_attrs_logged_out(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + + return pqc_attrs_logged_out(session, CKM_ML_DSA_KEY_PAIR_GEN, + CKP_ML_DSA_44, CKA_SIGN, CKM_ML_DSA); +} +#endif + +#ifdef WOLFPKCS11_MLKEM +static CK_RV test_mlkem_attrs_logged_out(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + + return pqc_attrs_logged_out(session, CKM_ML_KEM_KEY_PAIR_GEN, + CKP_ML_KEM_512, CKA_DECAPSULATE, + CKM_ML_KEM); +} +#endif +#endif + static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_NO_INIT_DECL(test_get_interface_list), PKCS11TEST_FUNC_NO_INIT_DECL(test_get_interface), @@ -4021,6 +4394,9 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_mldsa_fixed_keys_seed), PKCS11TEST_FUNC_SESS_DECL(test_mldsa_fixed_keys_both), PKCS11TEST_FUNC_SESS_DECL(test_copy_object_mldsa_key), +#ifndef WOLFPKCS11_NO_STORE + PKCS11TEST_FUNC_SESS_DECL(test_mldsa_attrs_logged_out), +#endif #endif #ifdef WOLFPKCS11_MLKEM PKCS11TEST_FUNC_SESS_DECL(test_mlkem_gen_keys), @@ -4040,6 +4416,12 @@ static TEST_FUNC testFunc[] = { PKCS11TEST_FUNC_SESS_DECL(test_mlkem_initial_states), PKCS11TEST_FUNC_SESS_DECL(test_mlkem_encap_decap_not_permitted), PKCS11TEST_FUNC_SESS_DECL(test_copy_object_mlkem_key), +#if defined(HAVE_ECC) && defined(WOLFPKCS11_HKDF) && !defined(NO_HMAC) + PKCS11TEST_FUNC_SESS_DECL(test_concatenate_hybrid_agreement), +#endif +#ifndef WOLFPKCS11_NO_STORE + PKCS11TEST_FUNC_SESS_DECL(test_mlkem_attrs_logged_out), +#endif #endif #ifdef WOLFPKCS11_LMS PKCS11TEST_FUNC_SESS_DECL(test_hss_verify_kat), diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index ca3e6c2f..44ac67a2 100644 --- a/wolfpkcs11/internal.h +++ b/wolfpkcs11/internal.h @@ -353,6 +353,8 @@ C_EXTRA_FLAGS="-DWOLFSSL_PUBLIC_MP -DWC_RSA_DIRECT" #define WP11_MAX_SYM_KEY_SZ (2048) #elif !defined(NO_DH) #define WP11_MAX_SYM_KEY_SZ (4096/8) +#elif defined(WOLFPKCS11_MLKEM) +#define WP11_MAX_SYM_KEY_SZ 256 #elif defined(HAVE_ECC) #define WP11_MAX_SYM_KEY_SZ ((521+7)/8) #else @@ -572,6 +574,8 @@ WP11_LOCAL int WP11_Object_OnToken(WP11_Object* object); WP11_LOCAL void WP11_Object_Persist(WP11_Object* object); WP11_LOCAL int WP11_KeyType_IsSecret(CK_KEY_TYPE type); WP11_LOCAL CK_KEY_TYPE WP11_Object_GetType(WP11_Object* object); +WP11_LOCAL WP11_Slot* WP11_Object_GetSlot(WP11_Object* object); +WP11_LOCAL int WP11_Object_KeyState(WP11_Object* object); WP11_LOCAL CK_ULONG WP11_Object_GetDevId(WP11_Object* object); WP11_LOCAL int WP11_Object_SetRsaKey(WP11_Object* object, unsigned char** data, @@ -720,6 +724,10 @@ WP11_LOCAL int WP11_GenerateRandomKey(WP11_Object* secret, WP11_Slot* slot, WP11_LOCAL int WP11_KDF_Derive(WP11_Session* session, CK_HKDF_PARAMS_PTR params, unsigned char* key, word32* keyLen, WP11_Object* priv); +WP11_LOCAL int WP11_Concat_KeyLen(WP11_Object* key, word32* len); +WP11_LOCAL int WP11_Concat_Derive(WP11_Object* base, WP11_Object* other, + const byte* data, word32 dataLen, + int dataFirst, byte* out, word32 outLen); WP11_LOCAL int WP11_Tls12_Master_Key_Derive(CK_SSL3_RANDOM_DATA* random, CK_MECHANISM_TYPE mech, const char* label, diff --git a/wolfpkcs11/pkcs11.h b/wolfpkcs11/pkcs11.h index 94f3c389..10d72dc6 100644 --- a/wolfpkcs11/pkcs11.h +++ b/wolfpkcs11/pkcs11.h @@ -341,6 +341,9 @@ extern "C" { #define CKM_SHA3_512 0x000002D0UL #define CKM_SHA3_512_HMAC 0x000002D1UL #define CKM_GENERIC_SECRET_KEY_GEN 0x00000350UL +#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360UL +#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362UL +#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363UL #define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371UL #define CKM_TLS_PRF 0x00000378UL #define CKM_PKCS5_PBKD2 0x000003B0UL @@ -714,6 +717,12 @@ typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS { } CK_AES_CBC_ENCRYPT_DATA_PARAMS; typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS* CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR; +typedef struct CK_KEY_DERIVATION_STRING_DATA { + CK_BYTE_PTR pData; + CK_ULONG ulLen; +} CK_KEY_DERIVATION_STRING_DATA; +typedef CK_KEY_DERIVATION_STRING_DATA* CK_KEY_DERIVATION_STRING_DATA_PTR; + typedef CK_ULONG CK_MAC_GENERAL_PARAMS; typedef CK_MAC_GENERAL_PARAMS* CK_MAC_GENERAL_PARAMS_PTR;