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 /lib/softoken | |
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
Diffstat (limited to 'lib/softoken')
-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 |
4 files changed, 90 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); } |