#include "pkcs11i.h" #include "blapi.h" #include "secerr.h" #include "softoken.h" /* Overview: * * This file contains implementations of the three KDFs from NIST SP800-108 * "Recommendation for Key Derivation Using Pseudorandom Functions": * * 1. KDF in Counter Mode (section 5.1) * 2. KDF in Feedback Mode (section 5.2) * 3. KDF in Double-Pipeline Iteration Mode (section 5.3) * * These KDFs are a form of negotiable building blocks for KDFs: protocol * designers can choose various fields, their endianness, and the underlying * PRF. These constructs are generic enough to handle creation of arbitrary, * (but known ahead of time) length outputs. * * The families of PRFs described here are used, among other places, in * Kerberos and GlobalPlatform's Secure Channel Protocol 03. The PKCS#11 v3.0 * design for this KDF facilitates a wide range of uses. * * Implementation Details: * * We reuse the new sftk_MACCtx for handling the underlying MACing; with a few * safe restrictions, we can reuse whatever it gives us to use as a PRF. * * We implement the core of the KDF in the *Raw(...) version of the function * call. The PKCS#11 key handling happens in the non-Raw version. This means * we need a single large allocation upfront (large enough to store the entire * key stream), but means we can share key parsing logic and enable the * creation of data objects. */ /* [ section: #define's ] */ #define VALID_CK_BOOL(x) ((x) == CK_TRUE || (x) == CK_FALSE) #define IS_COUNTER(_mech) ((_mech) == CKM_SP800_108_COUNTER_KDF || (_mech) == CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA) #define DOES_DERIVE_DATA(_mech) ((_mech) == CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA || (_mech) == CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA || (_mech) == CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA) /* [ section: parameter validation ] */ static CK_RV kbkdf_LoadParameters(CK_MECHANISM_TYPE mech, CK_MECHANISM_PTR pMechanism, CK_SP800_108_KDF_PARAMS_PTR kdf_params, CK_BYTE_PTR *initial_value, CK_ULONG_PTR initial_value_length) { /* This function loads the parameters for the given mechanism into the * specified kdf_params, splitting off the IV if present. In PKCS#11 v3.0, * CK_SP800_108_FEEDBACK_KDF_PARAMS and CK_SP800_108_KDF_PARAMS have * different ordering of internal parameters, which means that it isn't * easy to reuse feedback parameters in the same functions as non-feedback * parameters. Rather than duplicating the logic, split out the only * Feedback-specific data (the IV) into a separate argument and repack it * into the passed kdf_params struct instead. */ PR_ASSERT(pMechanism != NULL && kdf_params != NULL && initial_value != NULL && initial_value_length != NULL); CK_SP800_108_KDF_PARAMS_PTR in_params; CK_SP800_108_FEEDBACK_KDF_PARAMS_PTR feedback_params; if (mech == CKM_SP800_108_FEEDBACK_KDF || mech == CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA) { if (pMechanism->ulParameterLen != sizeof(CK_SP800_108_FEEDBACK_KDF_PARAMS)) { return CKR_MECHANISM_PARAM_INVALID; } feedback_params = (CK_SP800_108_FEEDBACK_KDF_PARAMS *)pMechanism->pParameter; if (feedback_params->pIV == NULL && feedback_params->ulIVLen > 0) { return CKR_MECHANISM_PARAM_INVALID; } kdf_params->prfType = feedback_params->prfType; kdf_params->ulNumberOfDataParams = feedback_params->ulNumberOfDataParams; kdf_params->pDataParams = feedback_params->pDataParams; kdf_params->ulAdditionalDerivedKeys = feedback_params->ulAdditionalDerivedKeys; kdf_params->pAdditionalDerivedKeys = feedback_params->pAdditionalDerivedKeys; *initial_value = feedback_params->pIV; *initial_value_length = feedback_params->ulIVLen; } else { if (pMechanism->ulParameterLen != sizeof(CK_SP800_108_KDF_PARAMS)) { return CKR_MECHANISM_PARAM_INVALID; } in_params = (CK_SP800_108_KDF_PARAMS *)pMechanism->pParameter; (*kdf_params) = *in_params; } return CKR_OK; } static CK_RV kbkdf_ValidateParameter(CK_MECHANISM_TYPE mech, const CK_PRF_DATA_PARAM *data) { /* This function validates that the passed data parameter (data) conforms * to PKCS#11 v3.0's expectations for KDF parameters. This depends both on * the type of this parameter (data->type) and on the KDF mechanism (mech) * as certain parameters are context dependent (like Iteration Variable). */ /* If the parameter is missing a value when one is expected, then this * parameter is invalid. */ if ((data->pValue == NULL) != (data->ulValueLen == 0)) { return CKR_MECHANISM_PARAM_INVALID; } switch (data->type) { case CK_SP800_108_ITERATION_VARIABLE: case CK_SP800_108_OPTIONAL_COUNTER: { if (data->type == CK_SP800_108_ITERATION_VARIABLE && !IS_COUNTER(mech)) { /* In Feedback and Double Pipeline KDFs, PKCS#11 v3.0 connotes the * iteration variable as the chaining value from the previous PRF * invocation. In contrast, counter mode treats this variable as a * COUNTER_FORMAT descriptor. Thus we can skip validation of * iteration variable parameters outside of counter mode. However, * PKCS#11 v3.0 technically mandates that pValue is NULL, so we * still have to validate that. */ if (data->pValue != NULL) { return CKR_MECHANISM_PARAM_INVALID; } return CKR_OK; } /* In counter mode, data->pValue should be a pointer to an instance of * CK_SP800_108_COUNTER_FORMAT; validate its length. */ if (data->ulValueLen != sizeof(CK_SP800_108_COUNTER_FORMAT)) { return CKR_MECHANISM_PARAM_INVALID; } CK_SP800_108_COUNTER_FORMAT_PTR param = (CK_SP800_108_COUNTER_FORMAT_PTR)data->pValue; /* Validate the endian parameter. */ if (!VALID_CK_BOOL(param->bLittleEndian)) { return CKR_MECHANISM_PARAM_INVALID; } /* Due to restrictions by our underlying hashes, we restrict bit * widths to actually be byte widths by ensuring they're a multiple * of eight. */ if ((param->ulWidthInBits % 8) != 0) { return CKR_MECHANISM_PARAM_INVALID; } /* Note that section 5.1 denotes the maximum length of the counter * to be 32. */ if (param->ulWidthInBits > 32) { return CKR_MECHANISM_PARAM_INVALID; } break; } case CK_SP800_108_DKM_LENGTH: { /* data->pValue should be a pointer to an instance of * CK_SP800_108_DKM_LENGTH_FORMAT; validate its length. */ if (data->ulValueLen != sizeof(CK_SP800_108_DKM_LENGTH_FORMAT)) { return CKR_MECHANISM_PARAM_INVALID; } CK_SP800_108_DKM_LENGTH_FORMAT_PTR param = (CK_SP800_108_DKM_LENGTH_FORMAT_PTR)data->pValue; /* Validate the method parameter. */ if (param->dkmLengthMethod != CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS && param->dkmLengthMethod != CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS) { return CKR_MECHANISM_PARAM_INVALID; } /* Validate the endian parameter. */ if (!VALID_CK_BOOL(param->bLittleEndian)) { return CKR_MECHANISM_PARAM_INVALID; } /* Validate the maximum width: we restrict it to being a byte width * instead of a bit width due to restrictions by the underlying * PRFs. */ if ((param->ulWidthInBits % 8) != 0) { return CKR_MECHANISM_PARAM_INVALID; } /* Ensure that the width doesn't overflow a 64-bit int. This * restriction is arbitrary but since the counters can't exceed * 32-bits (and most PRFs output at most 1024 bits), you're unlikely * to need all 64-bits of length indicator. */ if (param->ulWidthInBits > 64) { return CKR_MECHANISM_PARAM_INVALID; } break; } case CK_SP800_108_BYTE_ARRAY: /* There is no additional data to validate for byte arrays; we can * only assume the byte array is of the specified size. */ break; default: /* Unexpected parameter type. */ return CKR_MECHANISM_PARAM_INVALID; } return CKR_OK; } static CK_RV kbkdf_ValidateDerived(CK_DERIVED_KEY_PTR key) { CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; PRUint64 keySize = 0; /* The pointer to the key handle shouldn't be NULL. If it is, we can't * do anything else, so exit early. Every other failure case sets the * key->phKey = CK_INVALID_HANDLE, so we can't use `goto failure` here. */ if (key->phKey == NULL) { return CKR_MECHANISM_PARAM_INVALID; } /* Validate that we have no attributes if and only if pTemplate is NULL. * Otherwise, there's an inconsistency somewhere. */ if ((key->ulAttributeCount == 0) != (key->pTemplate == NULL)) { goto failure; } for (size_t offset = 0; offset < key->ulAttributeCount; offset++) { CK_ATTRIBUTE_PTR template = key->pTemplate + offset; /* We only look for the CKA_VALUE_LEN and CKA_KEY_TYPE attributes. * Everything else we assume we can set on the key if it is passed * here. However, if we can't inquire as to a length (and barring * that, if we have a key type without a standard length), we're * definitely stuck. This mirrors the logic at the top of * NSC_DeriveKey(...). */ if (template->type == CKA_KEY_TYPE) { if (template->ulValueLen != sizeof(CK_KEY_TYPE)) { goto failure; } keyType = *(CK_KEY_TYPE *)template->pValue; } else if (template->type == CKA_VALUE_LEN) { if (template->ulValueLen != sizeof(CK_ULONG)) { goto failure; } keySize = *(CK_ULONG *)template->pValue; } } if (keySize == 0) { /* When we lack a keySize, see if we can infer it from the type of the * passed key. */ keySize = sftk_MapKeySize(keyType); } /* The main piece of information we validate is that we have a length for * this key. */ if (keySize == 0 || keySize >= (1ull << 32ull)) { goto failure; } return CKR_OK; failure: /* PKCS#11 v3.0: If the failure was caused by the content of a specific * key's template (ie the template defined by the content of pTemplate), * the corresponding phKey value will be set to CK_INVALID_HANDLE to * identify the offending template. */ *(key->phKey) = CK_INVALID_HANDLE; return CKR_MECHANISM_PARAM_INVALID; } static CK_RV kbkdf_ValidateParameters(CK_MECHANISM_TYPE mech, const CK_SP800_108_KDF_PARAMS *params, CK_ULONG keySize) { CK_RV ret = CKR_MECHANISM_PARAM_INVALID; int param_type_count[5] = { 0, 0, 0, 0, 0 }; size_t offset = 0; /* Start with checking the prfType as a mechanism against a list of * PRFs allowed by PKCS#11 v3.0. */ if (!(/* The following types aren't defined in NSS yet. */ /* params->prfType != CKM_3DES_CMAC && */ params->prfType == CKM_AES_CMAC || /* allow */ /* We allow any HMAC except MD2 and MD5. */ params->prfType != CKM_MD2_HMAC || /* disallow */ params->prfType != CKM_MD5_HMAC || /* disallow */ sftk_HMACMechanismToHash(params->prfType) != HASH_AlgNULL /* Valid HMAC <-> HASH isn't NULL */ )) { return CKR_MECHANISM_PARAM_INVALID; } /* We can't have a null pDataParams pointer: we always need at least one * parameter to succeed. */ if (params->pDataParams == NULL) { return CKR_HOST_MEMORY; } /* Validate each KDF parameter. */ for (offset = 0; offset < params->ulNumberOfDataParams; offset++) { /* Validate this parameter has acceptable values. */ ret = kbkdf_ValidateParameter(mech, params->pDataParams + offset); if (ret != CKR_OK) { return CKR_MECHANISM_PARAM_INVALID; } /* Count that we have a parameter of this type. The above logic * in ValidateParameter MUST validate that type is within the * appropriate range. */ PR_ASSERT(params->pDataParams[offset].type < sizeof(param_type_count) / sizeof(param_type_count[0])); param_type_count[params->pDataParams[offset].type] += 1; } if (IS_COUNTER(mech)) { /* We have to have at least one iteration variable parameter. */ if (param_type_count[CK_SP800_108_ITERATION_VARIABLE] == 0) { return CKR_MECHANISM_PARAM_INVALID; } /* We can't have any optional counters parameters -- these belong in * iteration variable parameters instead. */ if (param_type_count[CK_SP800_108_OPTIONAL_COUNTER] != 0) { return CKR_MECHANISM_PARAM_INVALID; } } /* Validate basic assumptions about derived keys: * NULL <-> ulAdditionalDerivedKeys > 0 */ if ((params->ulAdditionalDerivedKeys == 0) != (params->pAdditionalDerivedKeys == NULL)) { return CKR_MECHANISM_PARAM_INVALID; } /* Validate each derived key. */ for (offset = 0; offset < params->ulAdditionalDerivedKeys; offset++) { ret = kbkdf_ValidateDerived(params->pAdditionalDerivedKeys + offset); if (ret != CKR_OK) { return CKR_MECHANISM_PARAM_INVALID; } } /* Validate the length of our primary key. */ if (keySize == 0 || ((PRUint64)keySize) >= (1ull << 32ull)) { return CKR_KEY_SIZE_RANGE; } return CKR_OK; } /* [ section: parameter helpers ] */ static CK_VOID_PTR kbkdf_FindParameter(const CK_SP800_108_KDF_PARAMS *params, CK_PRF_DATA_TYPE type) { for (size_t offset = 0; offset < params->ulNumberOfDataParams; offset++) { if (params->pDataParams[offset].type == type) { return params->pDataParams[offset].pValue; } } return NULL; } size_t kbkdf_IncrementBuffer(size_t cur_offset, size_t consumed, size_t prf_length) { return cur_offset + PR_ROUNDUP(consumed, prf_length); } CK_ULONG kbkdf_GetDerivedKeySize(CK_DERIVED_KEY_PTR derived_key) { /* Precondition: kbkdf_ValidateDerived(...) returns CKR_OK for this key, * which implies that keySize is defined. */ CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_ULONG keySize = 0; for (size_t offset = 0; offset < derived_key->ulAttributeCount; offset++) { CK_ATTRIBUTE_PTR template = derived_key->pTemplate + offset; /* Find the two attributes we care about. */ if (template->type == CKA_KEY_TYPE) { keyType = *(CK_KEY_TYPE *)template->pValue; } else if (template->type == CKA_VALUE_LEN) { keySize = *(CK_ULONG *)template->pValue; } } /* Prefer keySize, if we have it. */ if (keySize > 0) { return keySize; } /* Else, fall back to this mapping. We know kbkdf_ValidateDerived(...) * passed, so this should return non-zero. */ return sftk_MapKeySize(keyType); } static CK_RV kbkdf_CalculateLength(const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, CK_ULONG ret_key_size, PRUint64 *output_bitlen, size_t *buffer_length) { /* Two cases: either we have additional derived keys or we don't. In the * case that we don't, the length of the derivation is the size of the * single derived key, and that is the length of the PRF buffer. Otherwise, * we need to use the proper CK_SP800_108_DKM_LENGTH_METHOD to calculate * the length of the output (in bits), with a separate value for the size * of the PRF data buffer. This means that, under PKCS#11 with additional * derived keys, we lie to the KDF about the _actual_ length of the PRF * output. * * Note that *output_bitlen is the L parameter in NIST SP800-108 and is in * bits. However, *buffer_length is in bytes. */ if (params->ulAdditionalDerivedKeys == 0) { /* When we have no additional derived keys, we get the keySize from * the value passed to one of our KBKDF_* methods. */ *output_bitlen = ret_key_size; *buffer_length = ret_key_size; } else { /* Offset in the additional derived keys array. */ size_t offset = 0; /* Size of the derived key. */ CK_ULONG derived_size = 0; /* In the below, we place the sum of the keys into *output_bitlen * and the size of the buffer (with padding mandated by PKCS#11 v3.0) * into *buffer_length. If the method is the segment sum, then we * replace *output_bitlen with *buffer_length at the end. This ensures * we always get a output buffer large enough to handle all derived * keys, and *output_bitlen reflects the correct L value. */ /* Count the initial derived key. */ *output_bitlen = ret_key_size; *buffer_length = kbkdf_IncrementBuffer(0, ret_key_size, ctx->mac_size); /* Handle n - 1 keys. The last key is special. */ for (; offset < params->ulAdditionalDerivedKeys - 1; offset++) { derived_size = kbkdf_GetDerivedKeySize(params->pAdditionalDerivedKeys + offset); *output_bitlen += derived_size; *buffer_length = kbkdf_IncrementBuffer(*buffer_length, derived_size, ctx->mac_size); } /* Handle the last key. */ derived_size = kbkdf_GetDerivedKeySize(params->pAdditionalDerivedKeys + offset); *output_bitlen += derived_size; *buffer_length = kbkdf_IncrementBuffer(*buffer_length, derived_size, ctx->mac_size); /* Pointer to the DKM method parameter. Note that this implicit cast * is safe since we've assumed we've been validated by * kbkdf_ValidateParameters(...). When kdm_param is NULL, we don't * use the output_bitlen parameter. */ CK_SP800_108_DKM_LENGTH_FORMAT_PTR dkm_param = kbkdf_FindParameter(params, CK_SP800_108_DKM_LENGTH); if (dkm_param != NULL) { if (dkm_param->dkmLengthMethod == CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS) { *output_bitlen = *buffer_length; } } } /* Note that keySize is the size in bytes and ctx->mac_size is also * the size in bytes. However, output_bitlen needs to be in bits, so * multiply by 8 here. */ *output_bitlen *= 8; return CKR_OK; } static CK_RV kbkdf_CalculateIterations(CK_MECHANISM_TYPE mech, const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, size_t buffer_length, PRUint32 *num_iterations) { CK_SP800_108_COUNTER_FORMAT_PTR param_ptr = NULL; PRUint64 iteration_count; PRUint64 r = 32; /* We need to know how many full iterations are required. This is done * by rounding up the division of the PRF length into buffer_length. * However, we're not guaranteed that the last output is a full PRF * invocation, so handle that here. */ iteration_count = buffer_length + (ctx->mac_size - 1); iteration_count = iteration_count / ctx->mac_size; /* NIST SP800-108, section 5.1, process step #2: * * if n > 2^r - 1, then indicate an error and stop. * * In non-counter mode KDFs, r is set at 32, leaving behavior * under-defined when the optional counter is included but fewer than * 32 bits. This implementation assumes r is 32, but if the counter * parameter is included, validates it against that. In counter-mode * KDFs, this is in the ITERATION_VARIABLE parameter; in feedback- or * pipeline-mode KDFs, this is in the COUNTER parameter. * * This is consistent with the supplied sample CAVP tests; none reuses the * same counter value. In some configurations, this could result in * duplicated KDF output. We seek to avoid that from happening. */ if (IS_COUNTER(mech)) { param_ptr = kbkdf_FindParameter(params, CK_SP800_108_ITERATION_VARIABLE); /* Validated by kbkdf_ValidateParameters(...) above. */ PR_ASSERT(param_ptr != NULL); r = ((CK_SP800_108_COUNTER_FORMAT_PTR)param_ptr)->ulWidthInBits; } else { param_ptr = kbkdf_FindParameter(params, CK_SP800_108_COUNTER); /* Not guaranteed to exist, hence the default value of r=32. */ if (param_ptr != NULL) { r = ((CK_SP800_108_COUNTER_FORMAT_PTR)param_ptr)->ulWidthInBits; } } if (iteration_count >= (1ull << r) || r > 32) { return CKR_MECHANISM_PARAM_INVALID; } *num_iterations = (PRUint32)iteration_count; return CKR_OK; } static CK_RV kbkdf_AddParameters(CK_MECHANISM_TYPE mech, sftk_MACCtx *ctx, const CK_SP800_108_KDF_PARAMS *params, PRUint32 counter, PRUint64 length, const unsigned char *chaining_prf, size_t chaining_prf_len, CK_PRF_DATA_TYPE exclude) { size_t offset = 0; CK_RV ret = CKR_OK; for (offset = 0; offset < params->ulNumberOfDataParams; offset++) { CK_PRF_DATA_PARAM_PTR param = params->pDataParams + offset; if (param->type == exclude) { /* Necessary for Double Pipeline mode: when constructing the IV, * we skip the optional counter. */ continue; } switch (param->type) { case CK_SP800_108_ITERATION_VARIABLE: { /* When present in COUNTER mode, this signifies adding the counter * variable to the PRF. Otherwise, it signifies the chaining * value for other KDF modes. */ if (IS_COUNTER(mech)) { CK_SP800_108_COUNTER_FORMAT_PTR counter_format = (CK_SP800_108_COUNTER_FORMAT_PTR)param->pValue; CK_BYTE buffer[sizeof(PRUint64)]; CK_ULONG num_bytes; sftk_EncodeInteger(counter, counter_format->ulWidthInBits, counter_format->bLittleEndian, buffer, &num_bytes); ret = sftk_MAC_Update(ctx, buffer, num_bytes); } else { ret = sftk_MAC_Update(ctx, chaining_prf, chaining_prf_len); } break; } case CK_SP800_108_COUNTER: { /* Only present in the case when not using COUNTER mode. */ PR_ASSERT(!IS_COUNTER(mech)); /* We should've already validated that this parameter is of * type COUNTER_FORMAT. */ CK_SP800_108_COUNTER_FORMAT_PTR counter_format = (CK_SP800_108_COUNTER_FORMAT_PTR)param->pValue; CK_BYTE buffer[sizeof(PRUint64)]; CK_ULONG num_bytes; sftk_EncodeInteger(counter, counter_format->ulWidthInBits, counter_format->bLittleEndian, buffer, &num_bytes); ret = sftk_MAC_Update(ctx, buffer, num_bytes); break; } case CK_SP800_108_BYTE_ARRAY: ret = sftk_MAC_Update(ctx, (CK_BYTE_PTR)param->pValue, param->ulValueLen); break; case CK_SP800_108_DKM_LENGTH: { /* We've already done the hard work of calculating the length in * the kbkdf_CalculateIterations function; we merely need to add * the length to the desired point in the input stream. */ CK_SP800_108_DKM_LENGTH_FORMAT_PTR length_format = (CK_SP800_108_DKM_LENGTH_FORMAT_PTR)param->pValue; CK_BYTE buffer[sizeof(PRUint64)]; CK_ULONG num_bytes; sftk_EncodeInteger(length, length_format->ulWidthInBits, length_format->bLittleEndian, buffer, &num_bytes); ret = sftk_MAC_Update(ctx, buffer, num_bytes); break; } default: /* This should've been caught by kbkdf_ValidateParameters(...). */ PR_ASSERT(PR_FALSE); return CKR_MECHANISM_PARAM_INVALID; } if (ret != CKR_OK) { return ret; } } return CKR_OK; } CK_RV kbkdf_SaveKey(SFTKObject *key, unsigned char *key_buffer, unsigned int key_len) { return sftk_forceAttribute(key, CKA_VALUE, key_buffer, key_len); } CK_RV kbkdf_CreateKey(CK_MECHANISM_TYPE kdf_mech, CK_SESSION_HANDLE hSession, CK_DERIVED_KEY_PTR derived_key, SFTKObject **ret_key) { /* Largely duplicated from NSC_DeriveKey(...) */ CK_RV ret = CKR_HOST_MEMORY; SFTKObject *key = NULL; SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession); size_t offset = 0; /* Slot should be non-NULL because NSC_DeriveKey(...) has already * performed a sftk_SlotFromSessionHandle(...) call on this session * handle. However, Coverity incorrectly flagged this (see 1607955). */ PR_ASSERT(slot != NULL); PR_ASSERT(ret_key != NULL); PR_ASSERT(derived_key != NULL); PR_ASSERT(derived_key->phKey != NULL); if (slot == NULL) { return CKR_SESSION_HANDLE_INVALID; } /* Create the new key object for this additional derived key. */ key = sftk_NewObject(slot); if (key == NULL) { return CKR_HOST_MEMORY; } /* Setup the key from the provided template. */ for (offset = 0; offset < derived_key->ulAttributeCount; offset++) { ret = sftk_AddAttributeType(key, sftk_attr_expand(derived_key->pTemplate + offset)); if (ret != CKR_OK) { sftk_FreeObject(key); return ret; } } /* When using the CKM_SP800_* series of mechanisms, the result must be a * secret key, so its contents can be adequately protected in FIPS mode. * However, when using the special CKM_NSS_SP800_*_DERIVE_DATA series, the * contents need not be protected, so we set CKO_DATA on these "keys". */ CK_OBJECT_CLASS classType = CKO_SECRET_KEY; if (DOES_DERIVE_DATA(kdf_mech)) { classType = CKO_DATA; } ret = sftk_forceAttribute(key, CKA_CLASS, &classType, sizeof(classType)); if (ret != CKR_OK) { sftk_FreeObject(key); return ret; } *ret_key = key; return CKR_OK; } CK_RV kbkdf_FinalizeKey(CK_SESSION_HANDLE hSession, CK_DERIVED_KEY_PTR derived_key, SFTKObject *key) { /* Largely duplicated from NSC_DeriveKey(...) */ CK_RV ret = CKR_HOST_MEMORY; SFTKSession *session = NULL; PR_ASSERT(derived_key != NULL && key != NULL); SFTKSessionObject *sessionForKey = sftk_narrowToSessionObject(key); PR_ASSERT(sessionForKey != NULL); sessionForKey->wasDerived = PR_TRUE; session = sftk_SessionFromHandle(hSession); /* Session should be non-NULL because NSC_DeriveKey(...) has already * performed a sftk_SessionFromHandle(...) call on this session handle. */ PR_ASSERT(session != NULL); ret = sftk_handleObject(key, session); if (ret != CKR_OK) { goto done; } *(derived_key->phKey) = key->handle; done: /* Guaranteed that key != NULL */ sftk_FreeObject(key); /* Doesn't do anything. */ if (session) { sftk_FreeSession(session); } return ret; } CK_RV kbkdf_SaveKeys(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE hSession, CK_SP800_108_KDF_PARAMS_PTR params, unsigned char *output_buffer, size_t buffer_len, size_t prf_length, SFTKObject *ret_key, CK_ULONG ret_key_size) { CK_RV ret; size_t key_offset = 0; size_t buffer_offset = 0; PR_ASSERT(output_buffer != NULL && buffer_len > 0 && ret_key != NULL); /* First place key material into the main key. */ ret = kbkdf_SaveKey(ret_key, output_buffer + buffer_offset, ret_key_size); if (ret != CKR_OK) { return ret; } /* Then increment the offset based on PKCS#11 additional key guidelines: * no two keys may share the key stream from the same PRF invocation. */ buffer_offset = kbkdf_IncrementBuffer(buffer_offset, ret_key_size, prf_length); if (params->ulAdditionalDerivedKeys > 0) { /* Note that the following code is technically incorrect: PKCS#11 v3.0 * says that _no_ key should be set in the event of failure to derive * _any_ key. */ for (key_offset = 0; key_offset < params->ulAdditionalDerivedKeys; key_offset++) { CK_DERIVED_KEY_PTR derived_key = params->pAdditionalDerivedKeys + key_offset; SFTKObject *key_obj = NULL; size_t key_size = kbkdf_GetDerivedKeySize(derived_key); /* Create a new internal key object for this derived key. */ ret = kbkdf_CreateKey(mech, hSession, derived_key, &key_obj); if (ret != CKR_OK) { *(derived_key->phKey) = CK_INVALID_HANDLE; return ret; } /* Save the underlying key bytes to the key object. */ ret = kbkdf_SaveKey(key_obj, output_buffer + buffer_offset, key_size); if (ret != CKR_OK) { /* When kbkdf_CreateKey(...) exits with an error, it will free * the constructed key object. kbkdf_FinalizeKey(...) also * always frees the key object. In the unlikely event that * kbkdf_SaveKey(...) _does_ fail, we thus need to free it * manually. */ sftk_FreeObject(key_obj); *(derived_key->phKey) = CK_INVALID_HANDLE; return ret; } /* Handle the increment. */ buffer_offset = kbkdf_IncrementBuffer(buffer_offset, key_size, prf_length); /* Finalize this key. */ ret = kbkdf_FinalizeKey(hSession, derived_key, key_obj); if (ret != CKR_OK) { *(derived_key->phKey) = CK_INVALID_HANDLE; return ret; } } } return CKR_OK; } /* [ section: KDFs ] */ static CK_RV kbkdf_CounterRaw(const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen) { CK_RV ret = CKR_OK; /* Counter variable for this KDF instance. */ PRUint32 counter; /* Number of iterations required of this PRF necessary to reach the * desired output length. */ PRUint32 num_iterations; /* Offset in ret_buffer that we're at. */ size_t buffer_offset = 0; /* Size of this block, in bytes. Defaults to ctx->mac_size except on * the last iteration where it could be a partial block. */ size_t block_size = ctx->mac_size; /* Calculate the number of iterations required based on the size of the * output buffer. */ ret = kbkdf_CalculateIterations(CKM_SP800_108_COUNTER_KDF, params, ctx, buffer_length, &num_iterations); if (ret != CKR_OK) { return ret; } /* * 5.1 - [ KDF in Counter Mode ] * * Fixed values: * 1. h - the length of the PRF in bits (ctx->mac_size) * 2. r - the length of the binary representation of the counter i * (params[k: params[k].type == CK_SP800_108_ITERATION_VARIABLE:].data->ulWidthInBits) * Input: * 1. K_I - the key for the PRF (base_key) * 2. label - a binary data field, usually before the separator. Optional. * 3. context - a binary data field, usually after the separator. Optional. * 4. L - length of the output in bits (output_bitlen) * * Process: * 1. n := ceil(L / h) (num_iterations) * 2. if n > 2^r - 1, then indicate an error and stop * 3. result(0) = NULL * 4. for i = 1 to n, do * a. K(i) = PRF(K_I, [i]_2 || Label || 0x00 || Context || [L]_2) * b. result(i) := result(i - 1) || K(i). * 5. return K_O := the leftmost L bits of result(n). */ for (counter = 1; counter <= num_iterations; counter++) { if (counter == num_iterations) { block_size = buffer_length - buffer_offset; /* Assumption: if we've validated our arguments correctly, this * should always be true. */ PR_ASSERT(block_size <= ctx->mac_size); } /* Add all parameters required by this instance of the KDF to the * input stream of the underlying PRF. */ ret = kbkdf_AddParameters(CKM_SP800_108_COUNTER_KDF, ctx, params, counter, output_bitlen, NULL, 0 /* chaining_prf output */, 0 /* exclude */); if (ret != CKR_OK) { return ret; } /* Finalize this iteration of the PRF. */ ret = sftk_MAC_Finish(ctx, ret_buffer + buffer_offset, NULL, block_size); if (ret != CKR_OK) { return ret; } /* Increment our position in the key material. */ buffer_offset += block_size; if (counter < num_iterations) { /* Reset the underlying PRF for the next iteration. Only do this * when we have a next iteration since it isn't necessary to do * either before the first iteration (MAC is already initialized) * or after the last iteration (we won't be called again). */ ret = sftk_MAC_Reset(ctx); if (ret != CKR_OK) { return ret; } } } return CKR_OK; } static CK_RV kbkdf_FeedbackRaw(const CK_SP800_108_KDF_PARAMS *params, const unsigned char *initial_value, CK_ULONG initial_value_length, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen) { CK_RV ret = CKR_OK; /* Counter variable for this KDF instance. */ PRUint32 counter; /* Number of iterations required of this PRF necessary to reach the * desired output length. */ PRUint32 num_iterations; /* Offset in ret_buffer that we're at. */ size_t buffer_offset = 0; /* Size of this block, in bytes. Defaults to ctx->mac_size except on * the last iteration where it could be a partial block. */ size_t block_size = ctx->mac_size; /* The last PRF invocation and/or the initial value; used for feedback * chaining in this KDF. Note that we have to make it large enough to * fit the output of the PRF, but we can delay its actual creation until * the first PRF invocation. Until then, point to the IV value. */ unsigned char *chaining_value = (unsigned char *)initial_value; /* Size of the chaining value discussed above. Defaults to the size of * the IV value. */ size_t chaining_length = initial_value_length; /* Calculate the number of iterations required based on the size of the * output buffer. */ ret = kbkdf_CalculateIterations(CKM_SP800_108_FEEDBACK_KDF, params, ctx, buffer_length, &num_iterations); if (ret != CKR_OK) { goto finish; } /* * 5.2 - [ KDF in Feedback Mode ] * * Fixed values: * 1. h - the length of the PRF in bits (ctx->mac_size) * 2. r - the length of the binary representation of the counter i * (params[k: params[k].type == CK_SP800_108_OPTIONAL_COUNTER:].data->ulWidthInBits) * Note that it is only specified when the optional counter is requested. * Input: * 1. K_I - the key for the PRF (base_key) * 2. label - a binary data field, usually before the separator. Optional. * 3. context - a binary data field, usually after the separator. Optional. * 4. IV - a binary data field, initial PRF value. (params->pIV) * 5. L - length of the output in bits (output_bitlen) * * Process: * 1. n := ceil(L / h) (num_iterations) * 2. if n > 2^32 - 1, then indicate an error and stop * 3. result(0) = NULL, K(0) := IV (chaining_value) * 4. for i = 1 to n, do * a. K(i) = PRF(K_I, K(i-1) {|| [i]_2} || Label || 0x00 || Context || [L]_2) * b. result(i) := result(i - 1) || K(i). * 5. return K_O := the leftmost L bits of result(n). */ for (counter = 1; counter <= num_iterations; counter++) { if (counter == num_iterations) { block_size = buffer_length - buffer_offset; /* Assumption: if we've validated our arguments correctly, this * should always be true. */ PR_ASSERT(block_size <= ctx->mac_size); } /* Add all parameters required by this instance of the KDF to the * input stream of the underlying PRF. */ ret = kbkdf_AddParameters(CKM_SP800_108_FEEDBACK_KDF, ctx, params, counter, output_bitlen, chaining_value, chaining_length, 0 /* exclude */); if (ret != CKR_OK) { goto finish; } if (counter == 1) { /* On the first iteration, chaining_value points to the IV from * the caller and chaining_length is the length of that IV. We * now need to allocate a buffer of suitable length to store the * MAC output. */ chaining_value = PORT_ZNewArray(unsigned char, ctx->mac_size); chaining_length = ctx->mac_size; if (chaining_value == NULL) { ret = CKR_HOST_MEMORY; goto finish; } } /* Finalize this iteration of the PRF. Unlike other KDF forms, we * first save this to the chaining value so that we can reuse it * in the next iteration before copying the necessary length to * the output buffer. */ ret = sftk_MAC_Finish(ctx, chaining_value, NULL, chaining_length); if (ret != CKR_OK) { goto finish; } /* Save as much of the chaining value as we need for output. */ PORT_Memcpy(ret_buffer + buffer_offset, chaining_value, block_size); /* Increment our position in the key material. */ buffer_offset += block_size; if (counter < num_iterations) { /* Reset the underlying PRF for the next iteration. Only do this * when we have a next iteration since it isn't necessary to do * either before the first iteration (MAC is already initialized) * or after the last iteration (we won't be called again). */ ret = sftk_MAC_Reset(ctx); if (ret != CKR_OK) { goto finish; } } } finish: if (chaining_value != initial_value && chaining_value != NULL) { PORT_ZFree(chaining_value, chaining_length); } return ret; } static CK_RV kbkdf_PipelineRaw(const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen) { CK_RV ret = CKR_OK; /* Counter variable for this KDF instance. */ PRUint32 counter; /* Number of iterations required of this PRF necessary to reach the * desired output length. */ PRUint32 num_iterations; /* Offset in ret_buffer that we're at. */ size_t buffer_offset = 0; /* Size of this block, in bytes. Defaults to ctx->mac_size except on * the last iteration where it could be a partial block. */ size_t block_size = ctx->mac_size; /* The last PRF invocation. This is used for the first of the double * PRF invocations this KDF is named after. This defaults to NULL, * signifying that we have to calculate the initial value from params; * when non-NULL, we directly add only this value to the PRF. */ unsigned char *chaining_value = NULL; /* Size of the chaining value discussed above. Defaults to 0. */ size_t chaining_length = 0; /* Calculate the number of iterations required based on the size of the * output buffer. */ ret = kbkdf_CalculateIterations(CKM_SP800_108_DOUBLE_PIPELINE_KDF, params, ctx, buffer_length, &num_iterations); if (ret != CKR_OK) { goto finish; } /* * 5.3 - [ KDF in Double-Pipeline Iteration Mode ] * * Fixed values: * 1. h - the length of the PRF in bits (ctx->mac_size) * 2. r - the length of the binary representation of the counter i * (params[k: params[k].type == CK_SP800_108_OPTIONAL_COUNTER:].data->ulWidthInBits) * Note that it is only specified when the optional counter is requested. * Input: * 1. K_I - the key for the PRF (base_key) * 2. label - a binary data field, usually before the separator. Optional. * 3. context - a binary data field, usually after the separator. Optional. * 4. L - length of the output in bits (output_bitlen) * * Process: * 1. n := ceil(L / h) (num_iterations) * 2. if n > 2^32 - 1, then indicate an error and stop * 3. result(0) = NULL * 4. A(0) := IV := Label || 0x00 || Context || [L]_2 * 5. for i = 1 to n, do * a. A(i) := PRF(K_I, A(i-1)) * b. K(i) := PRF(K_I, A(i) {|| [i]_2} || Label || 0x00 || Context || [L]_2 * c. result(i) := result(i-1) || K(i) * 6. return K_O := the leftmost L bits of result(n). */ for (counter = 1; counter <= num_iterations; counter++) { if (counter == num_iterations) { block_size = buffer_length - buffer_offset; /* Assumption: if we've validated our arguments correctly, this * should always be true. */ PR_ASSERT(block_size <= ctx->mac_size); } /* ===== First pipeline: construct A(i) ===== */ if (counter == 1) { /* On the first iteration, we have no chaining value so specify * NULL for the pointer and 0 for the length, and exclude the * optional counter if it exists. This is what NIST specifies as * the IV for the KDF. */ ret = kbkdf_AddParameters(CKM_SP800_108_DOUBLE_PIPELINE_KDF, ctx, params, counter, output_bitlen, NULL, 0, CK_SP800_108_OPTIONAL_COUNTER); if (ret != CKR_OK) { goto finish; } /* Allocate the chaining value so we can save the PRF output. */ chaining_value = PORT_ZNewArray(unsigned char, ctx->mac_size); chaining_length = ctx->mac_size; if (chaining_value == NULL) { ret = CKR_HOST_MEMORY; goto finish; } } else { /* On all other iterations, the next stage of the first pipeline * comes directly from this stage. */ ret = sftk_MAC_Update(ctx, chaining_value, chaining_length); if (ret != CKR_OK) { goto finish; } } /* Save the PRF output to chaining_value for use in the second * pipeline. */ ret = sftk_MAC_Finish(ctx, chaining_value, NULL, chaining_length); if (ret != CKR_OK) { goto finish; } /* Reset the PRF so we can reuse it for the second pipeline. */ ret = sftk_MAC_Reset(ctx); if (ret != CKR_OK) { goto finish; } /* ===== Second pipeline: construct K(i) ===== */ /* Add all parameters required by this instance of the KDF to the * input stream of the underlying PRF. Note that this includes the * chaining value we calculated from the previous pipeline stage. */ ret = kbkdf_AddParameters(CKM_SP800_108_FEEDBACK_KDF, ctx, params, counter, output_bitlen, chaining_value, chaining_length, 0 /* exclude */); if (ret != CKR_OK) { goto finish; } /* Finalize this iteration of the PRF directly to the output buffer. * Unlike Feedback mode, this pipeline doesn't influence the previous * stage. */ ret = sftk_MAC_Finish(ctx, ret_buffer + buffer_offset, NULL, block_size); if (ret != CKR_OK) { goto finish; } /* Increment our position in the key material. */ buffer_offset += block_size; if (counter < num_iterations) { /* Reset the underlying PRF for the next iteration. Only do this * when we have a next iteration since it isn't necessary to do * either before the first iteration (MAC is already initialized) * or after the last iteration (we won't be called again). */ ret = sftk_MAC_Reset(ctx); if (ret != CKR_OK) { goto finish; } } } finish: PORT_ZFree(chaining_value, chaining_length); return ret; } static CK_RV kbkdf_RawDispatch(CK_MECHANISM_TYPE mech, const CK_SP800_108_KDF_PARAMS *kdf_params, const CK_BYTE *initial_value, CK_ULONG initial_value_length, SFTKObject *prf_key, const unsigned char *prf_key_bytes, unsigned int prf_key_length, unsigned char **out_key_bytes, size_t *out_key_length, unsigned int *mac_size, CK_ULONG ret_key_size) { CK_RV ret; /* Context for our underlying PRF function. * * Zeroing context required unconditional call of sftk_MAC_Destroy. */ sftk_MACCtx ctx = { 0 }; /* We need one buffers large enough to fit the entire KDF key stream for * all iterations of the PRF. This needs only include to the end of the * last key, so it isn't an even multiple of the PRF output size. */ unsigned char *output_buffer = NULL; /* Size of the above buffer, in bytes. Note that this is technically * separate from the below output_bitlen variable due to the presence * of additional derived keys. See commentary in kbkdf_CalculateLength. */ size_t buffer_length = 0; /* While NIST specifies a maximum length (in bits) for the counter, they * don't for the maximum length. It is unlikely, but theoretically * possible for output of the PRF to exceed 32 bits while keeping the * counter under 2^32. Thus, use a 64-bit variable for the maximum * output length. * * It is unlikely any caller will request this much data in practice. * 2^32 invocations of the PRF (for a 512-bit PRF) would be 256GB of * data in the KDF key stream alone. The bigger limit is the number of * and size of keys (again, 2^32); this could easily exceed 256GB when * counting the backing softoken key, the key data, template data, and * the input parameters to this KDF. * * This is the L parameter in NIST SP800-108. */ PRUint64 output_bitlen = 0; /* First validate our passed input parameters against PKCS#11 v3.0 * and NIST SP800-108 requirements. */ ret = kbkdf_ValidateParameters(mech, kdf_params, ret_key_size); if (ret != CKR_OK) { goto finish; } /* Initialize the underlying PRF state. */ if (prf_key) { ret = sftk_MAC_Init(&ctx, kdf_params->prfType, prf_key); } else { ret = sftk_MAC_InitRaw(&ctx, kdf_params->prfType, prf_key_bytes, prf_key_length, PR_TRUE); } if (ret != CKR_OK) { goto finish; } /* Compute the size of our output buffer based on passed parameters and * the output size of the underlying PRF. */ ret = kbkdf_CalculateLength(kdf_params, &ctx, ret_key_size, &output_bitlen, &buffer_length); if (ret != CKR_OK) { goto finish; } /* Allocate memory for the PRF output */ output_buffer = PORT_ZNewArray(unsigned char, buffer_length); if (output_buffer == NULL) { ret = CKR_HOST_MEMORY; goto finish; } /* Call into the underlying KDF */ switch (mech) { case CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA: /* fall through */ case CKM_SP800_108_COUNTER_KDF: ret = kbkdf_CounterRaw(kdf_params, &ctx, output_buffer, buffer_length, output_bitlen); break; case CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA: /* fall through */ case CKM_SP800_108_FEEDBACK_KDF: ret = kbkdf_FeedbackRaw(kdf_params, initial_value, initial_value_length, &ctx, output_buffer, buffer_length, output_bitlen); break; case CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA: /* fall through */ case CKM_SP800_108_DOUBLE_PIPELINE_KDF: ret = kbkdf_PipelineRaw(kdf_params, &ctx, output_buffer, buffer_length, output_bitlen); break; default: /* Shouldn't happen unless NIST introduces a new KBKDF type. */ PR_ASSERT(PR_FALSE); ret = CKR_FUNCTION_FAILED; } /* Validate the above KDF succeeded. */ if (ret != CKR_OK) { goto finish; } *out_key_bytes = output_buffer; *out_key_length = buffer_length; *mac_size = ctx.mac_size; output_buffer = NULL; /* returning the buffer, don't zero and free it */ finish: PORT_ZFree(output_buffer, buffer_length); /* Free the PRF. This should handle clearing all sensitive information. */ sftk_MAC_Destroy(&ctx, PR_FALSE); return ret; } /* [ section: PKCS#11 entry ] */ CK_RV kbkdf_Dispatch(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, SFTKObject *prf_key, SFTKObject *ret_key, CK_ULONG ret_key_size) { /* This handles boilerplate common to all KBKDF types. Instead of placing * this in pkcs11c.c, place it here to reduce clutter. */ CK_RV ret; /* Assumptions about our calling environment. */ PR_ASSERT(pMechanism != NULL && prf_key != NULL && ret_key != NULL); /* Validate that the caller passed parameters. */ if (pMechanism->pParameter == NULL) { return CKR_MECHANISM_PARAM_INVALID; } /* Create a common set of parameters to use for all KDF types. This * separates out the KDF parameters from the Feedback-specific IV, * allowing us to use a common type for all calls. */ CK_SP800_108_KDF_PARAMS kdf_params = { 0 }; CK_BYTE_PTR initial_value = NULL; CK_ULONG initial_value_length = 0; unsigned char *output_buffer = NULL; size_t buffer_length = 0; unsigned int mac_size = 0; /* Split Feedback-specific IV from remaining KDF parameters. */ ret = kbkdf_LoadParameters(mech, pMechanism, &kdf_params, &initial_value, &initial_value_length); if (ret != CKR_OK) { goto finish; } /* let rawDispatch handle the rest. We split this out so we could * handle the POST test without accessing pkcs #11 objects. */ ret = kbkdf_RawDispatch(mech, &kdf_params, initial_value, initial_value_length, prf_key, NULL, 0, &output_buffer, &buffer_length, &mac_size, ret_key_size); if (ret != CKR_OK) { goto finish; } /* Write the output of the PRF into the appropriate keys. */ ret = kbkdf_SaveKeys(mech, hSession, &kdf_params, output_buffer, buffer_length, mac_size, ret_key, ret_key_size); if (ret != CKR_OK) { goto finish; } finish: PORT_ZFree(output_buffer, buffer_length); return ret; } struct sftk_SP800_Test_struct { CK_MECHANISM_TYPE mech; CK_SP800_108_KDF_PARAMS kdf_params; unsigned int expected_mac_size; unsigned int ret_key_length; const unsigned char expected_key_bytes[64]; }; static const CK_SP800_108_COUNTER_FORMAT counter_32 = { 0, 32 }; static const CK_PRF_DATA_PARAM counter_32_data = { CK_SP800_108_ITERATION_VARIABLE, (CK_VOID_PTR)&counter_32, sizeof(counter_32) }; #ifdef NSS_FULL_POST static const CK_SP800_108_COUNTER_FORMAT counter_16 = { 0, 16 }; static const CK_PRF_DATA_PARAM counter_16_data = { CK_SP800_108_ITERATION_VARIABLE, (CK_VOID_PTR)&counter_16, sizeof(counter_16) }; static const CK_PRF_DATA_PARAM counter_null_data = { CK_SP800_108_ITERATION_VARIABLE, NULL, 0 }; #endif static const struct sftk_SP800_Test_struct sftk_SP800_Tests[] = { #ifdef NSS_FULL_POST { CKM_SP800_108_COUNTER_KDF, { CKM_AES_CMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_16_data, 0, NULL }, 16, 64, { 0x7b, 0x1c, 0xe7, 0xf3, 0x14, 0x67, 0x15, 0xdd, 0xde, 0x0c, 0x09, 0x46, 0x3f, 0x47, 0x7b, 0xa6, 0xb8, 0xba, 0x40, 0x07, 0x7c, 0xe3, 0x19, 0x53, 0x26, 0xac, 0x4c, 0x2e, 0x2b, 0x37, 0x41, 0xe4, 0x1b, 0x01, 0x3f, 0x2f, 0x2d, 0x16, 0x95, 0xee, 0xeb, 0x7e, 0x72, 0x7d, 0xa4, 0xab, 0x2e, 0x67, 0x1d, 0xef, 0x6f, 0xa2, 0xc6, 0xee, 0x3c, 0xcf, 0xef, 0x88, 0xfd, 0x5c, 0x1d, 0x7b, 0xa0, 0x5a }, }, { CKM_SP800_108_COUNTER_KDF, { CKM_SHA384_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_32_data, 0, NULL }, 48, 64, { 0xe6, 0x62, 0xa4, 0x32, 0x5c, 0xe4, 0xc2, 0x28, 0x73, 0x8a, 0x5d, 0x94, 0xe7, 0x05, 0xe0, 0x5a, 0x71, 0x61, 0xb2, 0x3c, 0x51, 0x28, 0x03, 0x1d, 0xa7, 0xf5, 0x10, 0x83, 0x34, 0xdb, 0x11, 0x73, 0x92, 0xa6, 0x79, 0x74, 0x81, 0x5d, 0x22, 0x7e, 0x8d, 0xf2, 0x59, 0x14, 0x56, 0x60, 0xcf, 0xb2, 0xb3, 0xfd, 0x46, 0xfd, 0x9b, 0x74, 0xfe, 0x4a, 0x09, 0x30, 0x4a, 0xdf, 0x07, 0x43, 0xfe, 0x85 }, }, { CKM_SP800_108_COUNTER_KDF, { CKM_SHA512_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_32_data, 0, NULL }, 64, 64, { 0xb0, 0x78, 0x36, 0xe1, 0x15, 0xd6, 0xf0, 0xac, 0x68, 0x7b, 0x42, 0xd3, 0xb6, 0x82, 0x51, 0xad, 0x95, 0x0a, 0x69, 0x88, 0x84, 0xc2, 0x2e, 0x07, 0x34, 0x62, 0x8d, 0x42, 0x72, 0x0f, 0x22, 0xe6, 0xd5, 0x7f, 0x80, 0x15, 0xe6, 0x84, 0x00, 0x65, 0xef, 0x64, 0x77, 0x29, 0xd6, 0x3b, 0xc7, 0x9a, 0x15, 0x6d, 0x36, 0xf3, 0x96, 0xc9, 0x14, 0x3f, 0x2d, 0x4a, 0x7c, 0xdb, 0xc3, 0x6c, 0x3d, 0x6a }, }, { CKM_SP800_108_FEEDBACK_KDF, { CKM_AES_CMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL }, 16, 64, { 0xc0, 0xa0, 0x23, 0x96, 0x16, 0x4d, 0xd6, 0xbd, 0x2a, 0x75, 0x8e, 0x72, 0xf5, 0xc3, 0xa0, 0xb8, 0x78, 0x83, 0x15, 0x21, 0x34, 0xd3, 0xd8, 0x71, 0xc9, 0xe7, 0x4b, 0x20, 0xb7, 0x65, 0x5b, 0x13, 0xbc, 0x85, 0x54, 0xe3, 0xb6, 0xee, 0x73, 0xd5, 0xf2, 0xa0, 0x94, 0x1a, 0x79, 0x66, 0x3b, 0x1e, 0x67, 0x3e, 0x69, 0xa4, 0x12, 0x40, 0xa9, 0xda, 0x8d, 0x14, 0xb1, 0xce, 0xf1, 0x4b, 0x79, 0x4e }, }, { CKM_SP800_108_FEEDBACK_KDF, { CKM_SHA256_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL }, 32, 64, { 0x99, 0x9b, 0x08, 0x79, 0x14, 0x2e, 0x58, 0x34, 0xd7, 0x92, 0xa7, 0x7e, 0x7f, 0xc2, 0xf0, 0x34, 0xa3, 0x4e, 0x33, 0xf0, 0x63, 0x95, 0x2d, 0xad, 0xbf, 0x3b, 0xcb, 0x6d, 0x4e, 0x07, 0xd9, 0xe9, 0xbd, 0xbd, 0x77, 0x54, 0xe1, 0xa3, 0x36, 0x26, 0xcd, 0xb1, 0xf9, 0x2d, 0x80, 0x68, 0xa2, 0x01, 0x4e, 0xbf, 0x35, 0xec, 0x65, 0xae, 0xfd, 0x71, 0xa6, 0xd7, 0x62, 0x26, 0x2c, 0x3f, 0x73, 0x63 }, }, { CKM_SP800_108_FEEDBACK_KDF, { CKM_SHA384_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL }, 48, 64, { 0xc8, 0x7a, 0xf8, 0xd9, 0x6b, 0x90, 0x82, 0x35, 0xea, 0xf5, 0x2c, 0x8f, 0xce, 0xaa, 0x3b, 0xa5, 0x68, 0xd3, 0x7f, 0xae, 0x31, 0x93, 0xe6, 0x69, 0x0c, 0xd1, 0x74, 0x7f, 0x8f, 0xc2, 0xe2, 0x33, 0x93, 0x45, 0x23, 0xba, 0xb3, 0x73, 0xc9, 0x2c, 0xd6, 0xd2, 0x10, 0x16, 0xe9, 0x9f, 0x9e, 0xe8, 0xc1, 0x0e, 0x29, 0x95, 0x3d, 0x16, 0x68, 0x24, 0x40, 0x4d, 0x40, 0x21, 0x41, 0xa6, 0xc8, 0xdb }, }, { CKM_SP800_108_FEEDBACK_KDF, { CKM_SHA512_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL }, 64, 64, { 0x81, 0x39, 0x12, 0xc2, 0xf9, 0x31, 0x24, 0x7c, 0x71, 0x12, 0x97, 0x08, 0x82, 0x76, 0x83, 0x55, 0x8c, 0x82, 0xf3, 0x09, 0xd6, 0x1b, 0x7a, 0xa2, 0x6e, 0x71, 0x6b, 0xad, 0x46, 0x57, 0x60, 0x89, 0x38, 0xcf, 0x63, 0xfa, 0xf4, 0x38, 0x27, 0xef, 0xf0, 0xaf, 0x75, 0x4e, 0xc2, 0xe0, 0x31, 0xdb, 0x59, 0x7d, 0x19, 0xc9, 0x6d, 0xbb, 0xed, 0x95, 0xaf, 0x3e, 0xd8, 0x33, 0x76, 0xab, 0xec, 0xfa }, }, { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { CKM_AES_CMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL }, 16, 64, { 0x3e, 0xa8, 0xbf, 0x77, 0x84, 0x90, 0xb0, 0x3a, 0x89, 0x16, 0x32, 0x01, 0x92, 0xd3, 0x1f, 0x1b, 0xc1, 0x06, 0xc5, 0x32, 0x62, 0x03, 0x50, 0x16, 0x3b, 0xb9, 0xa7, 0xdc, 0xb5, 0x68, 0x6a, 0xbb, 0xbb, 0x7d, 0x63, 0x69, 0x24, 0x6e, 0x09, 0xd6, 0x6f, 0x80, 0x57, 0x65, 0xc5, 0x62, 0x33, 0x96, 0x69, 0xe6, 0xab, 0x65, 0x36, 0xd0, 0xe2, 0x5c, 0xd7, 0xbd, 0xe4, 0x68, 0x13, 0xd6, 0xb1, 0x46 }, }, { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { CKM_SHA256_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL }, 32, 64, { 0xeb, 0x28, 0xd9, 0x2c, 0x19, 0x33, 0xb9, 0x2a, 0xf9, 0xac, 0x85, 0xbd, 0xf4, 0xdb, 0xfa, 0x88, 0x73, 0xf4, 0x36, 0x08, 0xdb, 0xfe, 0x13, 0xd1, 0x5a, 0xec, 0x7b, 0x68, 0x13, 0x53, 0xb3, 0xd1, 0x31, 0xf2, 0x83, 0xae, 0x9f, 0x75, 0x47, 0xb6, 0x6d, 0x3c, 0x20, 0x16, 0x47, 0x9c, 0x27, 0x66, 0xec, 0xa9, 0xdf, 0x0c, 0xda, 0x2a, 0xf9, 0xf4, 0x55, 0x74, 0xde, 0x9d, 0x3f, 0xe3, 0x5e, 0x14 }, }, { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { CKM_SHA384_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL }, 48, 64, { 0xa5, 0xca, 0x32, 0x40, 0x00, 0x93, 0xb2, 0xcc, 0x78, 0x3c, 0xa6, 0xc4, 0xaf, 0xa8, 0xb3, 0xd0, 0xa4, 0x6b, 0xb5, 0x31, 0x35, 0x87, 0x33, 0xa2, 0x6a, 0x6b, 0xe1, 0xff, 0xea, 0x1d, 0x6e, 0x9e, 0x0b, 0xde, 0x8b, 0x92, 0x15, 0xd6, 0x56, 0x2f, 0xb6, 0x1a, 0xd7, 0xd2, 0x01, 0x3e, 0x28, 0x2e, 0xfa, 0x84, 0x3c, 0xc0, 0xe8, 0xbe, 0x94, 0xc0, 0x06, 0xbd, 0xbf, 0x87, 0x1f, 0xb8, 0x64, 0xc2 }, }, { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { CKM_SHA512_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL }, 64, 64, { 0x3f, 0xd9, 0x4e, 0x80, 0x58, 0x21, 0xc8, 0xea, 0x22, 0x17, 0xcf, 0x7d, 0xce, 0xfd, 0xec, 0x03, 0xb9, 0xe4, 0xa2, 0xf7, 0xc0, 0xf1, 0x68, 0x81, 0x53, 0x71, 0xb7, 0x42, 0x14, 0x4e, 0x5b, 0x09, 0x05, 0x31, 0xb9, 0x27, 0x18, 0x2d, 0x23, 0xf8, 0x9c, 0x3d, 0x4e, 0xd0, 0xdd, 0xf3, 0x1e, 0x4b, 0xf2, 0xf9, 0x1a, 0x5d, 0x00, 0x66, 0x22, 0x83, 0xae, 0x3c, 0x53, 0xd2, 0x54, 0x4b, 0x06, 0x4c }, }, #endif { CKM_SP800_108_COUNTER_KDF, { CKM_SHA256_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_32_data, 0, NULL }, 32, 64, { 0xfb, 0x2b, 0xb5, 0xde, 0xce, 0x5a, 0x2b, 0xdc, 0x25, 0x8f, 0x54, 0x17, 0x4b, 0x5a, 0xa7, 0x90, 0x64, 0x36, 0xeb, 0x43, 0x1f, 0x1d, 0xf9, 0x23, 0xb2, 0x22, 0x29, 0xa0, 0xfa, 0x2e, 0x21, 0xb6, 0xb7, 0xfb, 0x27, 0x0a, 0x1c, 0xa6, 0x58, 0x43, 0xa1, 0x16, 0x44, 0x29, 0x4b, 0x1c, 0xb3, 0x72, 0xd5, 0x98, 0x9d, 0x27, 0xd5, 0x75, 0x25, 0xbf, 0x23, 0x61, 0x40, 0x48, 0xbb, 0x0b, 0x49, 0x8e }, } }; SECStatus sftk_fips_SP800_108_PowerUpSelfTests(void) { int i; CK_RV crv; const unsigned char prf_key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78 }; for (i = 0; i < PR_ARRAY_SIZE(sftk_SP800_Tests); i++) { const struct sftk_SP800_Test_struct *test = &sftk_SP800_Tests[i]; unsigned char *output_buffer; size_t buffer_length; unsigned int mac_size; crv = kbkdf_RawDispatch(test->mech, &test->kdf_params, prf_key, test->expected_mac_size, NULL, prf_key, test->expected_mac_size, &output_buffer, &buffer_length, &mac_size, test->ret_key_length); if (crv != CKR_OK) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } if ((mac_size != test->expected_mac_size) || (buffer_length != test->ret_key_length) || (output_buffer == NULL) || (PORT_Memcmp(output_buffer, test->expected_key_bytes, buffer_length) != 0)) { PORT_ZFree(output_buffer, buffer_length); return SECFailure; } PORT_ZFree(output_buffer, buffer_length); } return SECSuccess; }