summaryrefslogtreecommitdiff
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
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
-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
-rw-r--r--lib/util/pkcs11n.h22
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:
*