mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Implement TLS Hello extensions for ECC. Bug 236245. r=rrelyea.
This patch has a known problem, choosing ephemeral ECDH curves according to the wrong (suboptimal, non-FIPS) criteria. Modified Files: ssl3con.c ssl3ecc.c sslimpl.h
This commit is contained in:
parent
af83510020
commit
c4fb4fa280
@ -39,7 +39,7 @@
|
|||||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
/* $Id: ssl3con.c,v 1.85 2006/04/07 06:24:07 nelson%bolyard.com Exp $ */
|
/* $Id: ssl3con.c,v 1.86 2006/04/13 23:08:18 nelson%bolyard.com Exp $ */
|
||||||
|
|
||||||
#include "nssrenam.h"
|
#include "nssrenam.h"
|
||||||
#include "cert.h"
|
#include "cert.h"
|
||||||
@ -5377,24 +5377,6 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
|||||||
goto loser; /* malformed */
|
goto loser; /* malformed */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle TLS hello extensions, for SSL3 & TLS */
|
|
||||||
if (length) {
|
|
||||||
/* Get length of hello extensions */
|
|
||||||
PRInt32 extension_length;
|
|
||||||
extension_length = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
|
|
||||||
if (extension_length < 0) {
|
|
||||||
goto loser; /* alert already sent */
|
|
||||||
}
|
|
||||||
if (extension_length != length) {
|
|
||||||
ssl3_DecodeError(ss); /* send alert */
|
|
||||||
goto loser;
|
|
||||||
}
|
|
||||||
rv = ssl3_HandleClientHelloExtensions(ss, &b, &length);
|
|
||||||
if (rv != SECSuccess) {
|
|
||||||
goto loser; /* malformed */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
desc = handshake_failure;
|
desc = handshake_failure;
|
||||||
|
|
||||||
if (sid != NULL) {
|
if (sid != NULL) {
|
||||||
@ -5422,26 +5404,42 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
|||||||
ssl3_FilterECCipherSuitesByServerCerts(ss);
|
ssl3_FilterECCipherSuitesByServerCerts(ss);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PARANOID
|
||||||
/* Look for a matching cipher suite. */
|
/* Look for a matching cipher suite. */
|
||||||
j = ssl3_config_match_init(ss);
|
j = ssl3_config_match_init(ss);
|
||||||
if (j <= 0) { /* no ciphers are working/supported by PK11 */
|
if (j <= 0) { /* no ciphers are working/supported by PK11 */
|
||||||
errCode = PORT_GetError(); /* error code is already set. */
|
errCode = PORT_GetError(); /* error code is already set. */
|
||||||
goto alert_loser;
|
goto alert_loser;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* If we already have a session for this client, be sure to pick the
|
/* If we already have a session for this client, be sure to pick the
|
||||||
** same cipher suite we picked before.
|
** same cipher suite we picked before.
|
||||||
** This is not a loop, despite appearances.
|
** This is not a loop, despite appearances.
|
||||||
*/
|
*/
|
||||||
if (sid) do {
|
if (sid) do {
|
||||||
ssl3CipherSuiteCfg *suite = ss->cipherSuites;
|
ssl3CipherSuiteCfg *suite = ss->cipherSuites;
|
||||||
|
/* Find the entry for the cipher suite used in the cached session. */
|
||||||
for (j = ssl_V3_SUITES_IMPLEMENTED; j > 0; --j, ++suite) {
|
for (j = ssl_V3_SUITES_IMPLEMENTED; j > 0; --j, ++suite) {
|
||||||
if (suite->cipher_suite == sid->u.ssl3.cipherSuite)
|
if (suite->cipher_suite == sid->u.ssl3.cipherSuite)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!j)
|
PORT_Assert(j > 0);
|
||||||
|
if (j <= 0)
|
||||||
break;
|
break;
|
||||||
|
#ifdef PARANOID
|
||||||
|
/* Double check that the cached cipher suite is still enabled,
|
||||||
|
* implemented, and allowed by policy. Might have been disabled.
|
||||||
|
* The product policy won't change during the process lifetime.
|
||||||
|
* Implemented ("isPresent") shouldn't change for servers.
|
||||||
|
*/
|
||||||
if (!config_match(suite, ss->ssl3.policy, PR_TRUE))
|
if (!config_match(suite, ss->ssl3.policy, PR_TRUE))
|
||||||
break;
|
break;
|
||||||
|
#else
|
||||||
|
if (!suite->enabled)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
/* Double check that the cached cipher suite is in the client's list */
|
||||||
for (i = 0; i < suites.len; i += 2) {
|
for (i = 0; i < suites.len; i += 2) {
|
||||||
if ((suites.data[i] == MSB(suite->cipher_suite)) &&
|
if ((suites.data[i] == MSB(suite->cipher_suite)) &&
|
||||||
(suites.data[i + 1] == LSB(suite->cipher_suite))) {
|
(suites.data[i + 1] == LSB(suite->cipher_suite))) {
|
||||||
@ -5454,6 +5452,37 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
|||||||
}
|
}
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
|
/* START A NEW SESSION */
|
||||||
|
|
||||||
|
/* Handle TLS hello extensions, for SSL3 & TLS,
|
||||||
|
* only if we're not restarting a previous session.
|
||||||
|
*/
|
||||||
|
if (length) {
|
||||||
|
/* Get length of hello extensions */
|
||||||
|
PRInt32 extension_length;
|
||||||
|
extension_length = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
|
||||||
|
if (extension_length < 0) {
|
||||||
|
goto loser; /* alert already sent */
|
||||||
|
}
|
||||||
|
if (extension_length != length) {
|
||||||
|
ssl3_DecodeError(ss); /* send alert */
|
||||||
|
goto loser;
|
||||||
|
}
|
||||||
|
rv = ssl3_HandleClientHelloExtensions(ss, &b, &length);
|
||||||
|
if (rv != SECSuccess) {
|
||||||
|
goto loser; /* malformed */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PARANOID
|
||||||
|
/* Look for a matching cipher suite. */
|
||||||
|
j = ssl3_config_match_init(ss);
|
||||||
|
if (j <= 0) { /* no ciphers are working/supported by PK11 */
|
||||||
|
errCode = PORT_GetError(); /* error code is already set. */
|
||||||
|
goto alert_loser;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Select a cipher suite.
|
/* Select a cipher suite.
|
||||||
** NOTE: This suite selection algorithm should be the same as the one in
|
** NOTE: This suite selection algorithm should be the same as the one in
|
||||||
** ssl3_HandleV2ClientHello().
|
** ssl3_HandleV2ClientHello().
|
||||||
@ -7380,6 +7409,7 @@ xmit_loser:
|
|||||||
sid->u.ssl3.cipherSuite = ss->ssl3.hs.cipher_suite;
|
sid->u.ssl3.cipherSuite = ss->ssl3.hs.cipher_suite;
|
||||||
sid->u.ssl3.compression = ss->ssl3.hs.compression;
|
sid->u.ssl3.compression = ss->ssl3.hs.compression;
|
||||||
sid->u.ssl3.policy = ss->ssl3.policy;
|
sid->u.ssl3.policy = ss->ssl3.policy;
|
||||||
|
sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves;
|
||||||
sid->u.ssl3.exchKeyType = effectiveExchKeyType;
|
sid->u.ssl3.exchKeyType = effectiveExchKeyType;
|
||||||
sid->version = ss->version;
|
sid->version = ss->version;
|
||||||
sid->authAlgorithm = ss->sec.authAlgorithm;
|
sid->authAlgorithm = ss->sec.authAlgorithm;
|
||||||
@ -8002,6 +8032,7 @@ ssl3_InitState(sslSocket *ss)
|
|||||||
ssl3_InitCipherSpec(ss, ss->ssl3.prSpec);
|
ssl3_InitCipherSpec(ss, ss->ssl3.prSpec);
|
||||||
|
|
||||||
ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello;
|
ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello;
|
||||||
|
ss->ssl3.hs.negotiatedECCurves = SSL3_SUPPORTED_CURVES_MASK;
|
||||||
ssl_ReleaseSpecWriteLock(ss);
|
ssl_ReleaseSpecWriteLock(ss);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -40,9 +40,10 @@
|
|||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
/* ECC code moved here from ssl3con.c */
|
/* ECC code moved here from ssl3con.c */
|
||||||
/* $Id: ssl3ecc.c,v 1.6 2006/04/07 06:24:07 nelson%bolyard.com Exp $ */
|
/* $Id: ssl3ecc.c,v 1.7 2006/04/13 23:08:18 nelson%bolyard.com Exp $ */
|
||||||
|
|
||||||
#include "nssrenam.h"
|
#include "nssrenam.h"
|
||||||
|
#include "nss.h"
|
||||||
#include "cert.h"
|
#include "cert.h"
|
||||||
#include "ssl.h"
|
#include "ssl.h"
|
||||||
#include "cryptohi.h" /* for DSAU_ stuff */
|
#include "cryptohi.h" /* for DSAU_ stuff */
|
||||||
@ -75,24 +76,41 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Types and names of elliptic curves used in TLS */
|
/* Types and names of elliptic curves used in TLS */
|
||||||
typedef enum { ec_type_explicitPrime = 1,
|
typedef enum { ec_type_explicitPrime = 1,
|
||||||
ec_type_explicitChar2Curve,
|
ec_type_explicitChar2Curve = 2,
|
||||||
ec_type_named
|
ec_type_named
|
||||||
} ECType;
|
} ECType;
|
||||||
|
|
||||||
typedef enum { ec_noName = 0,
|
typedef enum { ec_noName = 0,
|
||||||
ec_sect163k1, ec_sect163r1, ec_sect163r2,
|
ec_sect163k1 = 1,
|
||||||
ec_sect193r1, ec_sect193r2, ec_sect233k1,
|
ec_sect163r1 = 2,
|
||||||
ec_sect233r1, ec_sect239k1, ec_sect283k1,
|
ec_sect163r2 = 3,
|
||||||
ec_sect283r1, ec_sect409k1, ec_sect409r1,
|
ec_sect193r1 = 4,
|
||||||
ec_sect571k1, ec_sect571r1, ec_secp160k1,
|
ec_sect193r2 = 5,
|
||||||
ec_secp160r1, ec_secp160r2, ec_secp192k1,
|
ec_sect233k1 = 6,
|
||||||
ec_secp192r1, ec_secp224k1, ec_secp224r1,
|
ec_sect233r1 = 7,
|
||||||
ec_secp256k1, ec_secp256r1, ec_secp384r1,
|
ec_sect239k1 = 8,
|
||||||
ec_secp521r1,
|
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
|
ec_pastLastName
|
||||||
} ECName;
|
} ECName;
|
||||||
|
|
||||||
|
|
||||||
#define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName))
|
#define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName))
|
||||||
|
|
||||||
/* Table containing OID tags for elliptic curves named in the
|
/* Table containing OID tags for elliptic curves named in the
|
||||||
@ -127,6 +145,15 @@ static const SECOidTag ecName2OIDTag[] = {
|
|||||||
SEC_OID_SECG_EC_SECP521R1, /* 25 */
|
SEC_OID_SECG_EC_SECP521R1, /* 25 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct ECDHEKeyPairStr {
|
||||||
|
ssl3KeyPair * pair;
|
||||||
|
PRInt32 flag;
|
||||||
|
PRCallOnceType once;
|
||||||
|
} ECDHEKeyPair;
|
||||||
|
|
||||||
|
/* arrays of ECDHE KeyPairs */
|
||||||
|
static ECDHEKeyPair gECDHEKeyPairs[ec_pastLastName];
|
||||||
|
|
||||||
static SECStatus
|
static SECStatus
|
||||||
ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params)
|
ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params)
|
||||||
{
|
{
|
||||||
@ -361,11 +388,79 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
|
|||||||
return SECSuccess;
|
return SECSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* function to clear out the lists */
|
||||||
|
static SECStatus
|
||||||
|
ssl3_ShutdownECDHECurves(void *appData, void *nssData)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
ECDHEKeyPair *keyPair = &gECDHEKeyPairs[0];
|
||||||
|
|
||||||
|
for (i=0; i < ec_pastLastName; i++, keyPair++) {
|
||||||
|
if (keyPair->pair) {
|
||||||
|
ssl3_FreeKeyPair(keyPair->pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memset(gECDHEKeyPairs, 0, sizeof gECDHEKeyPairs);
|
||||||
|
return SECSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PRStatus
|
||||||
|
ssl3_ECRegister(void)
|
||||||
|
{
|
||||||
|
SECStatus rv;
|
||||||
|
rv = NSS_RegisterShutdown(ssl3_ShutdownECDHECurves, gECDHEKeyPairs);
|
||||||
|
return (PRStatus)rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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) \
|
||||||
|
((curveName > ec_noName) && \
|
||||||
|
(curveName < ec_pastLastName) && \
|
||||||
|
((1UL << curveName) & ss->ssl3.hs.negotiatedECCurves) != 0)
|
||||||
|
|
||||||
|
/* CallOnce function, called once for each named curve. */
|
||||||
|
static PRStatus
|
||||||
|
ssl3_CreateECDHEphemeralKeyPair(void * arg)
|
||||||
|
{
|
||||||
|
SECKEYPrivateKey * privKey = NULL;
|
||||||
|
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) {
|
||||||
|
return PR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL);
|
||||||
|
SECITEM_FreeItem(&ecParams, PR_FALSE);
|
||||||
|
|
||||||
|
if (!privKey || !pubKey || !(keyPair = ssl3_NewKeyPair(privKey, pubKey))) {
|
||||||
|
if (privKey) {
|
||||||
|
SECKEY_DestroyPrivateKey(privKey);
|
||||||
|
}
|
||||||
|
if (pubKey) {
|
||||||
|
SECKEY_DestroyPublicKey(pubKey);
|
||||||
|
}
|
||||||
|
ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
|
||||||
|
return PR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gECDHEKeyPairs[ec_curve].pair = keyPair;
|
||||||
|
return PR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates the ephemeral public and private ECDH keys used by
|
* Creates the ephemeral public and private ECDH keys used by
|
||||||
* server in ECDHE_RSA and ECDHE_ECDSA handshakes.
|
* server in ECDHE_RSA and ECDHE_ECDSA handshakes.
|
||||||
* XXX For now, the elliptic curve is hardcoded to NIST P-256.
|
* For now, the elliptic curve is chosen to be the same
|
||||||
|
* strength as the signing certificate (ECC or RSA).
|
||||||
* We need an API to specify the curve. This won't be a real
|
* We need an API to specify the curve. This won't be a real
|
||||||
* issue until we further develop server-side support for ECC
|
* issue until we further develop server-side support for ECC
|
||||||
* cipher suites.
|
* cipher suites.
|
||||||
@ -373,26 +468,73 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
|
|||||||
SECStatus
|
SECStatus
|
||||||
ssl3_CreateECDHEphemeralKeys(sslSocket *ss)
|
ssl3_CreateECDHEphemeralKeys(sslSocket *ss)
|
||||||
{
|
{
|
||||||
SECStatus rv = SECSuccess;
|
SECKEYPublicKey * svrPublicKey = NULL;
|
||||||
SECKEYPrivateKey * privKey;
|
ssl3KeyPair * keyPair = NULL;
|
||||||
SECKEYPublicKey * pubKey;
|
ECName ec_curve = ec_noName;
|
||||||
SECKEYECParams ecParams = { siBuffer, NULL, 0 };
|
|
||||||
|
|
||||||
if (ss->ephemeralECDHKeyPair)
|
/* find the appropriate curve */
|
||||||
ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
|
if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa) {
|
||||||
ss->ephemeralECDHKeyPair = NULL;
|
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)) {
|
||||||
|
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||||
|
return SECFailure;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* RSA is our signing cert */
|
||||||
|
int serverKeyStrengthInBits = 3072; /* default it */
|
||||||
|
|
||||||
if (ecName2params(NULL, ec_secp256r1, &ecParams) == SECFailure)
|
svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_rsa);
|
||||||
return SECFailure;
|
if (!svrPublicKey) {
|
||||||
privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL);
|
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||||
if (!privKey || !pubKey ||
|
return SECFailure;
|
||||||
!(ss->ephemeralECDHKeyPair = ssl3_NewKeyPair(privKey, pubKey))) {
|
}
|
||||||
ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
|
|
||||||
rv = SECFailure;
|
/* 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) {
|
||||||
|
ec_curve = ec_secp160r2;
|
||||||
|
} else if (serverKeyStrengthInBits <= 2048) {
|
||||||
|
ec_curve = ec_secp224r1;
|
||||||
|
} else if (serverKeyStrengthInBits <= 3072) {
|
||||||
|
ec_curve = ec_secp256r1;
|
||||||
|
} else if (serverKeyStrengthInBits <= 7168) {
|
||||||
|
ec_curve = ec_secp384r1;
|
||||||
|
} else {
|
||||||
|
ec_curve = ec_secp521r1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PORT_Free(ecParams.data);
|
/* if there's no global key for this curve, make one. */
|
||||||
return rv;
|
if (gECDHEKeyPairs[ec_curve].pair == NULL) {
|
||||||
|
PRStatus status;
|
||||||
|
|
||||||
|
status = PR_CallOnce(&gECDHEKeyPairs[ec_noName].once, ssl3_ECRegister);
|
||||||
|
if (status != PR_SUCCESS) {
|
||||||
|
return SECFailure;
|
||||||
|
}
|
||||||
|
status = PR_CallOnceWithArg(&gECDHEKeyPairs[ec_curve].once,
|
||||||
|
ssl3_CreateECDHEphemeralKeyPair,
|
||||||
|
(void *)ec_curve);
|
||||||
|
if (status != PR_SUCCESS) {
|
||||||
|
return SECFailure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPair = gECDHEKeyPairs[ec_curve].pair;
|
||||||
|
PORT_Assert(keyPair != NULL);
|
||||||
|
if (!keyPair)
|
||||||
|
return SECFailure;
|
||||||
|
ss->ephemeralECDHKeyPair = ssl3_GetKeyPairRef(keyPair);
|
||||||
|
|
||||||
|
return SECSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
SECStatus
|
SECStatus
|
||||||
@ -418,8 +560,7 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
|||||||
*/
|
*/
|
||||||
ec_params.len = 3;
|
ec_params.len = 3;
|
||||||
ec_params.data = paramBuf;
|
ec_params.data = paramBuf;
|
||||||
rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len,
|
rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length);
|
||||||
&b, &length);
|
|
||||||
if (rv != SECSuccess) {
|
if (rv != SECSuccess) {
|
||||||
goto loser; /* malformed. */
|
goto loser; /* malformed. */
|
||||||
}
|
}
|
||||||
@ -777,6 +918,182 @@ ssl3_FilterECCipherSuitesByServerCerts(sslSocket * ss)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ask: is ANY ECC cipher suite enabled on this socket? */
|
||||||
|
/* Order(N^2). Yuk. Also, this ignores export policy. */
|
||||||
|
PRBool
|
||||||
|
ssl3_IsECCEnabled(sslSocket * ss)
|
||||||
|
{
|
||||||
|
const ssl3CipherSuite * suite;
|
||||||
|
|
||||||
|
for (suite = ecSuites; *suite; ++suite) {
|
||||||
|
PRBool enabled = PR_FALSE;
|
||||||
|
SECStatus rv = ssl3_CipherPrefGet(ss, *suite, &enabled);
|
||||||
|
|
||||||
|
PORT_Assert(rv == SECSuccess); /* else is coding error */
|
||||||
|
if (rv == SECSuccess && enabled)
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BE(n) 0, n
|
||||||
|
|
||||||
|
/* Prefabricated TLS client hello extension, Elliptic Curves List,
|
||||||
|
* offers curves 1-25.
|
||||||
|
*/
|
||||||
|
static const PRUint8 EClist[55] = {
|
||||||
|
BE(10), /* Extension type */
|
||||||
|
BE(51), /* octets that follow (25 pairs + 1 octet) */
|
||||||
|
50, /* octets that follow (25 pairs) */
|
||||||
|
BE( 1), BE( 2), BE( 3), BE( 4), BE( 5), BE( 6), BE( 7),
|
||||||
|
BE( 8), BE( 9), BE(10), BE(11), BE(12), BE(13), BE(14), BE(15),
|
||||||
|
BE(16), BE(17), BE(18), BE(19), BE(20), BE(21), BE(22), BE(23),
|
||||||
|
BE(24), BE(25)
|
||||||
|
};
|
||||||
|
|
||||||
|
static const PRUint8 ECPtFmt[6] = {
|
||||||
|
BE(11), /* Extension type */
|
||||||
|
BE( 2), /* octets that follow */
|
||||||
|
1, /* octets that follow */
|
||||||
|
0 /* uncompressed type only */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Send our "canned" (precompiled) Supported Elliptic Curves extension,
|
||||||
|
* which says that we support all TLS-defined named curves.
|
||||||
|
*/
|
||||||
|
PRInt32
|
||||||
|
ssl3_SendSupportedEllipticCurvesExtension(
|
||||||
|
sslSocket * ss,
|
||||||
|
PRBool append,
|
||||||
|
PRUint32 maxBytes)
|
||||||
|
{
|
||||||
|
if (!ss || !ssl3_IsECCEnabled(ss))
|
||||||
|
return 0;
|
||||||
|
if (append && maxBytes >= (sizeof EClist)) {
|
||||||
|
SECStatus rv = ssl3_AppendHandshake(ss, EClist, (sizeof EClist));
|
||||||
|
}
|
||||||
|
return (sizeof EClist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send our "canned" (precompiled) Supported Point Formats extension,
|
||||||
|
* which says that we only support uncompressed points.
|
||||||
|
*/
|
||||||
|
PRInt32
|
||||||
|
ssl3_SendSupportedPointFormatsExtension(
|
||||||
|
sslSocket * ss,
|
||||||
|
PRBool append,
|
||||||
|
PRUint32 maxBytes)
|
||||||
|
{
|
||||||
|
if (!ss || !ssl3_IsECCEnabled(ss))
|
||||||
|
return 0;
|
||||||
|
if (append && maxBytes >= (sizeof ECPtFmt)) {
|
||||||
|
SECStatus rv = ssl3_AppendHandshake(ss, ECPtFmt, (sizeof ECPtFmt));
|
||||||
|
}
|
||||||
|
return (sizeof ECPtFmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just make sure that the remote client supports uncompressed points,
|
||||||
|
* Since that is all we support. Disable ECC cipher suites if it doesn't.
|
||||||
|
*/
|
||||||
|
static SECStatus
|
||||||
|
ssl3_HandleSupportedPointFormatsExtension(sslSocket * ss, PRUint16 ex_type,
|
||||||
|
SECItem *data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (data->len < 2 || data->len > 255 || !data->data ||
|
||||||
|
data->len != (unsigned int)data->data[0] + 1) {
|
||||||
|
/* malformed */
|
||||||
|
goto loser;
|
||||||
|
}
|
||||||
|
for (i = data->len; --i > 0; ) {
|
||||||
|
if (data->data[i] == 0) {
|
||||||
|
/* indicate that we should send a reply */
|
||||||
|
SECStatus rv;
|
||||||
|
rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
|
||||||
|
&ssl3_SendSupportedPointFormatsExtension);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loser:
|
||||||
|
/* evil client doesn't support uncompressed */
|
||||||
|
ssl3_DisableECCSuites(ss, ecSuites);
|
||||||
|
return SECFailure;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define SSL3_GET_SERVER_PUBLICKEY(sock, type) \
|
||||||
|
(ss->serverCerts[type].serverKeyPair ? \
|
||||||
|
ss->serverCerts[type].serverKeyPair->pubKey : NULL)
|
||||||
|
|
||||||
|
/* Extract the TLS curve name for the public key in our EC server cert. */
|
||||||
|
ECName ssl3_GetSvrCertCurveName(sslSocket *ss)
|
||||||
|
{
|
||||||
|
SECKEYPublicKey *srvPublicKey;
|
||||||
|
ECName ec_curve = ec_noName;
|
||||||
|
|
||||||
|
srvPublicKey = SSL3_GET_SERVER_PUBLICKEY(ss, kt_ecdh);
|
||||||
|
if (srvPublicKey) {
|
||||||
|
ec_curve = params2ecName(&srvPublicKey->u.ec.DEREncodedParams);
|
||||||
|
}
|
||||||
|
return ec_curve;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that the curve in our server cert is one of the ones suppored
|
||||||
|
* by the remote client, and disable all ECC cipher suites if not.
|
||||||
|
*/
|
||||||
|
static SECStatus
|
||||||
|
ssl3_HandleSupportedEllipticCurvesExtension(sslSocket * ss, PRUint16 ex_type,
|
||||||
|
SECItem *data)
|
||||||
|
{
|
||||||
|
PRInt32 list_len;
|
||||||
|
PRUint32 peerCurves = 0;
|
||||||
|
PRUint32 mutualCurves = 0;
|
||||||
|
PRUint16 svrCertCurveName;
|
||||||
|
|
||||||
|
if (!data->data || data->len < 4 || data->len > 65535)
|
||||||
|
goto loser;
|
||||||
|
/* get the length of elliptic_curve_list */
|
||||||
|
list_len = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
|
||||||
|
if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
|
||||||
|
/* malformed */
|
||||||
|
goto loser;
|
||||||
|
}
|
||||||
|
/* build bit vector of peer's supported curve names */
|
||||||
|
while (data->len) {
|
||||||
|
PRInt32 curve_name =
|
||||||
|
ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
|
||||||
|
if (curve_name > ec_noName && curve_name < ec_pastLastName) {
|
||||||
|
peerCurves |= (1U << curve_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* What curves do we support in common? */
|
||||||
|
mutualCurves = ss->ssl3.hs.negotiatedECCurves &= peerCurves;
|
||||||
|
if (!mutualCurves) { /* no mutually supported EC Curves */
|
||||||
|
goto loser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if our ECC cert doesn't use one of these supported curves,
|
||||||
|
* disable ECC cipher suites that require an ECC cert.
|
||||||
|
*/
|
||||||
|
svrCertCurveName = ssl3_GetSvrCertCurveName(ss);
|
||||||
|
if (svrCertCurveName != ec_noName &&
|
||||||
|
(mutualCurves & (1U << svrCertCurveName)) != 0) {
|
||||||
|
return SECSuccess;
|
||||||
|
}
|
||||||
|
/* Our EC cert doesn't contain a mutually supported curve.
|
||||||
|
* Disable all ECC cipher suites that require an EC cert
|
||||||
|
*/
|
||||||
|
ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
|
||||||
|
ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
|
||||||
|
return SECFailure;
|
||||||
|
|
||||||
|
loser:
|
||||||
|
/* no common curve supported */
|
||||||
|
ssl3_DisableECCSuites(ss, ecSuites);
|
||||||
|
return SECFailure;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* NSS_ENABLE_ECC */
|
#endif /* NSS_ENABLE_ECC */
|
||||||
|
|
||||||
/* Format an SNI extension, using the name from the socket's URL,
|
/* Format an SNI extension, using the name from the socket's URL,
|
||||||
@ -835,7 +1152,10 @@ ssl3_HandleServerNameIndicationExtension(sslSocket * ss, PRUint16 ex_type,
|
|||||||
*/
|
*/
|
||||||
static const ssl3HelloExtensionHandler handlers[] = {
|
static const ssl3HelloExtensionHandler handlers[] = {
|
||||||
{ 0, &ssl3_HandleServerNameIndicationExtension },
|
{ 0, &ssl3_HandleServerNameIndicationExtension },
|
||||||
/* ECC handlers will be added here */
|
#ifdef NSS_ENABLE_ECC
|
||||||
|
{ 10, &ssl3_HandleSupportedEllipticCurvesExtension },
|
||||||
|
{ 11, &ssl3_HandleSupportedPointFormatsExtension },
|
||||||
|
#endif
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -847,14 +1167,18 @@ static const ssl3HelloExtensionHandler handlers[] = {
|
|||||||
static const
|
static const
|
||||||
ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSION_SENDERS] = {
|
ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSION_SENDERS] = {
|
||||||
{ 0, &ssl3_SendServerNameIndicationExtension },
|
{ 0, &ssl3_SendServerNameIndicationExtension },
|
||||||
/* ECC senders will be added here */
|
#ifdef NSS_ENABLE_ECC
|
||||||
|
{ 10, &ssl3_SendSupportedEllipticCurvesExtension },
|
||||||
|
{ 11, &ssl3_SendSupportedPointFormatsExtension },
|
||||||
|
#else
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* go through hello extensions in buffer "b".
|
/* go through hello extensions in buffer "b".
|
||||||
* For each one, find the extension handler in the table above, and
|
* For each one, find the extension handler in the table above, and
|
||||||
* if present, invoke that handler.
|
* if present, invoke that handler.
|
||||||
* ignore any externsions with unknown extensions types.
|
* ignore any extensions with unknown extension types.
|
||||||
*/
|
*/
|
||||||
SECStatus
|
SECStatus
|
||||||
ssl3_HandleClientHelloExtensions(sslSocket *ss,
|
ssl3_HandleClientHelloExtensions(sslSocket *ss,
|
||||||
@ -943,3 +1267,4 @@ ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
|
|||||||
}
|
}
|
||||||
return total_exten_len;
|
return total_exten_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
/* $Id: sslimpl.h,v 1.48 2006/04/07 06:24:07 nelson%bolyard.com Exp $ */
|
/* $Id: sslimpl.h,v 1.49 2006/04/13 23:08:18 nelson%bolyard.com Exp $ */
|
||||||
|
|
||||||
#ifndef __sslimpl_h_
|
#ifndef __sslimpl_h_
|
||||||
#define __sslimpl_h_
|
#define __sslimpl_h_
|
||||||
@ -179,6 +179,9 @@ typedef enum { SSLAppOpRead = 0,
|
|||||||
|
|
||||||
#define NUM_MIXERS 9
|
#define NUM_MIXERS 9
|
||||||
|
|
||||||
|
/* Mask of the 25 named curves we support. */
|
||||||
|
#define SSL3_SUPPORTED_CURVES_MASK 0x3fffffe
|
||||||
|
|
||||||
#ifndef BPB
|
#ifndef BPB
|
||||||
#define BPB 8 /* Bits Per Byte */
|
#define BPB 8 /* Bits Per Byte */
|
||||||
#endif
|
#endif
|
||||||
@ -586,6 +589,9 @@ struct sslSessionIDStr {
|
|||||||
SSL3KEAType exchKeyType;
|
SSL3KEAType exchKeyType;
|
||||||
/* key type used in exchange algorithm,
|
/* key type used in exchange algorithm,
|
||||||
* and to wrap the sym wrapping key. */
|
* and to wrap the sym wrapping key. */
|
||||||
|
#ifdef NSS_ENABLE_ECC
|
||||||
|
PRUint32 negotiatedECCurves;
|
||||||
|
#endif /* NSS_ENABLE_ECC */
|
||||||
|
|
||||||
/* The following values are NOT restored from the server's on-disk
|
/* The following values are NOT restored from the server's on-disk
|
||||||
* session cache, but are restored from the client's cache.
|
* session cache, but are restored from the client's cache.
|
||||||
@ -711,6 +717,9 @@ const ssl3CipherSuiteDef *suite_def;
|
|||||||
PRBool usedStepDownKey; /* we did a server key exchange. */
|
PRBool usedStepDownKey; /* we did a server key exchange. */
|
||||||
sslBuffer msgState; /* current state for handshake messages*/
|
sslBuffer msgState; /* current state for handshake messages*/
|
||||||
/* protected by recvBufLock */
|
/* protected by recvBufLock */
|
||||||
|
#ifdef NSS_ENABLE_ECC
|
||||||
|
PRUint32 negotiatedECCurves; /* bit mask */
|
||||||
|
#endif /* NSS_ENABLE_ECC */
|
||||||
} SSL3HandshakeState;
|
} SSL3HandshakeState;
|
||||||
|
|
||||||
|
|
||||||
@ -1260,7 +1269,8 @@ extern SECStatus ssl3_CreateRSAStepDownKeys(sslSocket *ss);
|
|||||||
|
|
||||||
#ifdef NSS_ENABLE_ECC
|
#ifdef NSS_ENABLE_ECC
|
||||||
extern SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss);
|
extern SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss);
|
||||||
extern void ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss);
|
extern void ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss);
|
||||||
|
extern PRBool ssl3_IsECCEnabled(sslSocket *ss);
|
||||||
#endif /* NSS_ENABLE_ECC */
|
#endif /* NSS_ENABLE_ECC */
|
||||||
|
|
||||||
extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);
|
extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);
|
||||||
|
Loading…
Reference in New Issue
Block a user