# HG changeset patch
# Parent  a6003f165cb9c78c56de01170b3f2ef60600c75e
Disable non-approved elliptic curves in FIPS mode - return errors when one of
them is requested and do not offer these curves in SSL/TLS negotiation.

Approved curves for FIPS-140-2 are: NIST P-224, P-256, P-384, P-521.

bsc#924307

diff --git a/lib/freebl/ecdecode.c b/lib/freebl/ecdecode.c
--- a/lib/freebl/ecdecode.c
+++ b/lib/freebl/ecdecode.c
@@ -9,19 +9,27 @@
 #endif
 
 #include "blapi.h"
 #include "secoid.h"
 #include "secitem.h"
 #include "secerr.h"
 #include "ec.h"
 #include "ecl-curve.h"
+#include "fips.h"
 
 #define CHECK_OK(func) if (func == NULL) goto cleanup
 #define CHECK_SEC_OK(func) if (SECSuccess != (rv = func)) goto cleanup
+#define DISABLED_IF(x) \
+    do { \
+	if (x) { \
+	    rv = SECFailure; \
+	    goto cleanup; \
+	} \
+    } while (0)
 
 /*
  * Initializes a SECItem from a hexadecimal string
  *
  * Warning: This function ignores leading 00's, so any leading 00's
  * in the hexadecimal string must be optional.
  */
 static SECItem *
@@ -197,350 +205,400 @@ EC_FillParams(PLArenaPool *arena, const 
     printf("Curve: %s\n", SECOID_FindOIDTagDescription(tag));
 #endif
 
     switch (tag) {
 
     /* Binary curves */
 
     case SEC_OID_ANSIX962_EC_C2PNB163V1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2pnb163v1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB163V1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2PNB163V2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2pnb163v2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB163V2, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2PNB163V3:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2pnb163v3 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB163V3, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2PNB176V1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2pnb176v1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB176V1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2TNB191V1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2tnb191v1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB191V1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2TNB191V2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2tnb191v2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB191V2, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2TNB191V3:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2tnb191v3 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB191V3, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2PNB208W1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2pnb208w1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB208W1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2TNB239V1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2tnb239v1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB239V1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2TNB239V2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2tnb239v2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB239V2, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2TNB239V3:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2tnb239v3 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB239V3, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2PNB272W1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2pnb272w1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB272W1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2PNB304W1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2pnb304w1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB304W1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2TNB359V1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2tnb359v1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB359V1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2PNB368W1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2pnb368w1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB368W1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_C2TNB431R1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for c2tnb431r1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB431R1, ec_field_GF2m,
 	    params) );
 	break;
 	
     case SEC_OID_SECG_EC_SECT113R1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect113r1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_113R1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT113R2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect113r2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_113R2, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT131R1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect131r1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_131R1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT131R2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect131r2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_131R2, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT163K1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect163k1
 	 * (the NIST K-163 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_163K1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT163R1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect163r1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_163R1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT163R2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect163r2
 	 * (the NIST B-163 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_163R2, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT193R1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect193r1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_193R1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT193R2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect193r2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_193R2, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT233K1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect233k1
 	 * (the NIST K-233 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_233K1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT233R1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect233r1
 	 * (the NIST B-233 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_233R1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT239K1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect239k1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_239K1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT283K1:
+	DISABLED_IF(FIPS_mode());
         /* Populate params for sect283k1
 	 * (the NIST K-283 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_283K1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT283R1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect283r1
 	 * (the NIST B-283 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_283R1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT409K1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect409k1
 	 * (the NIST K-409 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_409K1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT409R1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect409r1
 	 * (the NIST B-409 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_409R1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT571K1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect571k1
 	 * (the NIST K-571 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_571K1, ec_field_GF2m,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECT571R1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for sect571r1
 	 * (the NIST B-571 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_571R1, ec_field_GF2m,
 	    params) );
 	break;
 
     /* Prime curves */
 
     case SEC_OID_ANSIX962_EC_PRIME192V1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for prime192v1 aka secp192r1 
 	 * (the NIST P-192 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_192V1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_PRIME192V2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for prime192v2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_192V2, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_PRIME192V3:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for prime192v3 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_192V3, ec_field_GFp,
 	    params) );
 	break;
 	
     case SEC_OID_ANSIX962_EC_PRIME239V1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for prime239v1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_239V1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_PRIME239V2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for prime239v2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_239V2, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_PRIME239V3:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for prime239v3 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_239V3, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_ANSIX962_EC_PRIME256V1:
 	/* Populate params for prime256v1 aka secp256r1
 	 * (the NIST P-256 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_256V1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP112R1:
+	DISABLED_IF(FIPS_mode());
         /* Populate params for secp112r1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_112R1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP112R2:
+	DISABLED_IF(FIPS_mode());
         /* Populate params for secp112r2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_112R2, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP128R1:
+	DISABLED_IF(FIPS_mode());
         /* Populate params for secp128r1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_128R1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP128R2:
+	DISABLED_IF(FIPS_mode());
         /* Populate params for secp128r2 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_128R2, ec_field_GFp,
 	    params) );
 	break;
 	
     case SEC_OID_SECG_EC_SECP160K1:
+	DISABLED_IF(FIPS_mode());
         /* Populate params for secp160k1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_160K1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP160R1:
+	DISABLED_IF(FIPS_mode());
         /* Populate params for secp160r1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_160R1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP160R2:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for secp160r1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_160R2, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP192K1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for secp192k1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_192K1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP224K1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for secp224k1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_224K1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP224R1:
 	/* Populate params for secp224r1 
 	 * (the NIST P-224 curve)
 	 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_224R1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP256K1:
+	DISABLED_IF(FIPS_mode());
 	/* Populate params for secp256k1 */
 	CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_256K1, ec_field_GFp,
 	    params) );
 	break;
 
     case SEC_OID_SECG_EC_SECP384R1:
 	/* Populate params for secp384r1
 	 * (the NIST P-384 curve)
diff --git a/lib/ssl/ssl3ecc.c b/lib/ssl/ssl3ecc.c
--- a/lib/ssl/ssl3ecc.c
+++ b/lib/ssl/ssl3ecc.c
@@ -1145,20 +1145,24 @@ ssl3_SendSupportedCurvesXtn(
         }
     }
     return ecListSize;
 }
 
 PRUint32
 ssl3_GetSupportedECCurveMask(sslSocket *ss)
 {
+    PRUint32 mask = SSL3_ALL_SUPPORTED_CURVES_MASK;
     if (ssl3_SuiteBOnly(ss)) {
-        return SSL3_SUITE_B_SUPPORTED_CURVES_MASK;
+        mask = SSL3_SUITE_B_SUPPORTED_CURVES_MASK;
     }
-    return SSL3_ALL_SUPPORTED_CURVES_MASK;
+    if (PK11_IsFIPS()) {
+        mask &= SSL3_FIPS_SUPPORTED_CURVES_MASK;
+    }
+    return mask;
 }
 
 /* Send our "canned" (precompiled) Supported Point Formats extension,
  * which says that we only support uncompressed points.
  */
 PRInt32
 ssl3_SendSupportedPointFormatsXtn(
                         sslSocket * ss,
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -142,16 +142,18 @@ typedef enum { SSLAppOpRead = 0,
 #define SSL_MAX_CACHED_CERT_LEN		4060
 
 #define NUM_MIXERS                      9
 
 /* Mask of the 25 named curves we support. */
 #define SSL3_ALL_SUPPORTED_CURVES_MASK 0x3fffffe
 /* Mask of only 3 curves, suite B */
 #define SSL3_SUITE_B_SUPPORTED_CURVES_MASK 0x3800000
+/* Mask of the curces supported in FIPS: P-224, P-256, P-384, P-521 */
+#define SSL3_FIPS_SUPPORTED_CURVES_MASK 0x3a00000
 
 #ifndef BPB
 #define BPB 8 /* Bits Per Byte */
 #endif
 
 #define EXPORT_RSA_KEY_LENGTH 64	/* bytes */
 
 #define INITIAL_DTLS_TIMEOUT_MS   1000  /* Default value from RFC 4347 = 1s*/
diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -12,16 +12,17 @@
 #include "ssl.h"
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "nspr.h"
 #include "private/pprio.h"
 #ifndef NO_PKCS11_BYPASS
 #include "blapi.h"
 #endif
+#include "pk11pub.h"
 #include "nss.h"
 #include "pk11pqg.h"
 
 #define SET_ERROR_CODE   /* reminder */
 
 static const sslSocketOps ssl_default_ops = {   /* No SSL. */
     ssl_DefConnect,
     NULL,
@@ -3237,16 +3238,21 @@ ssl_NewSocket(PRBool makeLocks, SSLProto
         ss->pkcs11PinArg       = NULL;
         ss->ephemeralECDHKeyPair = NULL;
 
         ssl_ChooseOps(ss);
         ssl2_InitSocketPolicy(ss);
         ssl3_InitSocketPolicy(ss);
         PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
 
+        /* cannot cresate step down keys in fips mode */
+        if (!ss->opt.noStepDown && PK11_IsFIPS()) {
+            ss->opt.noStepDown = PR_TRUE;
+        }
+
         if (makeLocks) {
             status = ssl_MakeLocks(ss);
             if (status != SECSuccess)
                 goto loser;
         }
         status = ssl_CreateSecurityInfo(ss);
         if (status != SECSuccess)
             goto loser;
