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 *toPKCS#11v3.0'sexpectationsforKDFparameters.Thisdependsbothon *thetypeofthisparameter(data->type)andontheKDFmechanism(mech) *ascertainparametersarecontextdependent(likeIterationVariable).
*/
/* 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 *iterationvariableasthechainingvaluefromthepreviousPRF *invocation.Incontrast,countermodetreatsthisvariableasa *COUNTER_FORMATdescriptor.Thuswecanskipvalidationof *iterationvariableparametersoutsideofcountermode.However, *PKCS#11v3.0technicallymandatesthatpValueisNULL,sowe
* 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;
}
/* 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 *widthstoactuallybebytewidthsbyensuringthey'reamultiple
* 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;
}
/* 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 *insteadofabitwidthduetorestrictionsbytheunderlying
* PRFs. */ if ((param->ulWidthInBits % 8) != 0) { return CKR_MECHANISM_PARAM_INVALID;
}
/* Ensure that the width doesn't overflow a 64-bit int. This *restrictionisarbitrarybutsincethecounterscan'texceed *32-bits(andmostPRFsoutputatmost1024bits),you'reunlikely
* 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;
}
/* The pointer to the key handle shouldn't be NULL. If it is, we can't *doanythingelse,soexitearly.Everyotherfailurecasesetsthe
* 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;
}
/* We only look for the CKA_VALUE_LEN and CKA_KEY_TYPE attributes. *Everythingelseweassumewecansetonthekeyifitispassed *here.However,ifwecan'tinquireastoalength(andbarring *that,ifwehaveakeytypewithoutastandardlength),we're *definitelystuck.Thismirrorsthelogicatthetopof
* NSC_DeriveKey(...). */ if (template->type == CKA_KEY_TYPE) { if (template->ulValueLen != sizeof(CK_KEY_TYPE)) { goto failure;
}
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'stemplate(iethetemplatedefinedbythecontentofpTemplate), *thecorrespondingphKeyvaluewillbesettoCK_INVALID_HANDLEto
* identify the offending template. */
*(key->phKey) = CK_INVALID_HANDLE; return CKR_MECHANISM_PARAM_INVALID;
}
static PRBool
kbkdf_ValidPRF(CK_SP800_108_PRF_TYPE prf)
{ // See Table 161 of PKCS#11 v3.0 or Table 192 of PKCS#11 v3.1. switch (prf) { case CKM_AES_CMAC: /* case CKM_DES3_CMAC: */ return PR_TRUE; case CKM_SHA_1_HMAC: case CKM_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: case CKM_SHA3_224_HMAC: case CKM_SHA3_256_HMAC: case CKM_SHA3_384_HMAC: case CKM_SHA3_512_HMAC: /* Valid HMAC <-> HASH isn't NULL */ return sftk_HMACMechanismToHash(prf) != HASH_AlgNULL;
} return PR_FALSE;
}
/* Start with checking the prfType as a mechanism against a list of
* PRFs allowed by PKCS#11 v3.0. */ if (!kbkdf_ValidPRF(params->prfType)) { 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 *inValidateParameterMUSTvalidatethattypeiswithinthe
* 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;
}
}
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. */
/* Find the two attributes we care about. */ if (template->type == CKA_KEY_TYPE) {
keyType = *(CK_KEY_TYPE *)template->pValue;
} elseif (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 *casethatwedon't,thelengthofthederivationisthesizeofthe *singlederivedkey,andthatisthelengthofthePRFbuffer.Otherwise, *weneedtousetheproperCK_SP800_108_DKM_LENGTH_METHODtocalculate *thelengthoftheoutput(inbits),withaseparatevalueforthesize *ofthePRFdatabuffer.Thismeansthat,underPKCS#11withadditional *derivedkeys,welietotheKDFaboutthe_actual_lengthofthePRF *output. * *Notethat*output_bitlenistheLparameterinNISTSP800-108andisin *bits.However,*buffer_lengthisinbytes.
*/
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 *andthesizeofthebuffer(withpaddingmandatedbyPKCS#11v3.0) *into*buffer_length.Ifthemethodisthesegmentsum,thenwe *replace*output_bitlenwith*buffer_lengthattheend.Thisensures *wealwaysgetaoutputbufferlargeenoughtohandleallderived
* keys, and *output_bitlen reflects the correct L value. */
/* Pointer to the DKM method parameter. Note that this implicit cast *issafesincewe'veassumedwe'vebeenvalidatedby *kbkdf_ValidateParameters(...).Whenkdm_paramisNULL,wedon'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 *thesizeinbytes.However,output_bitlenneedstobeinbits,so
* multiply by 8 here. */
*output_bitlen *= 8;
/* We need to know how many full iterations are required. This is done *byroundingupthedivisionofthePRFlengthintobuffer_length. *However,we'renotguaranteedthatthelastoutputisafullPRF
* invocation, so handle that here. */
iteration_count = buffer_length + (ctx->mac_size - 1);
iteration_count = iteration_count / ctx->mac_size;
/* 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;
}
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 *variabletothePRF.Otherwise,itsignifiesthechaining
* 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 *thekbkdf_CalculateIterationsfunction;wemerelyneedtoadd
* 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;
}
/* Slot should be non-NULL because NSC_DeriveKey(...) has already *performedasftk_SlotFromSessionHandle(...)callonthissession
* 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 *secretkey,soitscontentscanbeadequatelyprotectedinFIPSmode. *However,whenusingthespecialCKM_NSS_SP800_*_DERIVE_DATAseries,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;
}
/* 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);
}
/* 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 *saysthat_no_keyshouldbesetintheeventoffailuretoderive
* _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 *theconstructedkeyobject.kbkdf_FinalizeKey(...)also *alwaysfreesthekeyobject.Intheunlikelyeventthat *kbkdf_SaveKey(...)_does_fail,wethusneedtofreeit
* 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;
}
}
}
/* 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;
}
/* 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_End(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 *whenwehaveanextiterationsinceitisn'tnecessarytodo *eitherbeforethefirstiteration(MACisalreadyinitialized)
* or after the last iteration (we won't be called again). */
ret = sftk_MAC_Reset(ctx); if (ret != CKR_OK) { return ret;
}
}
}
/* 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 *chaininginthisKDF.Notethatwehavetomakeitlargeenoughto *fittheoutputofthePRF,butwecandelayitsactualcreationuntil
* the first PRF invocation. Until then, point to the IV value. */ unsignedchar *chaining_value = (unsignedchar *)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;
}
/* 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 *thecallerandchaining_lengthisthelengthofthatIV.We *nowneedtoallocateabufferofsuitablelengthtostorethe
* MAC output. */
chaining_value = PORT_ZNewArray(unsignedchar, 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 *firstsavethistothechainingvaluesothatwecanreuseit *inthenextiterationbeforecopyingthenecessarylengthto
* the output buffer. */
ret = sftk_MAC_End(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 *whenwehaveanextiterationsinceitisn'tnecessarytodo *eitherbeforethefirstiteration(MACisalreadyinitialized)
* or after the last iteration (we won't be called again). */
ret = sftk_MAC_Reset(ctx); if (ret != CKR_OK) { goto finish;
}
}
}
/* 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 *PRFinvocationsthisKDFisnamedafter.ThisdefaultstoNULL, *signifyingthatwehavetocalculatetheinitialvaluefromparams;
* when non-NULL, we directly add only this value to the PRF. */ unsignedchar *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;
}
/* 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 *NULLforthepointerand0forthelength,andexcludethe *optionalcounterifitexists.ThisiswhatNISTspecifiesas
* 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(unsignedchar, 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_End(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 *inputstreamoftheunderlyingPRF.Notethatthisincludesthe
* 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. *UnlikeFeedbackmode,thispipelinedoesn'tinfluencetheprevious
* stage. */
ret = sftk_MAC_End(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 *whenwehaveanextiterationsinceitisn'tnecessarytodo *eitherbeforethefirstiteration(MACisalreadyinitialized)
* or after the last iteration (we won't be called again). */
ret = sftk_MAC_Reset(ctx); if (ret != CKR_OK) { goto finish;
}
}
}
/* We need one buffers large enough to fit the entire KDF key stream for *alliterationsofthePRF.Thisneedsonlyincludetotheendofthe
* last key, so it isn't an even multiple of the PRF output size. */ unsignedchar *output_buffer = NULL;
/* Size of the above buffer, in bytes. Note that this is technically *separatefromthebelowoutput_bitlenvariableduetothepresence *ofadditionalderivedkeys.Seecommentaryinkbkdf_CalculateLength.
*/
size_t buffer_length = 0;
/* While NIST specifies a maximum length (in bits) for the counter, they *don'tforthemaximumlength.Itisunlikely,buttheoretically *possibleforoutputofthePRFtoexceed32bitswhilekeepingthe *counterunder2^32.Thus,usea64-bitvariableforthemaximum *outputlength. * *Itisunlikelyanycallerwillrequestthismuchdatainpractice. *2^32invocationsofthePRF(fora512-bitPRF)wouldbe256GBof *dataintheKDFkeystreamalone.Thebiggerlimitisthenumberof *andsizeofkeys(again,2^32);thiscouldeasilyexceed256GBwhen *countingthebackingsoftokenkey,thekeydata,templatedata,and *theinputparameterstothisKDF. * *ThisistheLparameterinNISTSP800-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(unsignedchar, 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;
}
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_DestroyContext(&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. */
/* 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 *separatesouttheKDFparametersfromtheFeedback-specificIV,
* 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; unsignedchar *output_buffer = NULL;
size_t buffer_length = 0; unsignedint 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.