commit d7e5aa80ad88d34884d838b6ade7b7f5769a6a60
Author: Hans Petter Jansson <hpj@cl.no>
Date:   Fri Oct 20 00:36:30 2017 +0200

    Make TLS 1.0 PRF work in FIPS mode.

diff --git a/nss/lib/freebl/md5.c b/nss/lib/freebl/md5.c
index b3a796b..b2072cb 100644
--- a/nss/lib/freebl/md5.c
+++ b/nss/lib/freebl/md5.c
@@ -217,13 +217,11 @@ MD5_HashBuf(unsigned char *dest, const unsigned char *src, PRUint32 src_length)
 }
 
 MD5Context *
-MD5_NewContext(void)
+MD5_NewContext_NonFIPS(void)
 {
     /* no need to ZAlloc, MD5_Begin will init the context */
     MD5Context *cx;
 
-    IN_FIPS_RETURN(NULL);
-
     cx = (MD5Context *)PORT_Alloc(sizeof(MD5Context));
     if (cx == NULL) {
         PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
@@ -232,6 +230,13 @@ MD5_NewContext(void)
     return cx;
 }
 
+MD5Context *
+MD5_NewContext(void)
+{
+    IN_FIPS_RETURN(NULL);
+    return MD5_NewContext_NonFIPS();
+}
+
 void
 MD5_DestroyContext(MD5Context *cx, PRBool freeit)
 {
@@ -243,10 +248,8 @@ MD5_DestroyContext(MD5Context *cx, PRBool freeit)
 }
 
 void
-MD5_Begin(MD5Context *cx)
+MD5_Begin_NonFIPS(MD5Context *cx)
 {
-    IN_FIPS_RETURN();
-
     cx->lsbInput = 0;
     cx->msbInput = 0;
     /*  memset(cx->inBuf, 0, sizeof(cx->inBuf)); */
@@ -256,6 +259,13 @@ MD5_Begin(MD5Context *cx)
     cx->cv[3] = CV0_4;
 }
 
+void
+MD5_Begin(MD5Context *cx)
+{
+    IN_FIPS_RETURN();
+    MD5_Begin_NonFIPS(cx);
+}
+
 #define cls(i32, s) (tmp = i32, tmp << s | tmp >> (32 - s))
 
 #if defined(SOLARIS) || defined(HPUX)
@@ -431,14 +441,12 @@ md5_compress(MD5Context *cx, const PRUint32 *wBuf)
 }
 
 void
-MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen)
+MD5_Update_NonFIPS(MD5Context *cx, const unsigned char *input, unsigned int inputLen)
 {
     PRUint32 bytesToConsume;
     PRUint32 inBufIndex = cx->lsbInput & 63;
     const PRUint32 *wBuf;
 
-    IN_FIPS_RETURN();
-
     /* Add the number of input bytes to the 64-bit input counter. */
     addto64(cx->msbInput, cx->lsbInput, inputLen);
     if (inBufIndex) {
@@ -487,6 +495,13 @@ MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen)
         memcpy(cx->inBuf, input, inputLen);
 }
 
+void
+MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen)
+{
+    IN_FIPS_RETURN();
+    MD5_Update_NonFIPS(cx, input, inputLen);
+}
+
 static const unsigned char padbytes[] = {
     0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -503,8 +518,8 @@ static const unsigned char padbytes[] = {
 };
 
 void
-MD5_End(MD5Context *cx, unsigned char *digest,
-        unsigned int *digestLen, unsigned int maxDigestLen)
+MD5_End_NonFIPS(MD5Context *cx, unsigned char *digest,
+                       unsigned int *digestLen, unsigned int maxDigestLen)
 {
 #ifndef IS_LITTLE_ENDIAN
     PRUint32 tmp;
@@ -512,8 +527,6 @@ MD5_End(MD5Context *cx, unsigned char *digest,
     PRUint32 lowInput, highInput;
     PRUint32 inBufIndex = cx->lsbInput & 63;
 
-    IN_FIPS_RETURN();
-
     if (maxDigestLen < MD5_HASH_LEN) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return;
@@ -525,10 +538,10 @@ MD5_End(MD5Context *cx, unsigned char *digest,
     lowInput <<= 3;
 
     if (inBufIndex < MD5_END_BUFFER) {
-        MD5_Update(cx, padbytes, MD5_END_BUFFER - inBufIndex);
+        MD5_Update_NonFIPS(cx, padbytes, MD5_END_BUFFER - inBufIndex);
     } else {
-        MD5_Update(cx, padbytes,
-                   MD5_END_BUFFER + MD5_BUFFER_SIZE - inBufIndex);
+        MD5_Update_NonFIPS(cx, padbytes,
+                           MD5_END_BUFFER + MD5_BUFFER_SIZE - inBufIndex);
     }
 
     /* Store the number of bytes input (before padding) in final 64 bits. */
@@ -554,16 +567,22 @@ MD5_End(MD5Context *cx, unsigned char *digest,
 }
 
 void
-MD5_EndRaw(MD5Context *cx, unsigned char *digest,
-           unsigned int *digestLen, unsigned int maxDigestLen)
+MD5_End(MD5Context *cx, unsigned char *digest,
+        unsigned int *digestLen, unsigned int maxDigestLen)
+{
+    IN_FIPS_RETURN();
+    MD5_End_NonFIPS(cx, digest, digestLen, maxDigestLen);
+}
+
+void
+MD5_EndRaw_NonFIPS(MD5Context *cx, unsigned char *digest,
+                          unsigned int *digestLen, unsigned int maxDigestLen)
 {
 #ifndef IS_LITTLE_ENDIAN
     PRUint32 tmp;
 #endif
     PRUint32 cv[4];
 
-    IN_FIPS_RETURN();
-
     if (maxDigestLen < MD5_HASH_LEN) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return;
@@ -581,6 +600,14 @@ MD5_EndRaw(MD5Context *cx, unsigned char *digest,
         *digestLen = MD5_HASH_LEN;
 }
 
+void
+MD5_EndRaw(MD5Context *cx, unsigned char *digest,
+           unsigned int *digestLen, unsigned int maxDigestLen)
+{
+    IN_FIPS_RETURN();
+    MD5_EndRaw_NonFIPS(cx, digest, digestLen, maxDigestLen);
+}
+
 unsigned int
 MD5_FlattenSize(MD5Context *cx)
 {
diff --git a/nss/lib/freebl/rawhash.c b/nss/lib/freebl/rawhash.c
index d0e8ee8..5fff18c 100644
--- a/nss/lib/freebl/rawhash.c
+++ b/nss/lib/freebl/rawhash.c
@@ -154,3 +154,40 @@ HASH_GetRawHashObject(HASH_HashType hashType)
     }
     return &SECRawHashObjects[hashType];
 }
+
+/* Defined in md5.c */
+
+MD5Context *MD5_NewContext_NonFIPS(void);
+void MD5_Begin_NonFIPS(MD5Context *cx);
+void MD5_Update_NonFIPS(MD5Context *cx, const unsigned char *input, unsigned int inputLen);
+void MD5_End_NonFIPS(MD5Context *cx, unsigned char *digest,
+                            unsigned int *digestLen, unsigned int maxDigestLen);
+void MD5_EndRaw_NonFIPS(MD5Context *cx, unsigned char *digest,
+                               unsigned int *digestLen, unsigned int maxDigestLen);
+
+static const SECHashObject SECRawHashObjectMD5NonFIPS = {
+    MD5_LENGTH,
+    (void *(*)(void))MD5_NewContext_NonFIPS,
+    (void *(*)(void *))null_hash_clone_context,
+    (void (*)(void *, PRBool))MD5_DestroyContext,
+    (void (*)(void *))MD5_Begin_NonFIPS,
+    (void (*)(void *, const unsigned char *, unsigned int))MD5_Update_NonFIPS,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int))MD5_End_NonFIPS,
+    MD5_BLOCK_LENGTH,
+    HASH_AlgMD5,
+    (void (*)(void *, unsigned char *, unsigned int *, unsigned int))MD5_EndRaw_NonFIPS
+};
+
+const SECHashObject *
+HASH_GetRawHashObjectNonFIPS(HASH_HashType hashType)
+{
+    if (hashType <= HASH_AlgNULL || hashType >= HASH_AlgTOTAL) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
+    if (hashType == HASH_AlgMD5)
+      return &SECRawHashObjectMD5NonFIPS;
+
+    return &SECRawHashObjects[hashType];
+}
diff --git a/nss/lib/freebl/tlsprfalg.c b/nss/lib/freebl/tlsprfalg.c
index 1e5e678..d927754 100644
--- a/nss/lib/freebl/tlsprfalg.c
+++ b/nss/lib/freebl/tlsprfalg.c
@@ -12,6 +12,9 @@
 #include "hasht.h"
 #include "alghmac.h"
 
+/* To get valid MD5 object in FIPS mode */
+const SECHashObject *HASH_GetRawHashObjectNonFIPS(HASH_HashType hashType);
+
 #define PHASH_STATE_MAX_LEN HASH_LENGTH_MAX
 
 /* TLS P_hash function */
@@ -27,7 +30,7 @@ TLS_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label,
     SECStatus status;
     HMACContext *cx;
     SECStatus rv = SECFailure;
-    const SECHashObject *hashObj = HASH_GetRawHashObject(hashType);
+    const SECHashObject *hashObj = HASH_GetRawHashObjectNonFIPS(hashType);
 
     PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len));
     PORT_Assert((seed != NULL) && (seed->data != NULL));
diff --git a/nss/lib/softoken/pkcs11c.c b/nss/lib/softoken/pkcs11c.c
index 529b3a6..f38b05b 100644
--- a/nss/lib/softoken/pkcs11c.c
+++ b/nss/lib/softoken/pkcs11c.c
@@ -6266,7 +6266,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
     SFTKAttribute *att2 = NULL;
     unsigned char *buf;
     SHA1Context *sha;
-    MD5Context *md5;
+    MD5Context *md5 = NULL;
     MD2Context *md2;
     CK_ULONG macSize;
     CK_ULONG tmpKeySize;
@@ -6697,7 +6697,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
             }
             sftk_FreeAttribute(att2);
             md5 = MD5_NewContext();
-            if (md5 == NULL) {
+            if (md5 == NULL && !isTLS) {
                 crv = CKR_HOST_MEMORY;
                 break;
             }
