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:
nelson%bolyard.com 2006-04-13 23:08:18 +00:00
parent af83510020
commit c4fb4fa280
3 changed files with 423 additions and 57 deletions

View File

@ -39,7 +39,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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 "cert.h"
@ -5377,24 +5377,6 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
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;
if (sid != NULL) {
@ -5422,26 +5404,42 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
ssl3_FilterECCipherSuitesByServerCerts(ss);
#endif
#ifdef 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
/* If we already have a session for this client, be sure to pick the
** same cipher suite we picked before.
** This is not a loop, despite appearances.
*/
if (sid) do {
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) {
if (suite->cipher_suite == sid->u.ssl3.cipherSuite)
break;
}
if (!j)
PORT_Assert(j > 0);
if (j <= 0)
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))
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) {
if ((suites.data[i] == MSB(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);
/* 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.
** NOTE: This suite selection algorithm should be the same as the one in
** ssl3_HandleV2ClientHello().
@ -7380,6 +7409,7 @@ xmit_loser:
sid->u.ssl3.cipherSuite = ss->ssl3.hs.cipher_suite;
sid->u.ssl3.compression = ss->ssl3.hs.compression;
sid->u.ssl3.policy = ss->ssl3.policy;
sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves;
sid->u.ssl3.exchKeyType = effectiveExchKeyType;
sid->version = ss->version;
sid->authAlgorithm = ss->sec.authAlgorithm;
@ -8002,6 +8032,7 @@ ssl3_InitState(sslSocket *ss)
ssl3_InitCipherSpec(ss, ss->ssl3.prSpec);
ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello;
ss->ssl3.hs.negotiatedECCurves = SSL3_SUPPORTED_CURVES_MASK;
ssl_ReleaseSpecWriteLock(ss);
/*

View File

@ -40,9 +40,10 @@
* ***** END LICENSE BLOCK ***** */
/* 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 "nss.h"
#include "cert.h"
#include "ssl.h"
#include "cryptohi.h" /* for DSAU_ stuff */
@ -76,23 +77,40 @@
/* Types and names of elliptic curves used in TLS */
typedef enum { ec_type_explicitPrime = 1,
ec_type_explicitChar2Curve,
ec_type_explicitChar2Curve = 2,
ec_type_named
} ECType;
typedef enum { ec_noName = 0,
ec_sect163k1, ec_sect163r1, ec_sect163r2,
ec_sect193r1, ec_sect193r2, ec_sect233k1,
ec_sect233r1, ec_sect239k1, ec_sect283k1,
ec_sect283r1, ec_sect409k1, ec_sect409r1,
ec_sect571k1, ec_sect571r1, ec_secp160k1,
ec_secp160r1, ec_secp160r2, ec_secp192k1,
ec_secp192r1, ec_secp224k1, ec_secp224r1,
ec_secp256k1, ec_secp256r1, ec_secp384r1,
ec_secp521r1,
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;
#define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName))
/* Table containing OID tags for elliptic curves named in the
@ -127,6 +145,15 @@ static const SECOidTag ecName2OIDTag[] = {
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
ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params)
{
@ -361,11 +388,79 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
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
* 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
* issue until we further develop server-side support for ECC
* cipher suites.
@ -373,26 +468,73 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
SECStatus
ssl3_CreateECDHEphemeralKeys(sslSocket *ss)
{
SECStatus rv = SECSuccess;
SECKEYPrivateKey * privKey;
SECKEYPublicKey * pubKey;
SECKEYECParams ecParams = { siBuffer, NULL, 0 };
SECKEYPublicKey * svrPublicKey = NULL;
ssl3KeyPair * keyPair = NULL;
ECName ec_curve = ec_noName;
if (ss->ephemeralECDHKeyPair)
ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
ss->ephemeralECDHKeyPair = NULL;
if (ecName2params(NULL, ec_secp256r1, &ecParams) == SECFailure)
/* find the appropriate curve */
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)) {
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
return SECFailure;
}
} else {
/* RSA is our signing cert */
int serverKeyStrengthInBits = 3072; /* default it */
svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_rsa);
if (!svrPublicKey) {
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
return SECFailure;
privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL);
if (!privKey || !pubKey ||
!(ss->ephemeralECDHKeyPair = ssl3_NewKeyPair(privKey, pubKey))) {
ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
rv = SECFailure;
}
PORT_Free(ecParams.data);
return rv;
/* 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;
}
}
/* if there's no global key for this curve, make one. */
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
@ -418,8 +560,7 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
*/
ec_params.len = 3;
ec_params.data = paramBuf;
rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len,
&b, &length);
rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length);
if (rv != SECSuccess) {
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 */
/* 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[] = {
{ 0, &ssl3_HandleServerNameIndicationExtension },
/* ECC handlers will be added here */
#ifdef NSS_ENABLE_ECC
{ 10, &ssl3_HandleSupportedEllipticCurvesExtension },
{ 11, &ssl3_HandleSupportedPointFormatsExtension },
#endif
{ -1, NULL }
};
@ -847,14 +1167,18 @@ static const ssl3HelloExtensionHandler handlers[] = {
static const
ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSION_SENDERS] = {
{ 0, &ssl3_SendServerNameIndicationExtension },
/* ECC senders will be added here */
#ifdef NSS_ENABLE_ECC
{ 10, &ssl3_SendSupportedEllipticCurvesExtension },
{ 11, &ssl3_SendSupportedPointFormatsExtension },
#else
{ -1, NULL }
#endif
};
/* go through hello extensions in buffer "b".
* For each one, find the extension handler in the table above, and
* if present, invoke that handler.
* ignore any externsions with unknown extensions types.
* ignore any extensions with unknown extension types.
*/
SECStatus
ssl3_HandleClientHelloExtensions(sslSocket *ss,
@ -943,3 +1267,4 @@ ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
}
return total_exten_len;
}

View File

@ -39,7 +39,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** 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_
#define __sslimpl_h_
@ -179,6 +179,9 @@ typedef enum { SSLAppOpRead = 0,
#define NUM_MIXERS 9
/* Mask of the 25 named curves we support. */
#define SSL3_SUPPORTED_CURVES_MASK 0x3fffffe
#ifndef BPB
#define BPB 8 /* Bits Per Byte */
#endif
@ -586,6 +589,9 @@ struct sslSessionIDStr {
SSL3KEAType exchKeyType;
/* key type used in exchange algorithm,
* 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
* 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. */
sslBuffer msgState; /* current state for handshake messages*/
/* protected by recvBufLock */
#ifdef NSS_ENABLE_ECC
PRUint32 negotiatedECCurves; /* bit mask */
#endif /* NSS_ENABLE_ECC */
} SSL3HandshakeState;
@ -1261,6 +1270,7 @@ extern SECStatus ssl3_CreateRSAStepDownKeys(sslSocket *ss);
#ifdef NSS_ENABLE_ECC
extern SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss);
extern void ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss);
extern PRBool ssl3_IsECCEnabled(sslSocket *ss);
#endif /* NSS_ENABLE_ECC */
extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);