diff --git a/src/crypto.c b/src/crypto.c index 35b7d0f1..5e762ddf 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. */ @@ -641,7 +635,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 +663,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) @@ -1050,6 +1042,14 @@ static CK_RV CheckAttributeUpdate(WP11_Session* session, WP11_Object* obj, return CKR_OK; } +static CK_RV UndecodedKeyRv(WP11_Session* session) +{ + /* 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; +} + /** * Set the values of the attributes into the object. * @@ -1345,12 +1345,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(session); else if (ret != 0) return CKR_FUNCTION_FAILED; } @@ -10149,7 +10145,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 +10194,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 +10346,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(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 +10397,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 +10418,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; @@ -10804,24 +10842,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 +10987,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 +11021,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 +11055,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 +11101,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..9d04984d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -19044,6 +19044,129 @@ 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 = 0; + + if (key->objClass != CKO_SECRET_KEY || key->data.symmKey == NULL) + ret = BAD_FUNC_ARG; +#ifndef WOLFPKCS11_NO_STORE + else if (key->encoded || key->undecoded) + ret = BAD_STATE_E; +#endif +#ifdef WOLFSSL_STM32U5_DHUK + else if (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. 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..29b9dc1d 100644 --- a/tests/pkcs11str.c +++ b/tests/pkcs11str.c @@ -961,6 +961,88 @@ static CK_RV find_mlkem_pub_key(CK_SESSION_HANDLE session, } #endif /* WOLFPKCS11_MLKEM */ +#ifndef WOLFPKCS11_NO_STORE +static unsigned char concatKeyId[] = "123concatkey"; + +static CK_RV create_concat_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_ID, concatKeyId, sizeof(concatKeyId) - 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; +} + +static CK_RV concat_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) }; + CK_ATTRIBUTE findTmpl[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_ID, concatKeyId, sizeof(concatKeyId) - 1 }, + }; + CK_ULONG valueLen = 16 + sizeof(data); + 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_DeriveKey(session, &mech, key, tmpl, + sizeof(tmpl) / sizeof(*tmpl), &derived); + CHECK_CKR_FAIL(ret, CKR_USER_NOT_LOGGED_IN, + "Concatenate undecoded key before login"); + } + 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 +1213,15 @@ 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_concat_key(session); + if (ret == CKR_OK) { + printf("Done\n"); + } + } #endif pkcs11_close_session(session); } @@ -1155,6 +1246,13 @@ static CK_RV pkcs11_test(int slotId, int setPin, int closeDl) printf("Done\n"); } } + if (ret == CKR_OK && userPinLen != 0) { + printf("Concatenate before login ... "); + ret = concat_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..472f9751 100644 --- a/tests/pkcs11test.c +++ b/tests/pkcs11test.c @@ -15997,6 +15997,1019 @@ static CK_RV test_hkdf_derive_implied_class(void* args) } #endif +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_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}, + }; + + 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, &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 cnt = sizeof(tmpl) / sizeof(*tmpl); + + if (valueLen == 0) + cnt--; + *key = CK_INVALID_HANDLE; + return funcList->C_DeriveKey(session, mech, base, tmpl, cnt, key); +} + +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)}; + + 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); + + return ret; +} + +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)}, + }; + + 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"); + } + funcList->C_DestroyObject(session, key); + + return ret; +} + +static CK_RV test_concatenate_base_and_key(void* args) +{ + CK_SESSION_HANDLE session = *(CK_SESSION_HANDLE*)args; + CK_RV ret; + 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) }; + + 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 = 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, b, sizeof(b), CK_FALSE, CK_TRUE, + CK_TRUE, CK_TRUE, &hB); + CHECK_CKR(ret, "Create token key"); + } + if (ret == CKR_OK) { + 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 = 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(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) { @@ -19236,6 +20249,25 @@ 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 +#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..9a563482 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 */ @@ -4040,6 +4291,9 @@ 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 #endif #ifdef WOLFPKCS11_LMS PKCS11TEST_FUNC_SESS_DECL(test_hss_verify_kat), diff --git a/wolfpkcs11/internal.h b/wolfpkcs11/internal.h index ca3e6c2f..1c269517 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 @@ -720,6 +722,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;