summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorneil.williams%sun.com <devnull@localhost>2007-04-23 23:48:04 +0000
committerneil.williams%sun.com <devnull@localhost>2007-04-23 23:48:04 +0000
commit695218eddbbe2c6c6055b87608ea1d875160e953 (patch)
treeb66032b5a14759ad4edf5d43ba55ec6f81829451
parentbd10c376015c174358a423c675f74e25cd7c8d89 (diff)
downloadnss-hg-695218eddbbe2c6c6055b87608ea1d875160e953.tar.gz
Enh 325672, test function for bypassability, r=nelson
-rw-r--r--security/nss/lib/ssl/derive.c150
-rw-r--r--security/nss/lib/ssl/ssl3con.c3
-rw-r--r--security/nss/lib/ssl/ssl3ecc.c94
-rw-r--r--security/nss/lib/ssl/sslimpl.h49
4 files changed, 188 insertions, 108 deletions
diff --git a/security/nss/lib/ssl/derive.c b/security/nss/lib/ssl/derive.c
index e19b18e99..c347fa148 100644
--- a/security/nss/lib/ssl/derive.c
+++ b/security/nss/lib/ssl/derive.c
@@ -50,6 +50,7 @@
#include "secasn1.h"
#include "cert.h"
#include "secmodt.h"
+#include "keythi.h"
#include "sslproto.h"
#include "sslerr.h"
@@ -501,7 +502,7 @@ ssl3_MasterKeyDeriveBypass(
return rv;
}
-static PRBool
+static SECStatus
ssl_canExtractMS(PK11SymKey *pms, PRBool isDH, PRBool *pcbp)
{ SECStatus rv;
PK11SymKey * ms = NULL;
@@ -529,14 +530,13 @@ ssl_canExtractMS(PK11SymKey *pms, PRBool isDH, PRBool *pcbp)
CKM_TLS_KEY_AND_MAC_DERIVE, CKA_DERIVE, 0,
0);
if (ms == NULL)
- return(PR_FALSE);
+ return(SECFailure);
rv = PK11_ExtractKeyValue(ms);
-
+ *pcbp = (rv == SECSuccess);
PK11_FreeSymKey(ms);
- *pcbp = (rv == SECSuccess);
- return(PR_TRUE);
+ return(rv);
}
@@ -573,6 +573,7 @@ SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
SSLCipherSuiteInfo csdef;
PRBool extractable;
PRBool testrsa = PR_FALSE;
+ PRBool testrsa_export = PR_FALSE;
PRBool testecdh = PR_FALSE;
PRBool testecdhe = PR_FALSE;
@@ -590,6 +591,13 @@ SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
switch (csdef.keaType) {
case ssl_kea_rsa:
testrsa = PR_TRUE;
+ 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;
+ }
break;
case ssl_kea_ecdh:
if (strcmp(csdef.keaTypeName, "ECDHE") == 0) /* ephemeral? */
@@ -598,6 +606,7 @@ SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
testecdh = PR_TRUE;
break;
case ssl_kea_dh:
+ /* this is actually DHE */
default:
continue;
}
@@ -606,9 +615,15 @@ SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
srvPubkey = CERT_ExtractPublicKey(cert);
privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey);
- switch (privKeytype) {
+ if (privKeytype == rsaKey && testrsa) {
+ /* TLS_RSA */
int irv;
- case rsaKey:
+
+ if (testrsa_export && PK11_GetPrivateModulusLen(srvPrivkey)
+ > EXPORT_RSA_KEY_LENGTH) {
+ rv = SECSuccess;
+ goto done;
+ }
mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN;
mechanism_array[1] = CKM_RSA_PKCS;
@@ -619,8 +634,8 @@ SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
}
/* Generate the pre-master secret ... (client side) */
- version.major = 3 /*MSB(ss->clientHelloVersion)*/;
- version.minor = 0 /*LSB(ss->clientHelloVersion)*/;
+ 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);
@@ -637,55 +652,106 @@ SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
* but we're only testing the double bypass case */
pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms,
CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
- break;
- case ecKey: {
+ rv = ssl_canExtractMS(pms, PR_FALSE, pcanbypass);
+ if (rv != SECSuccess)
+ goto done;
+ }
+#ifdef NSS_ENABLE_ECC
+ if ((privKeytype == ecKey && ( testecdh || testecdhe)) ||
+ (privKeytype == rsaKey && testecdhe) ) {
+ SECKEYPublicKey *keapub;
+ 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) * BPB;
+ serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len;
+ if (srvPubkey->u.rsa.modulus.data[0] == 0) {
+ serverKeyStrengthInBits--;
+ }
+ /* convert to strength in bits */
+ serverKeyStrengthInBits *= BPB;
- /* perform client side KEA ops */
- /* generate a pair of ephemeral keys using server's parms */
- cpriv = SECKEY_CreateECPrivateKey(&srvPubkey->u.ec.DEREncodedParams,
- &cpub, NULL);
- if (!cpriv || !cpub) {
+ signatureKeyStrength =
+ SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
+
+ if ( requiredECCbits > signatureKeyStrength )
+ requiredECCbits = signatureKeyStrength;
+
+ ec_curve = ssl3_GetCurveWithECKeyStrength(SSL3_SUPPORTED_CURVES_MASK,
+ requiredECCbits);
+ rv = ssl_ECName2Params(NULL, ec_curve, &ecParams);
+ if (rv == SECFailure) {
+ goto done;
+ }
+ 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;
goto done;
+ }
+ } 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;
+ goto done;
}
/* now do the server side */
/* determine the PMS using client's public value */
- pms = PK11_PubDeriveWithKDF(srvPrivkey, cpub, PR_FALSE, NULL, NULL,
+ pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL,
CKM_ECDH1_DERIVE,
CKM_TLS_MASTER_KEY_DERIVE_DH,
CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
+ rv = ssl_canExtractMS(pms, PR_TRUE, pcanbypass);
SECKEY_DestroyPrivateKey(cpriv);
SECKEY_DestroyPublicKey(cpub);
+ if (testecdhe) {
+ SECKEY_DestroyPrivateKey(keapriv);
+ SECKEY_DestroyPublicKey(keapub);
+ if (privKeytype == rsaKey)
+ PORT_Free(ecParams.data);
}
- isDH = PR_TRUE;
- break;
- case dsaKey:
- default:
- break; /*can't bypass */
- }
-
- if (pms == NULL) {
- /*fprintf(stderr, "could not generate PMS"); */
- goto done;
- }
-
- if (testrsa && privKeytype == rsaKey
- && !ssl_canExtractMS(pms, PR_FALSE, pcanbypass) && ! *pcanbypass) {
- goto done;
- }
- if (testecdhe) {
- /* treat this like the non-ephemeral case since the server's cert
- must be an ecKey */
- testecdh = PR_TRUE;
- }
- if (testecdh && privKeytype == ecKey
- && !ssl_canExtractMS(pms, PR_TRUE, pcanbypass) && !*pcanbypass) {
- goto done;
+ if (rv != SECSuccess)
+ goto done;
}
+#endif /* NSS_ENABLE_ECC */
- /* *pcanbypass = PR_TRUE; set by ssl_canExtractMS() */
+ /* *pcanbypass has been set */
rv = SECSuccess;
done:
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 6fa531124..e16d25de3 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -194,9 +194,6 @@ static const /*SSL3ClientCertificateType */ uint8 certificate_types [] = {
*/
#define SSL3_BUFFER_FUDGE 100
-#define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
-
-
/* This is a hack to make sure we don't do double handshakes for US policy */
PRBool ssl3_global_policy_some_restricted = PR_FALSE;
diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c
index ab2e96144..d48babf08 100644
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -80,45 +80,12 @@
(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;
-
-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;
+ ((1UL << curveName) & curvemsk) != 0)
+
+
static SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve);
@@ -229,8 +196,8 @@ typedef struct ECDHEKeyPairStr {
/* arrays of ECDHE KeyPairs */
static ECDHEKeyPair gECDHEKeyPairs[ec_pastLastName];
-static SECStatus
-ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params)
+SECStatus
+ssl_ECName2Params(PRArenaPool * arena, ECName curve, SECKEYECParams * params)
{
SECOidData *oidData = NULL;
@@ -470,6 +437,22 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
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.
*/
@@ -486,7 +469,7 @@ ssl3_GetCurveNameForServerSocket(sslSocket *ss)
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;
}
@@ -508,31 +491,16 @@ ssl3_GetCurveNameForServerSocket(sslSocket *ss)
}
/* 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 */
@@ -575,7 +543,7 @@ ssl3_CreateECDHEphemeralKeyPair(void * arg)
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 (ssl_ECName2Params(NULL, ec_curve, &ecParams) != SECSuccess) {
gECDHEKeyPairs[ec_curve].error = PORT_GetError();
return PR_FAILURE;
}
@@ -742,7 +710,7 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
peerKey->keyType = ecKey;
/* set up EC parameters in peerKey */
- if (ecName2params(arena, ec_params.data[2],
+ if (ssl_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
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index c5c57a867..a30aed4a8 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -190,6 +190,8 @@ typedef enum { SSLAppOpRead = 0,
#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;
@@ -1280,6 +1282,52 @@ 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 ssl_ECName2Params(PRArenaPool *arena, ECName curve,
+ SECKEYECParams *params);
+
#endif /* NSS_ENABLE_ECC */
extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);
@@ -1420,6 +1468,7 @@ PRBool SSL_IsExportCipherSuite(PRUint16 cipherSuite);
#endif
void ssl_Trace(const char *format, ...);
+ECName ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits);
SEC_END_PROTOS