In particular the NSS_USE_ALG_IN_SSL_KX flag can be specified to allow a specific curve for TLS negotiation. This will affect the advertized curves as well. --- lib/ssl/ssl3ecc.c | 116 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 42 deletions(-)
diff --git a/lib/ssl/ssl3ecc.c b/lib/ssl/ssl3ecc.c index 37743a6..3feb41c 100644 --- a/lib/ssl/ssl3ecc.c +++ b/lib/ssl/ssl3ecc.c @@ -161,6 +161,7 @@ SECStatus ssl3_ECName2Params(PLArenaPool * arena, ECName curve, SECKEYECParams * params) { SECOidData *oidData = NULL; + PRUint32 policyFlags = 0; if ((curve <= ec_noName) || (curve >= ec_pastLastName) || ((oidData = SECOID_FindOIDByTag(ecName2OIDTag[curve])) == NULL)) { @@ -168,6 +169,12 @@ ssl3_ECName2Params(PLArenaPool * arena, ECName curve, SECKEYECParams * params) return SECFailure; } + if (NSS_GetAlgorithmPolicy(ecName2OIDTag[curve], &policyFlags) == SECFailure || + !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + return SECFailure; + } + SECITEM_AllocItem(arena, params, (2 + oidData->oid.len)); /* * params->data needs to contain the ASN encoding of an object ID (OID) @@ -186,6 +193,7 @@ params2ecName(SECKEYECParams * params) { SECItem oid = { siBuffer, NULL, 0}; SECOidData *oidData = NULL; + PRUint32 policyFlags = 0; ECName i; /* @@ -198,8 +206,12 @@ params2ecName(SECKEYECParams * params) oid.data = params->data + 2; if ((oidData = SECOID_FindOID(&oid)) == NULL) return ec_noName; for (i = ec_noName + 1; i < ec_pastLastName; i++) { - if (ecName2OIDTag[i] == oidData->offset) - return i; + if (ecName2OIDTag[i] == oidData->offset) { + if (NSS_GetAlgorithmPolicy(oidData->offset, &policyFlags) == SECSuccess && + (policyFlags & NSS_USE_ALG_IN_SSL_KX)) { + return i; + } + } } return ec_noName; @@ -1034,29 +1046,6 @@ ssl3_IsECCEnabled(sslSocket * ss) #define BE(n) 0, n -/* Prefabricated TLS client hello extension, Elliptic Curves List, - * offers only 3 curves, the Suite B curves, 23-25 - */ -static const PRUint8 suiteBECList[12] = { - BE(10), /* Extension type */ - BE( 8), /* octets that follow ( 3 pairs + 1 length pair) */ - BE( 6), /* octets that follow ( 3 pairs) */ - BE(23), BE(24), BE(25) -}; - -/* Prefabricated TLS client hello extension, Elliptic Curves List, - * offers curves 1-25. - */ -static const PRUint8 tlsECList[56] = { - BE(10), /* Extension type */ - BE(52), /* octets that follow (25 pairs + 1 length pair) */ - BE(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 */ @@ -1088,6 +1077,13 @@ ssl3_SuiteBOnly(sslSocket *ss) return PR_FALSE; } +#define APPEND_CURVE(CURVE_ID) \ + if (NSS_GetAlgorithmPolicy(ecName2OIDTag[CURVE_ID], &policy) == SECSuccess && \ + (policy & NSS_USE_ALG_IN_SSL_KX)) { \ + enabledCurves[pos++] = 0; \ + enabledCurves[pos++] = CURVE_ID; \ + } + /* Send our "canned" (precompiled) Supported Elliptic Curves extension, * which says that we support all TLS-defined named curves. */ @@ -1097,40 +1093,76 @@ ssl3_SendSupportedCurvesXtn( PRBool append, PRUint32 maxBytes) { - PRInt32 ecListSize = 0; - const PRUint8 *ecList = NULL; + unsigned char enabledCurves[64]; + PRUint32 policy; + unsigned pos = 0; + PRInt32 extension_length; + unsigned i; if (!ss || !ssl3_IsECCEnabled(ss)) return 0; if (ssl3_SuiteBOnly(ss)) { - ecListSize = sizeof suiteBECList; - ecList = suiteBECList; + APPEND_CURVE(23); + APPEND_CURVE(24); + APPEND_CURVE(25); } else { - ecListSize = sizeof tlsECList; - ecList = tlsECList; + for (i=1;i<=25;i++) { + APPEND_CURVE(i); + } } - - if (append && maxBytes >= ecListSize) { - SECStatus rv = ssl3_AppendHandshake(ss, ecList, ecListSize); + + extension_length = + 2 /* extension type */ + + 2 /* extension length */ + + 2 /* elliptic curves length */ + + pos; + + if (append && maxBytes >= extension_length) { + SECStatus rv; + rv = ssl3_AppendHandshakeNumber(ss, ssl_elliptic_curves_xtn, 2); if (rv != SECSuccess) - return -1; - if (!ss->sec.isServer) { - TLSExtensionData *xtnData = &ss->xtnData; - xtnData->advertised[xtnData->numAdvertised++] = + goto loser; + rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendHandshakeVariable(ss, enabledCurves, + pos, 2); + if (rv != SECSuccess) + goto loser; + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = ssl_elliptic_curves_xtn; - } + } else if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; } - return ecListSize; + + return extension_length; +loser: + return -1; } PRUint32 ssl3_GetSupportedECCurveMask(sslSocket *ss) { + unsigned i; + PRUint32 curves = 0; + PRUint32 policyFlags = 0; + + PORT_Assert(ec_pastLastName <= 31); + for (i = ec_noName + 1; i < ec_pastLastName; i++) { + if (NSS_GetAlgorithmPolicy(ecName2OIDTag[i], &policyFlags) == SECFailure || + !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) { + continue; + } + curves |= (1U << i); + } + if (ssl3_SuiteBOnly(ss)) { - return SSL3_SUITE_B_SUPPORTED_CURVES_MASK; + return (curves & SSL3_SUITE_B_SUPPORTED_CURVES_MASK); } - return SSL3_ALL_SUPPORTED_CURVES_MASK; + + return curves; } /* Send our "canned" (precompiled) Supported Point Formats extension, -- 1.9.0 -- dev-tech-crypto mailing list dev-tech-crypto@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-tech-crypto