summaryrefslogtreecommitdiff
path: root/lib/softoken
diff options
context:
space:
mode:
authorRobert Relyea <rrelyea@redhat.com>2020-04-20 16:58:16 -0700
committerRobert Relyea <rrelyea@redhat.com>2020-04-20 16:58:16 -0700
commit9edf1501af90dc1e2a35a6311ba1f2b7f418b85c (patch)
tree77dad4256198f72b2ca1e8dd490e42a5caa0ff25 /lib/softoken
parent11e48eaa16418b24b2700cf3935125a4e43f1212 (diff)
downloadnss-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.c5
-rw-r--r--lib/softoken/pkcs11c.c18
-rw-r--r--lib/softoken/pkcs11i.h3
-rw-r--r--lib/softoken/sftkike.c89
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);
}