diff options
author | neil.williams%sun.com <devnull@localhost> | 2007-04-23 23:48:04 +0000 |
---|---|---|
committer | neil.williams%sun.com <devnull@localhost> | 2007-04-23 23:48:04 +0000 |
commit | 695218eddbbe2c6c6055b87608ea1d875160e953 (patch) | |
tree | b66032b5a14759ad4edf5d43ba55ec6f81829451 | |
parent | bd10c376015c174358a423c675f74e25cd7c8d89 (diff) | |
download | nss-hg-695218eddbbe2c6c6055b87608ea1d875160e953.tar.gz |
Enh 325672, test function for bypassability, r=nelson
-rw-r--r-- | security/nss/lib/ssl/derive.c | 150 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3con.c | 3 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3ecc.c | 94 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslimpl.h | 49 |
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, ¶m, 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 |