# HG changeset patch
# Parent  f616a30eaf119c49568a947ae554fa0e96f76f96
Runtime checks for non-approved algorithms in FIPS mode

diff --git a/lib/freebl/alg2268.c b/lib/freebl/alg2268.c
--- a/lib/freebl/alg2268.c
+++ b/lib/freebl/alg2268.c
@@ -10,16 +10,18 @@
 #endif
 
 #include "blapi.h"
 #include "secerr.h"
 #ifdef XP_UNIX_XXX
 #include <stddef.h>	/* for ptrdiff_t */
 #endif
 
+#include "fips.h"
+
 /*
 ** RC2 symmetric block cypher
 */
 
 typedef SECStatus (rc2Func)(RC2Context *cx, unsigned char *output,
 		           const unsigned char *input, unsigned int inputLen);
 
 /* forward declarations */
@@ -98,30 +100,33 @@ 0231,0174,0072,0205,0043,0270,0264,0172,
 0055,0135,0372,0230,0343,0212,0222,0256,0005,0337,0051,0020,0147,0154,0272,0311,
 0323,0000,0346,0317,0341,0236,0250,0054,0143,0026,0001,0077,0130,0342,0211,0251,
 0015,0070,0064,0033,0253,0063,0377,0260,0273,0110,0014,0137,0271,0261,0315,0056,
 0305,0363,0333,0107,0345,0245,0234,0167,0012,0246,0040,0150,0376,0177,0301,0255
 };
 
 RC2Context * RC2_AllocateContext(void)
 {
+    IN_FIPS_RETURN(NULL);
     return PORT_ZNew(RC2Context);
 }
 SECStatus   
 RC2_InitContext(RC2Context *cx, const unsigned char *key, unsigned int len,
 	        const unsigned char *input, int mode, unsigned int efLen8, 
 		unsigned int unused)
 {
     PRUint8    *L,*L2;
     int         i;
 #if !defined(IS_LITTLE_ENDIAN)
     PRUint16    tmpS;
 #endif
     PRUint8     tmpB;
 
+    IN_FIPS_RETURN(SECFailure);
+
     if (!key || !cx || !len || len > (sizeof cx->B) || 
 	efLen8 > (sizeof cx->B)) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
     	return SECFailure;
     }
     if (mode == NSS_RC2) {
     	/* groovy */
     } else if (mode == NSS_RC2_CBC) {
@@ -183,17 +188,21 @@ RC2_InitContext(RC2Context *cx, const un
 **
 ** When mode is set to NSS_RC2_CBC the RC2 cipher is run in "cipher block
 ** chaining" mode.
 */
 RC2Context *
 RC2_CreateContext(const unsigned char *key, unsigned int len,
 		  const unsigned char *iv, int mode, unsigned efLen8)
 {
-    RC2Context *cx = PORT_ZNew(RC2Context);
+    RC2Context *cx;
+    
+    IN_FIPS_RETURN(NULL);
+
+    cx = PORT_ZNew(RC2Context);
     if (cx) {
 	SECStatus rv = RC2_InitContext(cx, key, len, iv, mode, efLen8, 0);
 	if (rv != SECSuccess) {
 	    RC2_DestroyContext(cx, PR_TRUE);
 	    cx = NULL;
 	}
     }
     return cx;
@@ -427,17 +436,21 @@ rc2_DecryptCBC(RC2Context *cx, unsigned 
 **	   stored in "output"
 **	"input" the input data
 **	"inputLen" the amount of input data
 */
 SECStatus RC2_Encrypt(RC2Context *cx, unsigned char *output,
 		      unsigned int *outputLen, unsigned int maxOutputLen,
 		      const unsigned char *input, unsigned int inputLen)
 {
-    SECStatus rv = SECSuccess;
+    SECStatus rv;
+	
+    IN_FIPS_RETURN(SECFailure);
+
+    rv = SECSuccess;
     if (inputLen) {
 	if (inputLen % RC2_BLOCK_SIZE) {
 	    PORT_SetError(SEC_ERROR_INPUT_LEN);
 	    return SECFailure;
 	}
 	if (maxOutputLen < inputLen) {
 	    PORT_SetError(SEC_ERROR_OUTPUT_LEN);
 	    return SECFailure;
@@ -460,17 +473,21 @@ SECStatus RC2_Encrypt(RC2Context *cx, un
 **	   stored in "output"
 **	"input" the input data
 **	"inputLen" the amount of input data
 */
 SECStatus RC2_Decrypt(RC2Context *cx, unsigned char *output,
 		      unsigned int *outputLen, unsigned int maxOutputLen,
 		      const unsigned char *input, unsigned int inputLen)
 {
-    SECStatus rv = SECSuccess;
+    SECStatus rv;
+    
+    IN_FIPS_RETURN(SECFailure);
+
+    rv = SECSuccess;
     if (inputLen) {
 	if (inputLen % RC2_BLOCK_SIZE) {
 	    PORT_SetError(SEC_ERROR_INPUT_LEN);
 	    return SECFailure;
 	}
 	if (maxOutputLen < inputLen) {
 	    PORT_SetError(SEC_ERROR_OUTPUT_LEN);
 	    return SECFailure;
diff --git a/lib/freebl/arcfour.c b/lib/freebl/arcfour.c
--- a/lib/freebl/arcfour.c
+++ b/lib/freebl/arcfour.c
@@ -8,16 +8,17 @@
 #include "stubs.h"
 #endif
 
 #include "prerr.h"
 #include "secerr.h"
 
 #include "prtypes.h"
 #include "blapi.h"
+#include "fips.h"
 
 /* Architecture-dependent defines */
 
 #if defined(SOLARIS) || defined(HPUX) || defined(NSS_X86) || \
     defined(_WIN64)
 /* Convert the byte-stream to a word-stream */
 #define CONVERT_TO_WORDS
 #endif
@@ -104,29 +105,32 @@ static const Stype Kinit[256] = {
 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
 };
 
 RC4Context *
 RC4_AllocateContext(void)
 {
+    IN_FIPS_RETURN(NULL);
     return PORT_ZNew(RC4Context);
 }
 
 SECStatus   
 RC4_InitContext(RC4Context *cx, const unsigned char *key, unsigned int len,
 	        const unsigned char * unused1, int unused2, 
 		unsigned int unused3, unsigned int unused4)
 {
 	unsigned int i;
 	PRUint8 j, tmp;
 	PRUint8 K[256];
 	PRUint8 *L;
 
+	IN_FIPS_RETURN(SECFailure);
+
 	/* verify the key length. */
 	PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
 	if (len == 0 || len >= ARCFOUR_STATE_SIZE) {
 		PORT_SetError(SEC_ERROR_BAD_KEY);
 		return SECFailure;
 	}
 	if (cx == NULL) {
 	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -159,30 +163,35 @@ RC4_InitContext(RC4Context *cx, const un
 
 
 /*
  * Initialize a new generator.
  */
 RC4Context *
 RC4_CreateContext(const unsigned char *key, int len)
 {
-    RC4Context *cx = RC4_AllocateContext();
+    RC4Context *cx;
+
+    IN_FIPS_RETURN(NULL);
+    
+    cx = RC4_AllocateContext();
     if (cx) {
 	SECStatus rv = RC4_InitContext(cx, key, len, NULL, 0, 0, 0);
 	if (rv != SECSuccess) {
 	    PORT_ZFree(cx, sizeof(*cx));
 	    cx = NULL;
 	}
     }
     return cx;
 }
 
 void 
 RC4_DestroyContext(RC4Context *cx, PRBool freeit)
 {
+	IN_FIPS_RETURN();
 	if (freeit)
 		PORT_ZFree(cx, sizeof(*cx));
 }
 
 #if defined(NSS_BEVAND_ARCFOUR)
 extern void ARCFOUR(RC4Context *cx, WORD inputLen, 
 	const unsigned char *input, unsigned char *output);
 #else
@@ -523,16 +532,18 @@ rc4_wordconv(RC4Context *cx, unsigned ch
 #endif
 #endif /* NSS_BEVAND_ARCFOUR */
 
 SECStatus 
 RC4_Encrypt(RC4Context *cx, unsigned char *output,
             unsigned int *outputLen, unsigned int maxOutputLen,
             const unsigned char *input, unsigned int inputLen)
 {
+	IN_FIPS_RETURN(SECFailure);
+
 	PORT_Assert(maxOutputLen >= inputLen);
 	if (maxOutputLen < inputLen) {
 		PORT_SetError(SEC_ERROR_OUTPUT_LEN);
 		return SECFailure;
 	}
 #if defined(NSS_BEVAND_ARCFOUR)
 	ARCFOUR(cx, inputLen, input, output);
         *outputLen = inputLen;
@@ -545,16 +556,18 @@ RC4_Encrypt(RC4Context *cx, unsigned cha
 	return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
 #endif
 }
 
 SECStatus RC4_Decrypt(RC4Context *cx, unsigned char *output,
                       unsigned int *outputLen, unsigned int maxOutputLen,
                       const unsigned char *input, unsigned int inputLen)
 {
+	IN_FIPS_RETURN(SECFailure);
+
 	PORT_Assert(maxOutputLen >= inputLen);
 	if (maxOutputLen < inputLen) {
 		PORT_SetError(SEC_ERROR_OUTPUT_LEN);
 		return SECFailure;
 	}
 	/* decrypt and encrypt are same operation. */
 #if defined(NSS_BEVAND_ARCFOUR)
 	ARCFOUR(cx, inputLen, input, output);
diff --git a/lib/freebl/fips.c b/lib/freebl/fips.c
--- a/lib/freebl/fips.c
+++ b/lib/freebl/fips.c
@@ -62,8 +62,37 @@ FIPS_rngDev(void)
 	case 1:
             return RNG_DEV_FIPS1;
 	default:
 	    fatal("Fatal error: internal error at %s:%u"
 		, __FILE__, __LINE__);
     }
 }
 
+/* either returns the input or aborts if in FIPS and the algorithm is not
+ * approved */
+PRBool
+FIPS_hashAlgApproved(HASH_HashType hashAlg)
+{
+    PRBool rv = PR_FALSE;
+
+    switch (hashAlg) {
+	case HASH_AlgNULL:
+	case HASH_AlgSHA1:
+	case HASH_AlgSHA256:
+	case HASH_AlgSHA384:
+	case HASH_AlgSHA512:
+	case HASH_AlgSHA224:
+	    rv = PR_TRUE;
+	    break;
+	default:
+	    /*
+	    fatal("Fatal error: non-approved hash algorithm (id %i)"
+		"requested while running in FIPS mode"
+		, hashAlg);
+	    */
+	    if (!FIPS_mode())
+		rv = PR_TRUE;
+	    break;
+    }
+    return rv;
+}
+
diff --git a/lib/freebl/fips.h b/lib/freebl/fips.h
--- a/lib/freebl/fips.h
+++ b/lib/freebl/fips.h
@@ -3,13 +3,25 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef FIPS_H
 #define FIPS_H
 
+#include "hasht.h"
+#include "secerr.h"
+
+#define IN_FIPS_RETURN(rv) \
+    do { \
+	if (FIPS_mode()) { \
+	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); \
+	    return rv; \
+	} \
+    } while (0)
+
 int	FIPS_mode(void);
 char*	FIPS_rngDev(void);
+PRBool	FIPS_hashAlgApproved(HASH_HashType hashAlg);
 
 #endif
 
diff --git a/lib/freebl/md2.c b/lib/freebl/md2.c
--- a/lib/freebl/md2.c
+++ b/lib/freebl/md2.c
@@ -8,16 +8,18 @@
 
 #include "prerr.h"
 #include "secerr.h"
 
 #include "prtypes.h"
 
 #include "blapi.h"
 
+#include "fips.h"
+
 #define MD2_DIGEST_LEN    16
 #define MD2_BUFSIZE       16
 #define MD2_X_SIZE        48  /* The X array, [CV | INPUT | TMP VARS] */
 #define MD2_CV             0  /* index into X for chaining variables */
 #define MD2_INPUT         16  /* index into X for input */
 #define MD2_TMPVARS       32  /* index into X for temporary variables */
 #define MD2_CHECKSUM_SIZE 16
 
@@ -61,31 +63,34 @@ static const PRUint8 MD2S[256] = {
  0061, 0104, 0120, 0264, 0217, 0355, 0037, 0032,
  0333, 0231, 0215, 0063, 0237, 0021, 0203, 0024
 };
 
 SECStatus 
 MD2_Hash(unsigned char *dest, const char *src)
 {
 	unsigned int len;
+	
+	IN_FIPS_RETURN(SECFailure);
 	MD2Context *cx = MD2_NewContext();
 	if (!cx) {
 		PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
 		return SECFailure;
 	}
 	MD2_Begin(cx);
 	MD2_Update(cx, (const unsigned char *)src, PORT_Strlen(src));
 	MD2_End(cx, dest, &len, MD2_DIGEST_LEN);
 	MD2_DestroyContext(cx, PR_TRUE);
 	return SECSuccess;
 }
 
 MD2Context *
 MD2_NewContext(void)
 {
+	IN_FIPS_RETURN(NULL);
 	MD2Context *cx = (MD2Context *)PORT_ZAlloc(sizeof(MD2Context));
 	if (cx == NULL) {
 		PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
 		return NULL;
 	}
 	return cx;
 }
 
@@ -94,16 +99,17 @@ MD2_DestroyContext(MD2Context *cx, PRBoo
 {
 	if (freeit)
 		PORT_ZFree(cx, sizeof(*cx));
 }
 
 void 
 MD2_Begin(MD2Context *cx)
 {
+	IN_FIPS_RETURN();
 	memset(cx, 0, sizeof(*cx));
 	cx->unusedBuffer = MD2_BUFSIZE;
 }
 
 static void
 md2_compress(MD2Context *cx)
 {
 	int j;
@@ -191,16 +197,18 @@ md2_compress(MD2Context *cx)
 	cx->unusedBuffer = MD2_BUFSIZE;
 }
 
 void 
 MD2_Update(MD2Context *cx, const unsigned char *input, unsigned int inputLen)
 {
 	PRUint32 bytesToConsume;
 	
+	IN_FIPS_RETURN();
+
 	/* Fill the remaining input buffer. */
 	if (cx->unusedBuffer != MD2_BUFSIZE) {
 		bytesToConsume = PR_MIN(inputLen, cx->unusedBuffer);
 		memcpy(&cx->X[MD2_INPUT + (MD2_BUFSIZE - cx->unusedBuffer)],
 		            input, bytesToConsume);
 		if (cx->unusedBuffer + bytesToConsume >= MD2_BUFSIZE)
 			md2_compress(cx);
 		inputLen -= bytesToConsume;
@@ -221,16 +229,19 @@ MD2_Update(MD2Context *cx, const unsigne
 	cx->unusedBuffer = MD2_BUFSIZE - inputLen;
 }
 
 void 
 MD2_End(MD2Context *cx, unsigned char *digest,
         unsigned int *digestLen, unsigned int maxDigestLen)
 {
 	PRUint8 padStart;
+	
+	IN_FIPS_RETURN();
+
 	if (maxDigestLen < MD2_BUFSIZE) {
 		PORT_SetError(SEC_ERROR_INVALID_ARGS);
 		return;
 	}
 	padStart = MD2_BUFSIZE - cx->unusedBuffer;
 	memset(&cx->X[MD2_INPUT + padStart], cx->unusedBuffer, 
 	            cx->unusedBuffer);
 	md2_compress(cx);
diff --git a/lib/freebl/md5.c b/lib/freebl/md5.c
--- a/lib/freebl/md5.c
+++ b/lib/freebl/md5.c
@@ -9,16 +9,18 @@
 #include "prerr.h"
 #include "secerr.h"
 
 #include "prtypes.h"
 #include "prlong.h"
 
 #include "blapi.h"
 
+#include "fips.h"
+
 #define MD5_HASH_LEN 16
 #define MD5_BUFFER_SIZE 64
 #define MD5_END_BUFFER (MD5_BUFFER_SIZE - 8)
 
 #define CV0_1 0x67452301
 #define CV0_2 0xefcdab89
 #define CV0_3 0x98badcfe
 #define CV0_4 0x10325476
@@ -189,56 +191,64 @@ struct MD5ContextStr {
 	} u;
 };
 
 #define inBuf u.b
 
 SECStatus 
 MD5_Hash(unsigned char *dest, const char *src)
 {
+	IN_FIPS_RETURN(SECFailure);
 	return MD5_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
 }
 
 SECStatus 
 MD5_HashBuf(unsigned char *dest, const unsigned char *src, PRUint32 src_length)
 {
 	unsigned int len;
 	MD5Context cx;
 
+	IN_FIPS_RETURN(SECFailure);
+
 	MD5_Begin(&cx);
 	MD5_Update(&cx, src, src_length);
 	MD5_End(&cx, dest, &len, MD5_HASH_LEN);
 	memset(&cx, 0, sizeof cx);
 	return SECSuccess;
 }
 
 MD5Context *
 MD5_NewContext(void)
 {
+	IN_FIPS_RETURN(NULL);
+
 	/* no need to ZAlloc, MD5_Begin will init the context */
 	MD5Context *cx = (MD5Context *)PORT_Alloc(sizeof(MD5Context));
 	if (cx == NULL) {
 		PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
 		return NULL;
 	}
 	return cx;
 }
 
 void 
 MD5_DestroyContext(MD5Context *cx, PRBool freeit)
 {
-	memset(cx, 0, sizeof *cx);
+	if (cx)
+	    memset(cx, 0, sizeof *cx);
 	if (freeit) {
 	    PORT_Free(cx);
 	}
 }
 
 void 
 MD5_Begin(MD5Context *cx)
 {
+	IN_FIPS_RETURN();
+
 	cx->lsbInput = 0;
 	cx->msbInput = 0;
 /*	memset(cx->inBuf, 0, sizeof(cx->inBuf)); */
 	cx->cv[0] = CV0_1;
 	cx->cv[1] = CV0_2;
 	cx->cv[2] = CV0_3;
 	cx->cv[3] = CV0_4;
 }
@@ -417,16 +427,18 @@ md5_compress(MD5Context *cx, const PRUin
 
 void 
 MD5_Update(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) {
 		/* There is already data in the buffer.  Fill with input. */
 		bytesToConsume = PR_MIN(inputLen, MD5_BUFFER_SIZE - inBufIndex);
 		memcpy(&cx->inBuf[inBufIndex], input, bytesToConsume);
 		if (inBufIndex + bytesToConsume >= MD5_BUFFER_SIZE) {
 			/* The buffer is filled.  Run the compression function. */
@@ -490,16 +502,18 @@ MD5_End(MD5Context *cx, unsigned char *d
         unsigned int *digestLen, unsigned int maxDigestLen)
 {
 #ifndef IS_LITTLE_ENDIAN
 	PRUint32 tmp;
 #endif
 	PRUint32 lowInput, highInput;
 	PRUint32 inBufIndex = cx->lsbInput & 63;
 
+	IN_FIPS_RETURN();
+
 	if (maxDigestLen < MD5_HASH_LEN) {
 		PORT_SetError(SEC_ERROR_INVALID_ARGS);
 		return;
 	}
 
 	/* Copy out the length of bits input before padding. */
 	lowInput = cx->lsbInput; 
 	highInput = (cx->msbInput << 3) | (lowInput >> 29);
@@ -538,16 +552,18 @@ void
 MD5_EndRaw(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;
 	}
 
 	memcpy(cv, cx->cv, sizeof(cv));
 #ifndef IS_LITTLE_ENDIAN
 	cv[0] = lendian(cv[0]);
diff --git a/lib/freebl/nsslowhash.c b/lib/freebl/nsslowhash.c
--- a/lib/freebl/nsslowhash.c
+++ b/lib/freebl/nsslowhash.c
@@ -7,16 +7,17 @@
 #endif
 #include "prtypes.h"
 #include "secerr.h"
 #include "pkcs11t.h"
 #include "blapi.h"
 #include "hasht.h"
 #include "plhash.h"
 #include "nsslowhash.h"
+#include "fips.h"
 
 /* FIPS selftests are implemented in library constructors and abort on failure
  * - if anybody gets to call this function it means the tests passed and this
  * can be a successful no-op; the integrity selftest that used to be here is
  * handled by the freebl constructor as well
  */
 CK_RV
 freebl_fipsPowerUpSelfTest( void )
@@ -67,16 +68,22 @@ NSSLOW_Reset(NSSLOWInitContext *context)
 }
 
 NSSLOWHASHContext *
 NSSLOWHASH_NewContext(NSSLOWInitContext *initContext, 
 			HASH_HashType hashType)
 {
    NSSLOWHASHContext *context;
 
+   /* return with an error if unapproved hash is requested in FIPS mode */
+   if (!FIPS_hashAlgApproved(hashType)) {
+	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+	return NULL;
+   }
+
    if (initContext != &dummyContext) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return (NULL);
    }
 
    context = PORT_ZNew(NSSLOWHASHContext);
    if (!context) {
 	return NULL;
diff --git a/lib/freebl/rawhash.c b/lib/freebl/rawhash.c
--- a/lib/freebl/rawhash.c
+++ b/lib/freebl/rawhash.c
@@ -5,16 +5,17 @@
 #ifdef FREEBL_NO_DEPEND
 #include "stubs.h"
 #endif
 
 #include "nspr.h"
 #include "hasht.h"
 #include "blapi.h"	/* below the line */
 #include "secerr.h"
+#include "fips.h"
 
 static void *
 null_hash_new_context(void)
 {
     return NULL;
 }
 
 static void *
@@ -148,14 +149,15 @@ const SECHashObject SECRawHashObjects[] 
     (void (*)(void *, unsigned char *, unsigned int *,
 	      unsigned int)) SHA224_EndRaw
   },
 };
 
 const SECHashObject *
 HASH_GetRawHashObject(HASH_HashType hashType)
 {
-    if (hashType < HASH_AlgNULL || hashType >= HASH_AlgTOTAL) {
+    if (hashType < HASH_AlgNULL || hashType >= HASH_AlgTOTAL
+	    || (!FIPS_hashAlgApproved(hashType))) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return NULL;
     }
     return &SECRawHashObjects[hashType];
 }
diff --git a/lib/freebl/seed.c b/lib/freebl/seed.c
--- a/lib/freebl/seed.c
+++ b/lib/freebl/seed.c
@@ -12,16 +12,18 @@
 #include <stddef.h>
 #ifdef WIN32
 #include <memory.h>
 #endif
 
 #include "seed.h"
 #include "secerr.h"
 
+#include "fips.h"
+
 static const seed_word SS[4][256] = {	
     {
         0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 
         0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124,
         0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, 
         0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360,
         0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, 
         0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314,
@@ -304,16 +306,18 @@ static const seed_word SS[4][256] = {
 
 
 void SEED_set_key(const unsigned char rawkey[SEED_KEY_LENGTH], 
                   SEED_KEY_SCHEDULE *ks)
 {
     seed_word K0, K1, K2, K3;
     seed_word t0, t1;
 
+    IN_FIPS_RETURN();
+
     char2word(rawkey   , K0);
     char2word(rawkey+4 , K1);
     char2word(rawkey+8 , K2);
     char2word(rawkey+12, K3);
 
     t0 = (K0 + K2 - KC0);
     t1 = (K1 - K3 + KC0);                     
     KEYUPDATE_TEMP(t0, t1, &ks->data[0]);
@@ -351,16 +355,18 @@ void SEED_set_key(const unsigned char ra
 
 void SEED_encrypt(const unsigned char s[SEED_BLOCK_SIZE], 
                   unsigned char d[SEED_BLOCK_SIZE], 
                   const SEED_KEY_SCHEDULE *ks)
 {
     seed_word L0, L1, R0, R1;
     seed_word t0, t1;
 
+    IN_FIPS_RETURN();
+
     char2word(s,    L0);
     char2word(s+4,  L1);
     char2word(s+8,  R0);
     char2word(s+12, R1);
     
     E_SEED(t0, t1, L0, L1, R0, R1, 0);
     E_SEED(t0, t1, R0, R1, L0, L1, 2);
     E_SEED(t0, t1, L0, L1, R0, R1, 4);
@@ -386,16 +392,18 @@ void SEED_encrypt(const unsigned char s[
 
 void SEED_decrypt(const unsigned char s[SEED_BLOCK_SIZE], 
                   unsigned char d[SEED_BLOCK_SIZE], 
                   const SEED_KEY_SCHEDULE *ks)
 {
     seed_word L0, L1, R0, R1;
     seed_word t0, t1;
 
+    IN_FIPS_RETURN();
+
     char2word(s,    L0);
     char2word(s+4,  L1);
     char2word(s+8,  R0);
     char2word(s+12, R1);
     
     E_SEED(t0, t1, L0, L1, R0, R1, 30);
     E_SEED(t0, t1, R0, R1, L0, L1, 28);
     E_SEED(t0, t1, L0, L1, R0, R1, 26);
@@ -434,16 +442,18 @@ void SEED_ecb_encrypt(const unsigned cha
 void SEED_cbc_encrypt(const unsigned char *in, unsigned char *out,
                       size_t len, const SEED_KEY_SCHEDULE *ks,
                       unsigned char ivec[SEED_BLOCK_SIZE], int enc)
 {
     size_t n;
     unsigned char tmp[SEED_BLOCK_SIZE];
     const unsigned char *iv = ivec;
 
+    IN_FIPS_RETURN();
+
     if (enc) {
         while (len >= SEED_BLOCK_SIZE) {
             for (n = 0; n < SEED_BLOCK_SIZE; ++n)
                 out[n] = in[n] ^ iv[n];
 
             SEED_encrypt(out, out, ks);
             iv = out;
             len -= SEED_BLOCK_SIZE;
@@ -510,24 +520,27 @@ void SEED_cbc_encrypt(const unsigned cha
             memcpy(ivec, tmp, SEED_BLOCK_SIZE);
         }
     }
 }
 
 SEEDContext *
 SEED_AllocateContext(void)
 {
+    IN_FIPS_RETURN(NULL);
     return PORT_ZNew(SEEDContext);
 }
 
 SECStatus   
 SEED_InitContext(SEEDContext *cx, const unsigned char *key, 
                  unsigned int keylen, const unsigned char *iv, 
                  int mode, unsigned int encrypt,unsigned int unused)
 {
+    IN_FIPS_RETURN(SECFailure);
+
     if (!cx) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     switch (mode) {
     case NSS_SEED:    
         SEED_set_key(key, &cx->ks);
@@ -549,17 +562,21 @@ SEED_InitContext(SEEDContext *cx, const 
 
     return SECSuccess;
 }
 
 SEEDContext *
 SEED_CreateContext(const unsigned char * key, const unsigned char *iv,
                    int mode, PRBool encrypt)
 {
-    SEEDContext *cx = PORT_ZNew(SEEDContext);
+    SEEDContext *cx;
+    
+    IN_FIPS_RETURN(NULL);
+    
+    cx = PORT_ZNew(SEEDContext);
     SECStatus rv   = SEED_InitContext(cx, key, SEED_KEY_LENGTH, iv, mode, 
                                       encrypt, 0);
 
     if (rv != SECSuccess) {
         PORT_ZFree(cx, sizeof *cx);
         cx = NULL;
     }
 
@@ -577,16 +594,18 @@ SEED_DestroyContext(SEEDContext *cx, PRB
     }
 }
 
 SECStatus
 SEED_Encrypt(SEEDContext *cx, unsigned char *out, unsigned int *outLen,
              unsigned int maxOutLen, const unsigned char *in, 
              unsigned int inLen)
 {
+    IN_FIPS_RETURN(SECFailure);
+
     if (!cx) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     if (!cx->encrypt) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
@@ -611,16 +630,18 @@ SEED_Encrypt(SEEDContext *cx, unsigned c
     return SECSuccess;
 }
 
 SECStatus
 SEED_Decrypt(SEEDContext *cx, unsigned char *out, unsigned int *outLen,
              unsigned int maxOutLen, const unsigned char *in, 
              unsigned int inLen)
 {
+    IN_FIPS_RETURN(SECFailure);
+
     if (!cx) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     if (cx->encrypt) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
--- a/lib/softoken/pkcs11c.c
+++ b/lib/softoken/pkcs11c.c
@@ -6098,17 +6098,17 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 	if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
 					CKK_GENERIC_SECRET)) {
 	    if (att2) sftk_FreeAttribute(att2);
 	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
 	    break;
 	}
 	sftk_FreeAttribute(att2);
 	md5 = MD5_NewContext();
-	if (md5 == NULL) { 
+	if (md5 == NULL && !isTLS) {
 	    crv = CKR_HOST_MEMORY;
 	    break;
 	}
 	sha = SHA1_NewContext();
 	if (sha == NULL) { 
 	    PORT_Free(md5);
 	    crv = CKR_HOST_MEMORY;
 	    break;
