Bug 325672, Create CanBypass function
authorneil.williams%sun.com
Wed, 18 Jul 2007 21:38:55 +0000
changeset 7946 36e45ab2369e3f4be0a35c68e8614255d26788a2
parent 7945 fd3d3c1aaf72c7ce2de3a4339d29a212a5be79cb
child 7948 95ed3563e905c01c4d4ca860de8db43974648ef6
push idunknown
push userunknown
push dateunknown
bugs325672
Bug 325672, Create CanBypass function r=Nelson
security/nss/cmd/selfserv/selfserv.c
security/nss/lib/ssl/derive.c
security/nss/lib/ssl/ssl.def
security/nss/lib/ssl/ssl.h
security/nss/lib/ssl/ssl3ecc.c
security/nss/lib/ssl/sslimpl.h
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -185,16 +185,17 @@ Usage(const char *progName)
 "         [-f fortezza_nickname] [-L [seconds]] [-M maxProcs] [-P dbprefix]\n"
 #else
 "         [-i pid_file] [-c ciphers] [-d dbdir] [-f fortezza_nickname] \n"
 "         [-L [seconds]] [-M maxProcs] [-P dbprefix] [-C SSLCacheEntries]\n"
 #endif /* NSS_ENABLE_ECC */
 "-S means disable SSL v2\n"
 "-3 means disable SSL v3\n"
 "-B bypasses the PKCS11 layer for SSL encryption and MACing\n"
+"-q checks for bypassability\n"
 "-D means disable Nagle delays in TCP\n"
 "-E means disable export ciphersuites and SSL step down key gen\n"
 "-T means disable TLS\n"
 "-R means disable detection of rollback from TLS to SSL3\n"
 "-b means try binding to the port and exit\n"
 "-m means test the model-socket feature of SSL_ImportFD.\n"
 "-r flag is interepreted as follows:\n"
 "    1 -r  means request, not require, cert on initial handshake.\n"
@@ -654,29 +655,41 @@ PRBool disableSSL2     = PR_FALSE;
 PRBool disableSSL3     = PR_FALSE;
 PRBool disableTLS      = PR_FALSE;
 PRBool disableRollBack = PR_FALSE;
 PRBool NoReuse         = PR_FALSE;
 PRBool hasSidCache     = PR_FALSE;
 PRBool disableStepDown = PR_FALSE;
 PRBool bypassPKCS11    = PR_FALSE;
 PRBool disableLocking  = PR_FALSE;
+PRBool testbypass      = PR_FALSE;
 
 static const char stopCmd[] = { "GET /stop " };
 static const char getCmd[]  = { "GET " };
 static const char EOFmsg[]  = { "EOF\r\n\r\n\r\n" };
 static const char outHeader[] = {
     "HTTP/1.0 200 OK\r\n"
     "Server: Generic Web Server\r\n"
     "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
     "Content-type: text/plain\r\n"
     "\r\n"
 };
 static const char crlCacheErr[]  = { "CRL ReCache Error: " };
 
+PRUint16 cipherlist[100];
+int nciphers;
+
+void
+savecipher(int c)
+{
+    if (nciphers < sizeof cipherlist / sizeof (cipherlist[0]))
+	cipherlist[nciphers++] = (PRUint16)c;
+}
+
+
 #ifdef FULL_DUPLEX_CAPABLE
 
 struct lockedVarsStr {
     PZLock *	lock;
     int		count;
     int		waiters;
     PZCondVar *	condVar;
 };
@@ -1670,29 +1683,30 @@ main(int argc, char **argv)
     PRBool               useExportPolicy = PR_FALSE;
     PRBool               useLocalThreads = PR_FALSE;
     PLOptState		*optstate;
     PLOptStatus          status;
     PRThread             *loggerThread;
     PRBool               debugCache = PR_FALSE; /* bug 90518 */
     char                 emptyString[] = { "" };
     char*                certPrefix = emptyString;
-
+    PRUint32		 protos = 0;
+ 
     tmp = strrchr(argv[0], '/');
     tmp = tmp ? tmp + 1 : argv[0];
     progName = strrchr(tmp, '\\');
     progName = progName ? progName + 1 : tmp;
 
     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
 
     /* please keep this list of options in ASCII collating sequence.
     ** numbers, then capital letters, then lower case, alphabetical. 
     */
     optstate = PL_CreateOptState(argc, argv, 
-    	"2:3BC:DEL:M:NP:RSTbc:d:e:f:hi:lmn:op:rst:vw:xy");
+        "2:3BC:DEL:M:NP:RSTbc:d:e:f:hi:lmn:op:qrst:vw:xy");
     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
 	++optionsFound;
 	switch(optstate->option) {
 	case '2': fileName = optstate->value; break;
 
 	case '3': disableSSL3 = PR_TRUE; break;
 
 	case 'B': bypassPKCS11 = PR_TRUE; break;
@@ -1749,16 +1763,18 @@ main(int argc, char **argv)
 	case 'n': nickName = PORT_Strdup(optstate->value); break;
 
 	case 'P': certPrefix = PORT_Strdup(optstate->value); break;
 
 	case 'o': MakeCertOK = 1; break;
 
 	case 'p': port = PORT_Atoi(optstate->value); break;
 
+	case 'q': testbypass = PR_TRUE; break;
+
 	case 'r': ++requestCert; break;
 
 	case 's': disableLocking = PR_TRUE; break;
 
 	case 't':
 	    maxThreads = PORT_Atoi(optstate->value);
 	    if ( maxThreads > MAX_THREADS ) maxThreads = MAX_THREADS;
 	    if ( maxThreads < MIN_THREADS ) maxThreads = MIN_THREADS;
@@ -1972,50 +1988,92 @@ main(int argc, char **argv)
 		fprintf(stderr, 
 			"Invalid cipher specification (-c arg).\n");
 		exit(9);
 	    }
 	}
 	PORT_Free(cstringSaved);
     }
 
+    if (testbypass) {
+	const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
+	int             i            = SSL_NumImplementedCiphers;
+	PRBool		enabled;
+
+	for (i=0; i < SSL_NumImplementedCiphers; i++, cipherSuites++) {
+	    if (SSL_CipherPrefGetDefault(*cipherSuites, &enabled) == SECSuccess
+				    && enabled)
+		savecipher(*cipherSuites);		    
+	}
+	protos = (disableTLS ? 0 : SSL_CBP_TLS1_0) +
+		 (disableSSL3 ? 0 : SSL_CBP_SSL3);
+    }
+
     if (nickName) {
 	cert[kt_rsa] = PK11_FindCertFromNickname(nickName, passwd);
 	if (cert[kt_rsa] == NULL) {
 	    fprintf(stderr, "selfserv: Can't find certificate %s\n", nickName);
 	    exit(10);
 	}
 	privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], passwd);
 	if (privKey[kt_rsa] == NULL) {
 	    fprintf(stderr, "selfserv: Can't find Private Key for cert %s\n", 
 	            nickName);
 	    exit(11);
 	}
+	if (testbypass) {
+	    PRBool bypassOK;
+	    if (SSL_CanBypass(cert[kt_rsa], privKey[kt_rsa], protos, cipherlist, 
+	                      nciphers, &bypassOK, passwd) != SECSuccess) {
+		SECU_PrintError(progName, "Bypass test failed %s\n", nickName);
+		exit(14);
+	    }
+	    fprintf(stderr, "selfserv: %s can%s bypass\n", nickName,
+		    bypassOK ? "" : "not");
+	}
     }
     if (fNickName) {
 	cert[kt_fortezza] = PK11_FindCertFromNickname(fNickName, NULL);
 	if (cert[kt_fortezza] == NULL) {
 	    fprintf(stderr, "selfserv: Can't find certificate %s\n", fNickName);
 	    exit(12);
 	}
 	privKey[kt_fortezza] = PK11_FindKeyByAnyCert(cert[kt_fortezza], NULL);
     }
 #ifdef NSS_ENABLE_ECC
     if (ecNickName) {
-	cert[kt_ecdh] = PK11_FindCertFromNickname(ecNickName, NULL);
+	cert[kt_ecdh] = PK11_FindCertFromNickname(ecNickName, passwd);
 	if (cert[kt_ecdh] == NULL) {
 	    fprintf(stderr, "selfserv: Can't find certificate %s\n",
 		    ecNickName);
 	    exit(13);
 	}
-	privKey[kt_ecdh] = PK11_FindKeyByAnyCert(cert[kt_ecdh], NULL);
+	privKey[kt_ecdh] = PK11_FindKeyByAnyCert(cert[kt_ecdh], passwd);
+	if (privKey[kt_ecdh] == NULL) {
+	    fprintf(stderr, "selfserv: Can't find Private Key for cert %s\n", 
+	            ecNickName);
+	    exit(11);
+	}	    
+	if (testbypass) {
+	    PRBool bypassOK;
+	    if (SSL_CanBypass(cert[kt_ecdh], privKey[kt_ecdh], protos, cipherlist,
+			      nciphers, &bypassOK, passwd) != SECSuccess) {
+		SECU_PrintError(progName, "Bypass test failed %s\n", ecNickName);
+		exit(15);
+	    }
+	    fprintf(stderr, "selfserv: %s can%s bypass\n", ecNickName,
+		    bypassOK ? "" : "not");
+       }
     }
 #endif /* NSS_ENABLE_ECC */
 
-    /* allocate the array of thread slots, and launch the worker threads. */
+    if (testbypass)
+	goto cleanup;
+
+/* allocate the array of thread slots, and launch the worker threads. */
     rv = launch_threads(&jobLoop, 0, 0, requestCert, useLocalThreads);
 
     if (rv == SECSuccess && logStats) {
 	loggerThread = PR_CreateThread(PR_SYSTEM_THREAD, 
 			logger, NULL, PR_PRIORITY_NORMAL, 
                         useLocalThreads ? PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
                         PR_UNJOINABLE_THREAD, 0);
 	if (loggerThread == NULL) {
@@ -2025,16 +2083,17 @@ main(int argc, char **argv)
     }
 
     if (rv == SECSuccess) {
 	server_main(listen_sock, requestCert, privKey, cert);
     }
 
     VLOG(("selfserv: server_thread: exiting"));
 
+cleanup:
     {
 	int i;
 	for (i=0; i<kt_kea_size; i++) {
 	    if (cert[i]) {
 		CERT_DestroyCertificate(cert[i]);
 	    }
 	    if (privKey[i]) {
 		SECKEY_DestroyPrivateKey(privKey[i]);
--- a/security/nss/lib/ssl/derive.c
+++ b/security/nss/lib/ssl/derive.c
@@ -39,16 +39,25 @@
 /* $Id$ */
 
 #include "ssl.h" 	/* prereq to sslimpl.h */
 #include "certt.h"	/* prereq to sslimpl.h */
 #include "keythi.h"	/* prereq to sslimpl.h */
 #include "sslimpl.h"
 #include "blapi.h"
 
+#include "secutil.h"
+#include "pk11func.h"
+#include "secasn1.h"
+#include "cert.h"
+#include "secmodt.h"
+
+#include "sslproto.h"
+#include "sslerr.h"
+
 /* make this a macro! */
 #ifdef NOT_A_MACRO
 static void
 buildSSLKey(unsigned char * keyBlock, unsigned int keyLen, SECItem * result)
 {
     result->type = siBuffer;
     result->data = keyBlock;
     result->len  = keyLen;
@@ -485,9 +494,336 @@ ssl3_MasterKeyDeriveBypass(
     pwSpec->msItem.data = pwSpec->raw_master_secret;
     pwSpec->msItem.len  = SSL3_MASTER_SECRET_LENGTH;
     PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data, 
                                            pwSpec->msItem.len));
 
     return rv;
 }
 
+static SECStatus
+ssl_canExtractMS(PK11SymKey *pms, PRBool isTLS, PRBool isDH, PRBool *pcbp)
+{   SECStatus	      rv;
+    PK11SymKey *    ms = NULL;
+    SECItem         params = {siBuffer, NULL, 0};
+    CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params;
+    unsigned char   rand[SSL3_RANDOM_LENGTH];
+    CK_VERSION      pms_version;
+    CK_MECHANISM_TYPE master_derive;
+    CK_MECHANISM_TYPE key_derive;
+    CK_FLAGS          keyFlags;
+    
+    if (pms == NULL)
+	return(SECFailure);
 
+    PORT_Memset(rand, 0, SSL3_RANDOM_LENGTH);
+
+    if (isTLS) {
+	if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH;
+	else master_derive = CKM_TLS_MASTER_KEY_DERIVE;
+	key_derive    = CKM_TLS_KEY_AND_MAC_DERIVE;
+	keyFlags      = CKF_SIGN | CKF_VERIFY;
+    } else {
+	if (isDH) master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+	else master_derive = CKM_SSL3_MASTER_KEY_DERIVE;
+	key_derive    = CKM_SSL3_KEY_AND_MAC_DERIVE;
+	keyFlags      = 0;
+    }
+
+    master_params.pVersion                     = &pms_version;
+    master_params.RandomInfo.pClientRandom     = rand;
+    master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
+    master_params.RandomInfo.pServerRandom     = rand;
+    master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
+
+    params.data = (unsigned char *) &master_params;
+    params.len  = sizeof master_params;
+
+    ms = PK11_DeriveWithFlags(pms, master_derive, &params, key_derive,
+			      CKA_DERIVE, 0, keyFlags);
+    if (ms == NULL)
+	return(SECFailure);
+
+    rv = PK11_ExtractKeyValue(ms);
+    *pcbp = (rv == SECSuccess);
+    PK11_FreeSymKey(ms);
+    
+    return(rv);
+
+}
+
+/* Check the key exchange algorithm for each cipher in the list to see if
+ * a master secret key can be extracted. If the KEA will use keys from the 
+ * specified cert make sure the extract operation is attempted from the slot
+ * where the private key resides.
+ * If MS can be extracted for all ciphers, (*pcanbypass) is set to TRUE and
+ * SECSuccess is returned. In all other cases but one (*pcanbypass) is
+ * set to FALSE and SECFailure is returned.
+ * In that last case Derive() has been called successfully but the MS is null, 
+ * CanBypass sets (*pcanbypass) to FALSE and returns SECSuccess indicating the
+ * arguments were all valid but the slot cannot be bypassed.
+ */
+
+SECStatus 
+SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
+	      PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites,
+              PRBool *pcanbypass, void *pwArg)
+{   SECStatus	      rv;
+    int		      i;
+    PRUint16	      suite;
+    PK11SymKey *      pms = NULL;
+    SECKEYPublicKey * srvPubkey = NULL;
+    KeyType	      privKeytype;
+    PK11SlotInfo *    slot = NULL;
+    SECItem           param;
+    CK_VERSION 	      version;
+    CK_MECHANISM_TYPE mechanism_array[2];
+    SECItem           enc_pms = {siBuffer, NULL, 0};
+    PRBool	      isTLS = PR_FALSE;
+    PRBool	      isDH = PR_FALSE;
+    SSLCipherSuiteInfo csdef;
+    PRBool	      extractable;
+    PRBool	      testrsa = PR_FALSE;
+    PRBool	      testrsa_export = PR_FALSE;
+    PRBool	      testecdh = PR_FALSE;
+    PRBool	      testecdhe = PR_FALSE;
+
+    if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    
+    srvPubkey = CERT_ExtractPublicKey(cert);
+    if (!srvPubkey)
+        return SECFailure;
+	
+    *pcanbypass = PR_TRUE;
+    rv = SECFailure;
+    
+    /* determine which KEAs to test */
+    for (i=0; i < nsuites && (suite = *ciphersuites++) != NULL; i++) {
+	/* skip SSL2 cipher suites and ones NSS doesn't support */
+	if (SSL_GetCipherSuiteInfo(suite, &csdef, sizeof(csdef)) != SECSuccess
+	    || SSL_IS_SSL2_CIPHER(suite) )
+	    continue;
+	switch (csdef.keaType) {
+	case ssl_kea_rsa:
+	    switch (csdef.cipherSuite) {
+	    case TLS_RSA_EXPORT1024_WITH_RC4_56_SHA:
+	    case TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA:
+	    case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
+	    case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
+		testrsa_export = PR_TRUE;
+	    }
+	    if (!testrsa_export)
+		testrsa = PR_TRUE;
+	    break;
+	case ssl_kea_ecdh:
+	    if (strcmp(csdef.keaTypeName, "ECDHE") == 0) /* ephemeral? */
+		testecdhe = PR_TRUE;
+	    else
+		testecdh = PR_TRUE;
+	    break;
+	case ssl_kea_dh:
+	    /* this is actually DHE */
+	default:
+	    continue;
+	}
+    }
+    
+    /* For each protocol try to derive and extract an MS.
+     * Failure of function any function except MS extract means
+     * continue with the next cipher test. Stop testing when the list is
+     * exhausted or when the first MS extract--not derive--fails.
+     */
+    privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey);
+    protocolmask &= SSL_CBP_SSL3|SSL_CBP_TLS1_0;
+    while (protocolmask) {
+	if (protocolmask & SSL_CBP_SSL3) {
+	    isTLS = PR_FALSE;
+	    protocolmask ^= SSL_CBP_SSL3;
+	} else {
+	    isTLS = PR_TRUE;
+	    protocolmask ^= SSL_CBP_TLS1_0;
+	}
+
+	if (privKeytype == rsaKey && testrsa_export) {
+	    if (PK11_GetPrivateModulusLen(srvPrivkey) > EXPORT_RSA_KEY_LENGTH) {
+		*pcanbypass = PR_FALSE;
+		rv = SECSuccess;
+		break;
+	    } else
+		testrsa = PR_TRUE;
+	}
+	for (; privKeytype == rsaKey && testrsa; ) {
+	    /* TLS_RSA */
+	    unsigned char     rsaPmsBuf[SSL3_RSA_PMS_LENGTH];
+	    unsigned int      outLen = 0;
+	    CK_MECHANISM_TYPE target;
+	    SECStatus	      irv;
+	    
+	    mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN;
+	    mechanism_array[1] = CKM_RSA_PKCS;
+
+	    slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg);
+	    if (slot == NULL) {
+		PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND);
+		break;
+	    }
+
+	    /* Generate the pre-master secret ...  (client side) */
+	    version.major = 3 /*MSB(clientHelloVersion)*/;
+	    version.minor = 0 /*LSB(clientHelloVersion)*/;
+	    param.data = (unsigned char *)&version;
+	    param.len  = sizeof version;
+	    pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, &param, 0, pwArg);
+	    PK11_FreeSlot(slot);
+	    if (!pms)
+		break;
+	    /* now wrap it */
+	    enc_pms.len  = SECKEY_PublicKeyStrength(srvPubkey);
+	    enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len);
+	    irv = PK11_PubWrapSymKey(CKM_RSA_PKCS, srvPubkey, pms, &enc_pms);
+	    if (irv != SECSuccess) 
+		break;
+	    PK11_FreeSymKey(pms);
+	    /* now do the server side--check the triple bypass first */
+	    rv = PK11_PrivDecryptPKCS1(srvPrivkey, rsaPmsBuf, &outLen,
+				       sizeof rsaPmsBuf,
+				       (unsigned char *)enc_pms.data,
+				       enc_pms.len);
+	    /* if decrypt worked we're done with the RSA test */
+	    if (rv == SECSuccess) {
+		*pcanbypass = PR_TRUE;
+		break;
+	    }
+	    /* check for fallback to double bypass */
+	    target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE
+			: CKM_SSL3_MASTER_KEY_DERIVE;
+	    pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms,
+				       target, CKA_DERIVE, 0);
+	    rv = ssl_canExtractMS(pms, isTLS, PR_FALSE, pcanbypass);
+	    if (rv == SECSuccess && *pcanbypass == PR_FALSE)
+		goto done;
+	    break;
+	}
+#ifdef NSS_ENABLE_ECC
+	for (; (privKeytype == ecKey && ( testecdh || testecdhe)) ||
+	       (privKeytype == rsaKey && testecdhe); ) {
+	    CK_MECHANISM_TYPE target;
+	    SECKEYPublicKey  *keapub = NULL;
+	    SECKEYPrivateKey *keapriv;
+	    SECKEYPublicKey  *cpub = NULL; /* client's ephemeral ECDH keys */
+	    SECKEYPrivateKey *cpriv = NULL;
+	    SECKEYECParams    ecParams = { siBuffer, NULL, 0 },
+			      *pecParams;
+
+	    if (privKeytype == ecKey && testecdhe) {
+		/* TLS_ECDHE_ECDSA */
+		pecParams = &srvPubkey->u.ec.DEREncodedParams;
+	    } else if (privKeytype == rsaKey && testecdhe) {
+		/* TLS_ECDHE_RSA */
+		ECName       ec_curve;
+		int		 serverKeyStrengthInBits;
+		int		 signatureKeyStrength;
+		int		 requiredECCbits;
+
+		/* find a curve of equivalent strength to the RSA key's */
+		requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey);
+		if (requiredECCbits < 0)
+		    break;
+		requiredECCbits *= BPB;
+		serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len;
+		if (srvPubkey->u.rsa.modulus.data[0] == 0) {
+		    serverKeyStrengthInBits--;
+		}
+		/* convert to strength in bits */
+		serverKeyStrengthInBits *= BPB;
+
+		signatureKeyStrength =
+		    SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
+
+		if ( requiredECCbits > signatureKeyStrength ) 
+		     requiredECCbits = signatureKeyStrength;
+
+		ec_curve =
+		    ssl3_GetCurveWithECKeyStrength(SSL3_SUPPORTED_CURVES_MASK,
+						   requiredECCbits);
+		rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams);
+		if (rv == SECFailure) {
+		    break;
+		}
+		pecParams = &ecParams;
+	    }
+
+	    if (testecdhe) {
+		/* generate server's ephemeral keys */
+		keapriv = SECKEY_CreateECPrivateKey(pecParams, &keapub, NULL); 
+		if (!keapriv || !keapub) {
+		    if (keapriv)
+			SECKEY_DestroyPrivateKey(keapriv);
+		    if (keapub)
+			SECKEY_DestroyPublicKey(keapub);
+		    PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
+		    rv = SECFailure;
+		    break;
+		}
+	    } else {
+		/* TLS_ECDH_ECDSA */
+		keapub = srvPubkey;
+		keapriv = srvPrivkey;
+		pecParams = &srvPubkey->u.ec.DEREncodedParams;
+	    }
+
+	    /* perform client side ops */
+	    /* generate a pair of ephemeral keys using server's parms */
+	    cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL);
+	    if (!cpriv || !cpub) {
+		if (testecdhe) {
+		    SECKEY_DestroyPrivateKey(keapriv);
+		    SECKEY_DestroyPublicKey(keapub);
+		}
+		PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
+		rv = SECFailure;
+		break;
+	    }
+	    /* now do the server side */
+	    /* determine the PMS using client's public value */
+	    target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE_DH
+			   : CKM_SSL3_MASTER_KEY_DERIVE_DH;
+	    pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL,
+				    CKM_ECDH1_DERIVE,
+				    target,
+				    CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
+	    rv = ssl_canExtractMS(pms, isTLS, PR_TRUE, pcanbypass);
+	    SECKEY_DestroyPrivateKey(cpriv);
+	    SECKEY_DestroyPublicKey(cpub);
+	    if (testecdhe) {
+		SECKEY_DestroyPrivateKey(keapriv);
+		SECKEY_DestroyPublicKey(keapub);
+		if (privKeytype == rsaKey)
+		    PORT_Free(ecParams.data);
+	    }
+	    if (rv == SECSuccess && *pcanbypass == PR_FALSE)
+		goto done;
+	    break;
+	}
+#endif /* NSS_ENABLE_ECC */
+	if (pms)
+	    PK11_FreeSymKey(pms);
+    }
+
+    /* *pcanbypass has been set */
+    rv = SECSuccess;
+    
+  done:
+    if (pms)
+	PK11_FreeSymKey(pms);
+    
+    if (srvPubkey) {
+    	SECKEY_DestroyPublicKey(srvPubkey);
+	srvPubkey = NULL;
+    }
+
+
+    return rv;
+}
+
--- a/security/nss/lib/ssl/ssl.def
+++ b/security/nss/lib/ssl/ssl.def
@@ -128,8 +128,14 @@ SSL_ShutdownServerSessionIDCache;
 ;+};
 ;+NSS_3.11.4 {      # NSS 3.11.4 release
 ;+    global:
 SSL_ForceHandshakeWithTimeout;
 SSL_ReHandshakeWithTimeout;
 ;+    local:
 ;+*;
 ;+};
+;+NSS_3.11.7 {      # NSS 3.11.7 release
+;+    global:
+SSL_CanBypass;
+;+    local:
+;+*;
+;+};
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -469,11 +469,42 @@ SSL_IMPORT SECStatus SSL_GetCipherSuiteI
                                         SSLCipherSuiteInfo *info, PRUintn len);
 
 /*
 ** Return a new reference to the certificate that was most recently sent
 ** to the peer on this SSL/TLS connection, or NULL if none has been sent.
 */
 SSL_IMPORT CERTCertificate * SSL_LocalCertificate(PRFileDesc *fd);
 
+/* Test an SSL configuration to see if  SSL_BYPASS_PKCS11 can be turned on.
+** Check the key exchange algorithm for each cipher in the list to see if
+** a master secret key can be extracted after being derived with the mechanism
+** required by the protocolmask argument. If the KEA will use keys from the
+** specified cert make sure the extract operation is attempted from the slot
+** where the private key resides.
+** If MS can be extracted for all ciphers, (*pcanbypass) is set to TRUE and
+** SECSuccess is returned. In all other cases but one (*pcanbypass) is
+** set to FALSE and SECFailure is returned.
+** In that last case Derive() has been called successfully but the MS is null,
+** CanBypass sets (*pcanbypass) to FALSE and returns SECSuccess indicating the
+** arguments were all valid but the slot cannot be bypassed.
+**
+** Note: A TRUE return code from CanBypass means "Your configuration will perform
+** NO WORSE with the bypass enabled than without"; it does NOT mean that every
+** cipher suite listed will work properly with the selected protocols.
+**
+** Caveat: If export cipher suites are included in the argument list Canbypass
+** will return FALSE.
+**/
+
+/* protocol mask bits */
+#define SSL_CBP_SSL3	0x0001	        /* test SSL v3 mechanisms */
+#define SSL_CBP_TLS1_0	0x0002		/* test TLS v1.0 mechanisms */
+
+SSL_IMPORT SECStatus SSL_CanBypass(CERTCertificate *cert,
+                                   SECKEYPrivateKey *privKey,
+				   PRUint32 protocolmask,
+				   PRUint16 *ciphers, int nciphers,
+                                   PRBool *pcanbypass, void *pwArg);
+
 SEC_END_PROTOS
 
 #endif /* __ssl_h_ */
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -75,55 +75,22 @@
 #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
 		(x)->pValue=(v); (x)->ulValueLen = (l);
 #endif
 
 #define SSL_GET_SERVER_PUBLIC_KEY(sock, type) \
     (ss->serverCerts[type].serverKeyPair ? \
     ss->serverCerts[type].serverKeyPair->pubKey : NULL)
 
-#define SSL_IS_CURVE_NEGOTIATED(ss, curveName) \
+#define SSL_IS_CURVE_NEGOTIATED(curvemsk, curveName) \
     ((curveName > ec_noName) && \
      (curveName < ec_pastLastName) && \
-     ((1UL << curveName) & ss->ssl3.hs.negotiatedECCurves) != 0)
-
-/* Types and names of elliptic curves used in TLS */
-typedef enum { ec_type_explicitPrime      = 1,
-	       ec_type_explicitChar2Curve = 2,
-	       ec_type_named
-} ECType;
+     ((1UL << curveName) & curvemsk) != 0)
 
-typedef enum { ec_noName     = 0,
-	       ec_sect163k1  = 1, 
-	       ec_sect163r1  = 2, 
-	       ec_sect163r2  = 3,
-	       ec_sect193r1  = 4, 
-	       ec_sect193r2  = 5, 
-	       ec_sect233k1  = 6,
-	       ec_sect233r1  = 7, 
-	       ec_sect239k1  = 8, 
-	       ec_sect283k1  = 9,
-	       ec_sect283r1  = 10, 
-	       ec_sect409k1  = 11, 
-	       ec_sect409r1  = 12,
-	       ec_sect571k1  = 13, 
-	       ec_sect571r1  = 14, 
-	       ec_secp160k1  = 15,
-	       ec_secp160r1  = 16, 
-	       ec_secp160r2  = 17, 
-	       ec_secp192k1  = 18,
-	       ec_secp192r1  = 19, 
-	       ec_secp224k1  = 20, 
-	       ec_secp224r1  = 21,
-	       ec_secp256k1  = 22, 
-	       ec_secp256r1  = 23, 
-	       ec_secp384r1  = 24,
-	       ec_secp521r1  = 25,
-	       ec_pastLastName
-} ECName;
+
 
 static SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve);
 
 #define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName))
 
 /* Table containing OID tags for elliptic curves named in the
  * ECC-TLS IETF draft.
  */
@@ -224,18 +191,18 @@ typedef struct ECDHEKeyPairStr {
     ssl3KeyPair *  pair;
     int            error;  /* error code of the call-once function */
     PRCallOnceType once;
 } ECDHEKeyPair;
 
 /* arrays of ECDHE KeyPairs */
 static ECDHEKeyPair gECDHEKeyPairs[ec_pastLastName];
 
-static SECStatus 
-ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params)
+SECStatus 
+ssl3_ECName2Params(PRArenaPool * arena, ECName curve, SECKEYECParams * params)
 {
     SECOidData *oidData = NULL;
 
     if ((curve <= ec_noName) || (curve >= ec_pastLastName) ||
 	((oidData = SECOID_FindOIDByTag(ecName2OIDTag[curve])) == NULL)) {
         PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
 	return SECFailure;
     }
@@ -465,33 +432,49 @@ ssl3_HandleECDHClientKeyExchange(sslSock
     PK11_FreeSymKey(pms);
     if (rv != SECSuccess) {
 	SEND_ALERT
 	return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */
     }
     return SECSuccess;
 }
 
+ECName
+ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits)
+{
+    int    i;
+    
+    for ( i = 0; bits2curve[i].curve != ec_noName; i++) {
+	if (bits2curve[i].bits < requiredECCbits)
+	    continue;
+    	if (SSL_IS_CURVE_NEGOTIATED(curvemsk, bits2curve[i].curve)) {
+	    return bits2curve[i].curve;
+	}
+    }
+    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+    return ec_noName;
+}
+
 /* find the "weakest link".  Get strength of signature key and of sym key.
  * choose curve for the weakest of those two.
  */
 ECName
 ssl3_GetCurveNameForServerSocket(sslSocket *ss)
 {
     SECKEYPublicKey * svrPublicKey = NULL;
     ECName ec_curve = ec_noName;
     int    signatureKeyStrength = 521;
     int    requiredECCbits = ss->sec.secretKeyBits * 2;
     int    i;
 
     if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa) {
 	svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_ecdh);
 	if (svrPublicKey)
 	    ec_curve = params2ecName(&svrPublicKey->u.ec.DEREncodedParams);
-	if (!SSL_IS_CURVE_NEGOTIATED(ss, ec_curve)) {
+	if (!SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves, ec_curve)) {
 	    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
 	    return ec_noName;
 	}
 	signatureKeyStrength = curve2bits[ ec_curve ];
     } else {
         /* RSA is our signing cert */
         int serverKeyStrengthInBits;
  
@@ -504,40 +487,24 @@ ssl3_GetCurveNameForServerSocket(sslSock
         /* currently strength in bytes */
         serverKeyStrengthInBits = svrPublicKey->u.rsa.modulus.len;
         if (svrPublicKey->u.rsa.modulus.data[0] == 0) {
             serverKeyStrengthInBits--;
         }
         /* convert to strength in bits */
         serverKeyStrengthInBits *= BPB;
  
-        if (serverKeyStrengthInBits <= 1024) {
-            signatureKeyStrength = 160;
-        } else if (serverKeyStrengthInBits <= 2048) {
-            signatureKeyStrength = 224;
-        } else if (serverKeyStrengthInBits <= 3072) {
-            signatureKeyStrength = 256;
-        } else if (serverKeyStrengthInBits <= 7168) {
-            signatureKeyStrength = 384;
-        } else  {
-            signatureKeyStrength = 521;
-        }
+        signatureKeyStrength =
+	    SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
     }
     if ( requiredECCbits > signatureKeyStrength ) 
          requiredECCbits = signatureKeyStrength;
 
-    for ( i = 0; bits2curve[i].curve != ec_noName; i++) {
-	if (bits2curve[i].bits < requiredECCbits)
-	    continue;
-    	if (SSL_IS_CURVE_NEGOTIATED(ss, bits2curve[i].curve)) {
-	    return bits2curve[i].curve;
-	}
-    }
-    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
-    return ec_noName;
+    return ssl3_GetCurveWithECKeyStrength(ss->ssl3.hs.negotiatedECCurves,
+					  requiredECCbits);
 }
 
 /* function to clear out the lists */
 static SECStatus 
 ssl3_ShutdownECDHECurves(void *appData, void *nssData)
 {
     int i;
     ECDHEKeyPair *keyPair = &gECDHEKeyPairs[0];
@@ -570,17 +537,17 @@ ssl3_CreateECDHEphemeralKeyPair(void * a
     SECKEYPublicKey *     pubKey   = NULL;
     ssl3KeyPair *	  keyPair  = NULL;
     ECName                ec_curve = (ECName)arg;
     SECKEYECParams        ecParams = { siBuffer, NULL, 0 };
 
     PORT_Assert(gECDHEKeyPairs[ec_curve].pair == NULL);
 
     /* ok, no one has generated a global key for this curve yet, do so */
-    if (ecName2params(NULL, ec_curve, &ecParams) != SECSuccess) {
+    if (ssl3_ECName2Params(NULL, ec_curve, &ecParams) != SECSuccess) {
 	gECDHEKeyPairs[ec_curve].error = PORT_GetError();
 	return PR_FAILURE;
     }
 
     privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL);    
     SECITEM_FreeItem(&ecParams, PR_FALSE);
 
     if (!privKey || !pubKey || !(keyPair = ssl3_NewKeyPair(privKey, pubKey))) {
@@ -737,17 +704,17 @@ ssl3_HandleECDHServerKeyExchange(sslSock
     if (peerKey == NULL) {
 	goto no_memory;
     }
 
     peerKey->arena                 = arena;
     peerKey->keyType               = ecKey;
 
     /* set up EC parameters in peerKey */
-    if (ecName2params(arena, ec_params.data[2], 
+    if (ssl3_ECName2Params(arena, ec_params.data[2], 
 	    &peerKey->u.ec.DEREncodedParams) != SECSuccess) {
 	/* we should never get here since we already 
 	 * checked that we are dealing with a supported curve
 	 */
 	errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
 	goto alert_loser;
     }
 
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -186,16 +186,18 @@ typedef enum { SSLAppOpRead = 0,
 #else
 #define SSL3_SUPPORTED_CURVES_MASK 0x3fffffe
 #endif
 
 #ifndef BPB
 #define BPB 8 /* Bits Per Byte */
 #endif
 
+#define EXPORT_RSA_KEY_LENGTH 64	/* bytes */
+
 typedef struct sslBufferStr             sslBuffer;
 typedef struct sslConnectInfoStr        sslConnectInfo;
 typedef struct sslGatherStr             sslGather;
 typedef struct sslSecurityInfoStr       sslSecurityInfo;
 typedef struct sslSessionIDStr          sslSessionID;
 typedef struct sslSocketStr             sslSocket;
 typedef struct sslSocketOpsStr          sslSocketOps;
 
@@ -1278,16 +1280,64 @@ int ssl3_GatherCompleteHandshake(sslSock
  */
 extern SECStatus ssl3_CreateRSAStepDownKeys(sslSocket *ss);
 
 #ifdef NSS_ENABLE_ECC
 extern void      ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss);
 extern PRBool    ssl3_IsECCEnabled(sslSocket *ss);
 extern SECStatus ssl3_DisableECCSuites(sslSocket * ss, 
                                        const ssl3CipherSuite * suite);
+
+/* Macro for finding a curve equivalent in strength to RSA key's */
+#define SSL_RSASTRENGTH_TO_ECSTRENGTH(s) \
+        ((s <= 1024) ? 160 \
+	  : ((s <= 2048) ? 224 \
+	    : ((s <= 3072) ? 256 \
+	      : ((s <= 7168) ? 384 : 521 ) ) ) )
+
+/* Types and names of elliptic curves used in TLS */
+typedef enum { ec_type_explicitPrime      = 1,
+	       ec_type_explicitChar2Curve = 2,
+	       ec_type_named
+} ECType;
+
+typedef enum { ec_noName     = 0,
+	       ec_sect163k1  = 1, 
+	       ec_sect163r1  = 2, 
+	       ec_sect163r2  = 3,
+	       ec_sect193r1  = 4, 
+	       ec_sect193r2  = 5, 
+	       ec_sect233k1  = 6,
+	       ec_sect233r1  = 7, 
+	       ec_sect239k1  = 8, 
+	       ec_sect283k1  = 9,
+	       ec_sect283r1  = 10, 
+	       ec_sect409k1  = 11, 
+	       ec_sect409r1  = 12,
+	       ec_sect571k1  = 13, 
+	       ec_sect571r1  = 14, 
+	       ec_secp160k1  = 15,
+	       ec_secp160r1  = 16, 
+	       ec_secp160r2  = 17, 
+	       ec_secp192k1  = 18,
+	       ec_secp192r1  = 19, 
+	       ec_secp224k1  = 20, 
+	       ec_secp224r1  = 21,
+	       ec_secp256k1  = 22, 
+	       ec_secp256r1  = 23, 
+	       ec_secp384r1  = 24,
+	       ec_secp521r1  = 25,
+	       ec_pastLastName
+} ECName;
+
+extern SECStatus ssl3_ECName2Params(PRArenaPool *arena, ECName curve,
+				   SECKEYECParams *params);
+ECName	ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits);
+
+
 #endif /* NSS_ENABLE_ECC */
 
 extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);
 extern SECStatus ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *on);
 extern SECStatus ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
 extern SECStatus ssl2_CipherPrefGetDefault(PRInt32 which, PRBool *enabled);
 
 extern SECStatus ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool on);
@@ -1418,16 +1468,17 @@ PRBool    SSL_IsExportCipherSuite(PRUint
 
 #ifdef TRACE
 #define SSL_TRACE(msg) ssl_Trace msg
 #else
 #define SSL_TRACE(msg)
 #endif
 
 void ssl_Trace(const char *format, ...);
+ECName	ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits);
 
 SEC_END_PROTOS
 
 #ifdef XP_OS2_VACPP
 #include <process.h>
 #endif
 
 #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)