diff options
author | Robert Relyea <rrelyea@redhat.com> | 2020-04-20 16:58:16 -0700 |
---|---|---|
committer | Robert Relyea <rrelyea@redhat.com> | 2020-04-20 16:58:16 -0700 |
commit | 9edf1501af90dc1e2a35a6311ba1f2b7f418b85c (patch) | |
tree | 77dad4256198f72b2ca1e8dd490e42a5caa0ff25 | |
parent | 11e48eaa16418b24b2700cf3935125a4e43f1212 (diff) | |
download | nss-hg-9edf1501af90dc1e2a35a6311ba1f2b7f418b85c.tar.gz |
Bug 1629663 NSS missing IKEv1 Quick Mode KDF prf r=kjacobs
We found another KDF function in libreswan that is not using the NSS KDF API.
Unfortunately, it seems the existing IKE KDF's in NSS are not usable for the
Quick Mode use.
The libreswan code is in compute_proto_keymat() and the specification is in https://tools.ietf.org/html/rfc2409#section-5.5
It needs:
KEYMAT = prf(SKEYID_d, [g(qm)^xy ] | protocol | SPI | Ni_b | Nr_b).
which an be thought of as:
KEYMAT = prf(KEY, [KEY] | BYTES)
but with the kicker that it also does multiple rounds aka key expansion:
KEYMAT = K1 | K2 | K3 | ...
where
K1 = prf(KEY, [KEY] | BYTES)
K2 = prf(KEY, K1 | [KEY] | BYTES)
K3 = prf(KEY, K1 | [KEY] | BYTES)
etc.
to generate the needed keying material >PRF size
This patch implements this by extendind the Appendix B Mechanism to take
and optional key and data in a new Mechanism parameter structure. Which
flavor is used (old CK_MECHANISM_TYPE or the new parameter) is determined by
the mechanism parameter lengths. Application which try to use this new feature
on old versions of NSS will get an error (rather than invalid data).
Differential Revision: https://phabricator.services.mozilla.com/D71813
-rw-r--r-- | lib/softoken/pkcs11.c | 5 | ||||
-rw-r--r-- | lib/softoken/pkcs11c.c | 18 | ||||
-rw-r--r-- | lib/softoken/pkcs11i.h | 3 | ||||
-rw-r--r-- | lib/softoken/sftkike.c | 89 | ||||
-rw-r--r-- | lib/util/pkcs11n.h | 22 |
5 files changed, 112 insertions, 25 deletions
diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c index 7961244a5..c9f01483c 100644 --- a/lib/softoken/pkcs11.c +++ b/lib/softoken/pkcs11.c @@ -383,7 +383,7 @@ static const struct mechanismList mechanisms[] = { { CKM_AES_CTS, { 16, 32, CKF_EN_DE }, PR_TRUE }, { CKM_AES_CTR, { 16, 32, CKF_EN_DE }, PR_TRUE }, { CKM_AES_GCM, { 16, 32, CKF_EN_DE_MSG }, PR_TRUE }, - { CKM_AES_XCBC_MAC_96, { 16, 16, CKF_SN_VR }, PR_TRUE }, + { CKM_AES_XCBC_MAC_96, { 12, 12, CKF_SN_VR }, PR_TRUE }, { CKM_AES_XCBC_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE }, /* ------------------------- Camellia Operations --------------------- */ { CKM_CAMELLIA_KEY_GEN, { 16, 32, CKF_GENERATE }, PR_TRUE }, @@ -586,7 +586,8 @@ static const struct mechanismList mechanisms[] = { /* --------------------IPSEC ----------------------- */ { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE }, { CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE }, - { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE } + { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE }, + { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE } }; static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]); diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c index f6dfeded4..65c94d0a8 100644 --- a/lib/softoken/pkcs11c.c +++ b/lib/softoken/pkcs11c.c @@ -6968,6 +6968,8 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, HASH_HashType hashType; CK_MECHANISM_TYPE hashMech; PRBool extractValue = PR_TRUE; + CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS ikeAppB; + CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS *pIkeAppB; CHECK_FORK(); @@ -7122,14 +7124,22 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, key, keySize); break; case CKM_NSS_IKE1_APP_B_PRF_DERIVE: - if (pMechanism->ulParameterLen != + pIkeAppB = (CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS *)pMechanism->pParameter; + if (pMechanism->ulParameterLen == sizeof(CK_MECHANISM_TYPE)) { + ikeAppB.prfMechanism = *(CK_MECHANISM_TYPE *)pMechanism->pParameter; + ikeAppB.bHasKeygxy = PR_FALSE; + ikeAppB.hKeygxy = CK_INVALID_HANDLE; + ikeAppB.pExtraData = NULL; + ikeAppB.ulExtraDataLen = 0; + pIkeAppB = &ikeAppB; + } else if (pMechanism->ulParameterLen != + sizeof(CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS)) { crv = CKR_MECHANISM_PARAM_INVALID; break; } - crv = sftk_ike1_appendix_b_prf(hSession, att, - (CK_MECHANISM_TYPE *)pMechanism->pParameter, - key, keySize); + crv = sftk_ike1_appendix_b_prf(hSession, att, pIkeAppB, key, + keySize); break; case CKM_NSS_IKE_PRF_PLUS_DERIVE: if (pMechanism->ulParameterLen != diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h index b2fb85969..1630442c9 100644 --- a/lib/softoken/pkcs11i.h +++ b/lib/softoken/pkcs11i.h @@ -813,7 +813,8 @@ extern CK_RV sftk_ike1_prf(CK_SESSION_HANDLE hSession, unsigned int keySize); extern CK_RV sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, - const CK_MECHANISM_TYPE *params, SFTKObject *outKey, + const CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS *params, + SFTKObject *outKey, unsigned int keySize); extern CK_RV sftk_ike_prf_plus(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, diff --git a/lib/softoken/sftkike.c b/lib/softoken/sftkike.c index 7d5370bd4..97bfc6f8a 100644 --- a/lib/softoken/sftkike.c +++ b/lib/softoken/sftkike.c @@ -697,18 +697,22 @@ fail: * This function returns (from rfc2409 appendix b): * Ka = K1 | K2 | K3 | K4 |... Kn * where: - * K1 = prf(K, 0x00) - * K2 = prf(K, K1) - * K3 = prf(K, K2) - * K4 = prf(K, K3) + * K1 = prf(K, [gxyKey]|[extraData]) or prf(K, 0) if gxyKey and extraData + * ar not present. + * K2 = prf(K, K1|[gxyKey]|[extraData]) + * K3 = prf(K, K2|[gxyKey]|[extraData]) + * K4 = prf(K, K3|[gxyKey]|[extraData]) * . - * Kn = prf(K, K(n-1)) + * Kn = prf(K, K(n-1)|[gxyKey]|[extraData]) * K = inKey */ CK_RV sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, - const CK_MECHANISM_TYPE *mech, SFTKObject *outKey, unsigned int keySize) + const CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS *params, + SFTKObject *outKey, unsigned int keySize) { + SFTKAttribute *gxyKeyValue = NULL; + SFTKObject *gxyKeyObj = NULL; unsigned char *outKeyData = NULL; unsigned char *thisKey = NULL; unsigned char *lastKey = NULL; @@ -718,7 +722,28 @@ sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, CK_RV crv; prfContext context; - crv = prf_setup(&context, *mech); + if ((params->ulExtraDataLen != 0) && (params->pExtraData == NULL)) { + return CKR_ARGUMENTS_BAD; + } + if (params->bHasKeygxy) { + SFTKSession *session; + session = sftk_SessionFromHandle(hSession); + if (session == NULL) { + return CKR_SESSION_HANDLE_INVALID; + } + gxyKeyObj = sftk_ObjectFromHandle(params->hKeygxy, session); + sftk_FreeSession(session); + if (gxyKeyObj == NULL) { + crv = CKR_KEY_HANDLE_INVALID; + goto fail; + } + gxyKeyValue = sftk_FindAttribute(gxyKeyObj, CKA_VALUE); + if (gxyKeyValue == NULL) { + crv = CKR_KEY_HANDLE_INVALID; + goto fail; + } + } + crv = prf_setup(&context, params->prfMechanism); if (crv != CKR_OK) { return crv; } @@ -741,25 +766,47 @@ sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, } /* - * this loop generates on block of the prf, basically - * kn = prf(key, Kn-1) - * Kn is thisKey, Kn-1 is lastKey - * key is inKey - */ + * this loop generates on block of the prf, basically + * kn = prf(key, Kn-1 | [Keygxy] | [ExtraData]) + * Kn is thisKey, Kn-1 is lastKey + * key is inKey + */ thisKey = outKeyData; for (genKeySize = 0; genKeySize <= keySize; genKeySize += macSize) { + PRBool hashedData = PR_FALSE; crv = prf_init(&context, inKey->attrib.pValue, inKey->attrib.ulValueLen); if (crv != CKR_OK) { goto fail; } - if (lastKey == NULL) { - const unsigned char zero = 0; - crv = prf_update(&context, &zero, 1); - } else { + if (lastKey != NULL) { crv = prf_update(&context, lastKey, macSize); + if (crv != CKR_OK) { + goto fail; + } + hashedData = PR_TRUE; } - if (crv != CKR_OK) { - goto fail; + if (gxyKeyValue != NULL) { + crv = prf_update(&context, gxyKeyValue->attrib.pValue, + gxyKeyValue->attrib.ulValueLen); + if (crv != CKR_OK) { + goto fail; + } + hashedData = PR_TRUE; + } + if (params->ulExtraDataLen != 0) { + crv = prf_update(&context, params->pExtraData, params->ulExtraDataLen); + if (crv != CKR_OK) { + goto fail; + } + hashedData = PR_TRUE; + } + /* if we haven't hashed anything yet, hash a zero */ + if (hashedData == PR_FALSE) { + const unsigned char zero = 0; + crv = prf_update(&context, &zero, 1); + if (crv != CKR_OK) { + goto fail; + } } crv = prf_final(&context, thisKey, macSize); if (crv != CKR_OK) { @@ -770,6 +817,12 @@ sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey, } crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize); fail: + if (gxyKeyValue) { + sftk_FreeAttribute(gxyKeyValue); + } + if (gxyKeyObj) { + sftk_FreeObject(gxyKeyObj); + } if (outKeyData) { PORT_ZFree(outKeyData, outKeySize); } diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h index afb78f475..193985044 100644 --- a/lib/util/pkcs11n.h +++ b/lib/util/pkcs11n.h @@ -427,6 +427,28 @@ typedef struct CK_NSS_IKE1_PRF_DERIVE_PARAMS { CK_BYTE keyNumber; } CK_NSS_IKE1_PRF_DERIVE_PARAMS; +/* CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS is a structure that provides the + * parameters to the CKM_NSS_IKE_APP_B_PRF_DERIVE mechanism. + * + * The fields of the structure have the following meanings: + * prfMechanism underlying MAC mechanism used to generate the prf. + * bHasKeygxy hKeygxy exists + * hKeygxy optional key to hash in the prf + * pExtraData optional extra data to hash in the prf + * ulExtraData length of the optional extra data. + * + * CK_NSS_IKE_APP_B_PRF_DERIVE can take wither CK_NSS_IKE1_APP_B_PRF_DRIVE_PARAMS + * or a single CK_MECHANISM_TYPE. In the latter cases bHashKeygx is assumed to + * be false and ulExtraDataLen is assumed to be '0'. + */ +typedef struct CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS { + CK_MECHANISM_TYPE prfMechanism; + CK_BBOOL bHasKeygxy; + CK_OBJECT_HANDLE hKeygxy; + CK_BYTE_PTR pExtraData; + CK_ULONG ulExtraDataLen; +} CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS; + /* * Parameter for the TLS extended master secret key derivation mechanisms: * |