Moving TLS 1.3 version negotiation into extension.
Change-Id: I73f9fd64b46f26978b897409d817b34ec9d93afd Reviewed-on: https://boringssl-review.googlesource.com/11080 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
committed by
CQ bot account: commit-bot@chromium.org
parent
2fb2ffb660
commit
fdd10998e1
@@ -562,7 +562,7 @@ OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl);
|
||||
#define DTLS1_VERSION 0xfeff
|
||||
#define DTLS1_2_VERSION 0xfefd
|
||||
|
||||
#define TLS1_3_DRAFT_VERSION 14
|
||||
#define TLS1_3_DRAFT_VERSION 0x7f0e
|
||||
|
||||
/* SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to
|
||||
* |version|. If |version| is zero, the default minimum version is used. It
|
||||
|
||||
@@ -209,16 +209,9 @@ extern "C" {
|
||||
#define TLSEXT_TYPE_key_share 40
|
||||
#define TLSEXT_TYPE_pre_shared_key 41
|
||||
#define TLSEXT_TYPE_early_data 42
|
||||
#define TLSEXT_TYPE_supported_versions 43
|
||||
#define TLSEXT_TYPE_cookie 44
|
||||
|
||||
/* TLSEXT_TYPE_draft_version is the extension used to advertise the TLS 1.3
|
||||
* draft implemented.
|
||||
*
|
||||
* See
|
||||
* https://github.com/tlswg/tls13-spec/wiki/Implementations#version-negotiation
|
||||
*/
|
||||
#define TLSEXT_TYPE_draft_version 0xff02
|
||||
|
||||
/* ExtensionType value from RFC5746 */
|
||||
#define TLSEXT_TYPE_renegotiate 0xff01
|
||||
|
||||
|
||||
@@ -731,6 +731,10 @@ static int ssl3_send_client_hello(SSL *ssl) {
|
||||
* key exchange, the ClientHello version is checked in the premaster secret.
|
||||
* Some servers fail when this value changes. */
|
||||
ssl->client_version = ssl->version;
|
||||
|
||||
if (max_version >= TLS1_3_VERSION) {
|
||||
ssl->client_version = ssl->method->version_to_wire(TLS1_2_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the configured session has expired or was created at a disabled
|
||||
|
||||
+68
-26
@@ -564,38 +564,75 @@ static int negotiate_version(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For TLS versions which use ClientHello.version, convert it to a version we
|
||||
* are aware of. */
|
||||
uint16_t version = 0;
|
||||
if (SSL_is_dtls(ssl)) {
|
||||
if (client_hello->version <= DTLS1_2_VERSION) {
|
||||
version = TLS1_2_VERSION;
|
||||
} else if (client_hello->version <= DTLS1_VERSION) {
|
||||
version = TLS1_1_VERSION;
|
||||
/* Check supported_versions extension if it is present. */
|
||||
CBS supported_versions;
|
||||
if (ssl_early_callback_get_extension(client_hello, &supported_versions,
|
||||
TLSEXT_TYPE_supported_versions)) {
|
||||
CBS versions;
|
||||
if (!CBS_get_u8_length_prefixed(&supported_versions, &versions) ||
|
||||
CBS_len(&supported_versions) != 0 ||
|
||||
CBS_len(&versions) == 0) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
|
||||
*out_alert = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int found_version = 0;
|
||||
while (CBS_len(&versions) != 0) {
|
||||
uint16_t ext_version;
|
||||
if (!CBS_get_u16(&versions, &ext_version)) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
|
||||
*out_alert = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if (!ssl->method->version_from_wire(&ext_version, ext_version)) {
|
||||
continue;
|
||||
}
|
||||
if (min_version <= ext_version &&
|
||||
ext_version <= max_version) {
|
||||
version = ext_version;
|
||||
found_version = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_version) {
|
||||
goto unsupported_protocol;
|
||||
}
|
||||
} else {
|
||||
if (client_hello->version >= TLS1_3_VERSION) {
|
||||
version = TLS1_3_VERSION;
|
||||
} else if (client_hello->version >= TLS1_2_VERSION) {
|
||||
version = TLS1_2_VERSION;
|
||||
} else if (client_hello->version >= TLS1_1_VERSION) {
|
||||
version = TLS1_1_VERSION;
|
||||
} else if (client_hello->version >= TLS1_VERSION) {
|
||||
version = TLS1_VERSION;
|
||||
} else if (client_hello->version >= SSL3_VERSION) {
|
||||
version = SSL3_VERSION;
|
||||
/* Process ClientHello.version instead. Note that versions beyond (D)TLS 1.2
|
||||
* do not use this mechanism. */
|
||||
if (SSL_is_dtls(ssl)) {
|
||||
if (client_hello->version <= DTLS1_2_VERSION) {
|
||||
version = TLS1_2_VERSION;
|
||||
} else if (client_hello->version <= DTLS1_VERSION) {
|
||||
version = TLS1_1_VERSION;
|
||||
} else {
|
||||
goto unsupported_protocol;
|
||||
}
|
||||
} else {
|
||||
if (client_hello->version >= TLS1_2_VERSION) {
|
||||
version = TLS1_2_VERSION;
|
||||
} else if (client_hello->version >= TLS1_1_VERSION) {
|
||||
version = TLS1_1_VERSION;
|
||||
} else if (client_hello->version >= TLS1_VERSION) {
|
||||
version = TLS1_VERSION;
|
||||
} else if (client_hello->version >= SSL3_VERSION) {
|
||||
version = SSL3_VERSION;
|
||||
} else {
|
||||
goto unsupported_protocol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply our minimum and maximum version. */
|
||||
if (version > max_version) {
|
||||
version = max_version;
|
||||
}
|
||||
/* Apply our minimum and maximum version. */
|
||||
if (version > max_version) {
|
||||
version = max_version;
|
||||
}
|
||||
|
||||
if (version < min_version) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
|
||||
*out_alert = SSL_AD_PROTOCOL_VERSION;
|
||||
return 0;
|
||||
if (version < min_version) {
|
||||
goto unsupported_protocol;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle FALLBACK_SCSV. */
|
||||
@@ -617,6 +654,11 @@ static int negotiate_version(
|
||||
ssl->s3->have_version = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
unsupported_protocol:
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
|
||||
*out_alert = SSL_AD_PROTOCOL_VERSION;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssl3_get_client_hello(SSL *ssl) {
|
||||
|
||||
@@ -543,12 +543,6 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
|
||||
goto err;
|
||||
}
|
||||
/* Only support SSLv3/TLS and DTLS. */
|
||||
if ((ssl_version >> 8) != SSL3_VERSION_MAJOR &&
|
||||
(ssl_version >> 8) != (DTLS1_VERSION >> 8)) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION);
|
||||
goto err;
|
||||
}
|
||||
ret->ssl_version = ssl_version;
|
||||
|
||||
CBS cipher;
|
||||
|
||||
+19
-3
@@ -951,6 +951,10 @@ static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (version == TLS1_3_VERSION) {
|
||||
version = TLS1_3_DRAFT_VERSION;
|
||||
}
|
||||
|
||||
return method->version_from_wire(out, version);
|
||||
}
|
||||
|
||||
@@ -965,6 +969,10 @@ static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (version == TLS1_3_VERSION) {
|
||||
version = TLS1_3_DRAFT_VERSION;
|
||||
}
|
||||
|
||||
return method->version_from_wire(out, version);
|
||||
}
|
||||
|
||||
@@ -2109,7 +2117,8 @@ void ssl_update_cache(SSL *ssl, int mode) {
|
||||
|
||||
static const char *ssl_get_version(int version) {
|
||||
switch (version) {
|
||||
case TLS1_3_VERSION:
|
||||
/* Report TLS 1.3 draft version as TLS 1.3 in the public API. */
|
||||
case TLS1_3_DRAFT_VERSION:
|
||||
return "TLSv1.3";
|
||||
|
||||
case TLS1_2_VERSION:
|
||||
@@ -2271,7 +2280,14 @@ int SSL_get_shutdown(const SSL *ssl) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SSL_version(const SSL *ssl) { return ssl->version; }
|
||||
int SSL_version(const SSL *ssl) {
|
||||
/* Report TLS 1.3 draft version as TLS 1.3 in the public API. */
|
||||
if (ssl->version == TLS1_3_DRAFT_VERSION) {
|
||||
return TLS1_3_VERSION;
|
||||
}
|
||||
|
||||
return ssl->version;
|
||||
}
|
||||
|
||||
SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) { return ssl->ctx; }
|
||||
|
||||
@@ -2962,7 +2978,7 @@ void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type,
|
||||
version = 0;
|
||||
break;
|
||||
default:
|
||||
version = ssl->version;
|
||||
version = SSL_version(ssl);
|
||||
}
|
||||
|
||||
ssl->msg_callback(is_write, version, content_type, buf, len, ssl,
|
||||
|
||||
+43
-29
@@ -1966,27 +1966,6 @@ static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) {
|
||||
return ext_ec_point_add_extension(ssl, out);
|
||||
}
|
||||
|
||||
|
||||
/* Draft Version Extension */
|
||||
|
||||
static int ext_draft_version_add_clienthello(SSL *ssl, CBB *out) {
|
||||
uint16_t min_version, max_version;
|
||||
if (!ssl_get_version_range(ssl, &min_version, &max_version) ||
|
||||
max_version < TLS1_3_VERSION) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CBB contents;
|
||||
if (!CBB_add_u16(out, TLSEXT_TYPE_draft_version) ||
|
||||
!CBB_add_u16_length_prefixed(out, &contents) ||
|
||||
!CBB_add_u16(&contents, TLS1_3_DRAFT_VERSION)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CBB_flush(out);
|
||||
}
|
||||
|
||||
|
||||
/* Pre Shared Key
|
||||
*
|
||||
* https://tools.ietf.org/html/draft-ietf-tls-tls13-14 */
|
||||
@@ -2279,6 +2258,41 @@ int ssl_ext_key_share_add_serverhello(SSL *ssl, CBB *out) {
|
||||
}
|
||||
|
||||
|
||||
/* Supported Versions
|
||||
*
|
||||
* https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.1 */
|
||||
|
||||
static int ext_supported_versions_add_clienthello(SSL *ssl, CBB *out) {
|
||||
uint16_t min_version, max_version;
|
||||
if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max_version <= TLS1_2_VERSION) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CBB contents, versions;
|
||||
if (!CBB_add_u16(out, TLSEXT_TYPE_supported_versions) ||
|
||||
!CBB_add_u16_length_prefixed(out, &contents) ||
|
||||
!CBB_add_u8_length_prefixed(&contents, &versions)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint16_t version = max_version; version >= min_version; version--) {
|
||||
if (!CBB_add_u16(&versions, ssl->method->version_to_wire(version))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CBB_flush(out)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Negotiated Groups
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc4492#section-5.1.2
|
||||
@@ -2475,14 +2489,6 @@ static const struct tls_extension kExtensions[] = {
|
||||
ext_ec_point_parse_clienthello,
|
||||
ext_ec_point_add_serverhello,
|
||||
},
|
||||
{
|
||||
TLSEXT_TYPE_draft_version,
|
||||
NULL,
|
||||
ext_draft_version_add_clienthello,
|
||||
forbid_parse_serverhello,
|
||||
ignore_parse_clienthello,
|
||||
dont_add_serverhello,
|
||||
},
|
||||
{
|
||||
TLSEXT_TYPE_key_share,
|
||||
NULL,
|
||||
@@ -2499,6 +2505,14 @@ static const struct tls_extension kExtensions[] = {
|
||||
ignore_parse_clienthello,
|
||||
dont_add_serverhello,
|
||||
},
|
||||
{
|
||||
TLSEXT_TYPE_supported_versions,
|
||||
NULL,
|
||||
ext_supported_versions_add_clienthello,
|
||||
forbid_parse_serverhello,
|
||||
ignore_parse_clienthello,
|
||||
dont_add_serverhello,
|
||||
},
|
||||
/* The final extension must be non-empty. WebSphere Application Server 7.0 is
|
||||
* intolerant to the last extension being zero-length. See
|
||||
* https://crbug.com/363583. */
|
||||
|
||||
+15
-22
@@ -26,9 +26,8 @@ const (
|
||||
VersionTLS13 = 0x0304
|
||||
)
|
||||
|
||||
// The draft version of TLS 1.3 that is implemented here and sent in the draft
|
||||
// indicator extension.
|
||||
const tls13DraftVersion = 14
|
||||
// A draft version of TLS 1.3 that is sent over the wire for the current draft.
|
||||
const tls13DraftVersion = 0x7f0e
|
||||
|
||||
const (
|
||||
maxPlaintext = 16384 // maximum plaintext payload length
|
||||
@@ -93,11 +92,11 @@ const (
|
||||
extensionKeyShare uint16 = 40 // draft-ietf-tls-tls13-13
|
||||
extensionPreSharedKey uint16 = 41 // draft-ietf-tls-tls13-13
|
||||
extensionEarlyData uint16 = 42 // draft-ietf-tls-tls13-13
|
||||
extensionSupportedVersions uint16 = 43 // draft-ietf-tls-tls13-16
|
||||
extensionCookie uint16 = 44 // draft-ietf-tls-tls13-13
|
||||
extensionCustom uint16 = 1234 // not IANA assigned
|
||||
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
|
||||
extensionRenegotiationInfo uint16 = 0xff01
|
||||
extensionTLS13Draft uint16 = 0xff02
|
||||
extensionChannelID uint16 = 30032 // not IANA assigned
|
||||
)
|
||||
|
||||
@@ -601,6 +600,14 @@ type ProtocolBugs struct {
|
||||
// specified value in the ClientHello version field.
|
||||
SendClientVersion uint16
|
||||
|
||||
// OmitSupportedVersions, if true, causes the client to omit the
|
||||
// supported versions extension.
|
||||
OmitSupportedVersions bool
|
||||
|
||||
// SendSupportedVersions, if non-empty, causes the client to send a
|
||||
// supported versions extension with the values from array.
|
||||
SendSupportedVersions []uint16
|
||||
|
||||
// NegotiateVersion, if non-zero, causes the server to negotiate the
|
||||
// specifed TLS version rather than the version supported by either
|
||||
// peer.
|
||||
@@ -1188,24 +1195,10 @@ func (c *Config) defaultCurves() map[CurveID]bool {
|
||||
return defaultCurves
|
||||
}
|
||||
|
||||
// mutualVersion returns the protocol version to use given the advertised
|
||||
// version of the peer.
|
||||
func (c *Config) mutualVersion(vers uint16, isDTLS bool) (uint16, bool) {
|
||||
// There is no such thing as DTLS 1.1.
|
||||
if isDTLS && vers == VersionTLS11 {
|
||||
vers = VersionTLS10
|
||||
}
|
||||
|
||||
minVersion := c.minVersion(isDTLS)
|
||||
maxVersion := c.maxVersion(isDTLS)
|
||||
|
||||
if vers < minVersion {
|
||||
return 0, false
|
||||
}
|
||||
if vers > maxVersion {
|
||||
vers = maxVersion
|
||||
}
|
||||
return vers, true
|
||||
// isSupportedVersion returns true if the specified protocol version is
|
||||
// acceptable.
|
||||
func (c *Config) isSupportedVersion(vers uint16, isDTLS bool) bool {
|
||||
return c.minVersion(isDTLS) <= vers && vers <= c.maxVersion(isDTLS)
|
||||
}
|
||||
|
||||
// getCertificateForName returns the best certificate for the given name,
|
||||
|
||||
@@ -33,8 +33,10 @@ func versionToWire(vers uint16, isDTLS bool) uint16 {
|
||||
}
|
||||
} else {
|
||||
switch vers {
|
||||
case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13:
|
||||
case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
|
||||
return vers
|
||||
case VersionTLS13:
|
||||
return tls13DraftVersion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +53,10 @@ func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) {
|
||||
}
|
||||
} else {
|
||||
switch vers {
|
||||
case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13:
|
||||
case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
|
||||
return vers, true
|
||||
case tls13DraftVersion:
|
||||
return VersionTLS13, true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ func (c *Conn) clientHandshake() error {
|
||||
return errors.New("tls: NextProtos values too large")
|
||||
}
|
||||
|
||||
minVersion := c.config.minVersion(c.isDTLS)
|
||||
maxVersion := c.config.maxVersion(c.isDTLS)
|
||||
hello := &clientHelloMsg{
|
||||
isDTLS: c.isDTLS,
|
||||
@@ -74,7 +75,7 @@ func (c *Conn) clientHandshake() error {
|
||||
duplicateExtension: c.config.Bugs.DuplicateExtension,
|
||||
channelIDSupported: c.config.ChannelID != nil,
|
||||
npnLast: c.config.Bugs.SwapNPNAndALPN,
|
||||
extendedMasterSecret: c.config.maxVersion(c.isDTLS) >= VersionTLS10,
|
||||
extendedMasterSecret: maxVersion >= VersionTLS10,
|
||||
srtpProtectionProfiles: c.config.SRTPProtectionProfiles,
|
||||
srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
|
||||
customExtension: c.config.Bugs.CustomExtension,
|
||||
@@ -235,8 +236,8 @@ NextCipherSuite:
|
||||
}
|
||||
}
|
||||
|
||||
versOk := candidateSession.vers >= c.config.minVersion(c.isDTLS) &&
|
||||
candidateSession.vers <= c.config.maxVersion(c.isDTLS)
|
||||
versOk := candidateSession.vers >= minVersion &&
|
||||
candidateSession.vers <= maxVersion
|
||||
if ticketOk && versOk && cipherSuiteOk {
|
||||
session = candidateSession
|
||||
}
|
||||
@@ -285,6 +286,19 @@ NextCipherSuite:
|
||||
}
|
||||
}
|
||||
|
||||
if maxVersion == VersionTLS13 && !c.config.Bugs.OmitSupportedVersions {
|
||||
if hello.vers >= VersionTLS13 {
|
||||
hello.vers = VersionTLS12
|
||||
}
|
||||
for version := maxVersion; version >= minVersion; version-- {
|
||||
hello.supportedVersions = append(hello.supportedVersions, versionToWire(version, c.isDTLS))
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.config.Bugs.SendSupportedVersions) > 0 {
|
||||
hello.supportedVersions = c.config.Bugs.SendSupportedVersions
|
||||
}
|
||||
|
||||
if c.config.Bugs.SendClientVersion != 0 {
|
||||
hello.vers = c.config.Bugs.SendClientVersion
|
||||
}
|
||||
@@ -366,12 +380,13 @@ NextCipherSuite:
|
||||
|
||||
serverVersion, ok := wireToVersion(serverWireVersion, c.isDTLS)
|
||||
if ok {
|
||||
c.vers, ok = c.config.mutualVersion(serverVersion, c.isDTLS)
|
||||
ok = c.config.isSupportedVersion(serverVersion, c.isDTLS)
|
||||
}
|
||||
if !ok {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return fmt.Errorf("tls: server selected unsupported protocol version %x", c.vers)
|
||||
}
|
||||
c.vers = serverVersion
|
||||
c.haveVers = true
|
||||
|
||||
helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg)
|
||||
|
||||
@@ -149,6 +149,7 @@ type clientHelloMsg struct {
|
||||
ticketSupported bool
|
||||
sessionTicket []uint8
|
||||
signatureAlgorithms []signatureAlgorithm
|
||||
supportedVersions []uint16
|
||||
secureRenegotiation []byte
|
||||
alpnProtocols []string
|
||||
duplicateExtension bool
|
||||
@@ -190,6 +191,7 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
|
||||
m.ticketSupported == m1.ticketSupported &&
|
||||
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
|
||||
eqSignatureAlgorithms(m.signatureAlgorithms, m1.signatureAlgorithms) &&
|
||||
eqUint16s(m.supportedVersions, m1.supportedVersions) &&
|
||||
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
|
||||
(m.secureRenegotiation == nil) == (m1.secureRenegotiation == nil) &&
|
||||
eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
|
||||
@@ -340,6 +342,14 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
signatureAlgorithms.addU16(uint16(sigAlg))
|
||||
}
|
||||
}
|
||||
if len(m.supportedVersions) > 0 {
|
||||
extensions.addU16(extensionSupportedVersions)
|
||||
supportedVersionsExtension := extensions.addU16LengthPrefixed()
|
||||
supportedVersions := supportedVersionsExtension.addU8LengthPrefixed()
|
||||
for _, version := range m.supportedVersions {
|
||||
supportedVersions.addU16(uint16(version))
|
||||
}
|
||||
}
|
||||
if m.secureRenegotiation != nil {
|
||||
extensions.addU16(extensionRenegotiationInfo)
|
||||
secureRenegoExt := extensions.addU16LengthPrefixed()
|
||||
@@ -400,11 +410,6 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
customExt := extensions.addU16LengthPrefixed()
|
||||
customExt.addBytes([]byte(m.customExtension))
|
||||
}
|
||||
if m.vers == VersionTLS13 {
|
||||
extensions.addU16(extensionTLS13Draft)
|
||||
extValue := extensions.addU16LengthPrefixed()
|
||||
extValue.addU16(tls13DraftVersion)
|
||||
}
|
||||
|
||||
if extensions.len() == 0 {
|
||||
hello.discardChild()
|
||||
@@ -477,6 +482,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
m.ticketSupported = false
|
||||
m.sessionTicket = nil
|
||||
m.signatureAlgorithms = nil
|
||||
m.supportedVersions = nil
|
||||
m.alpnProtocols = nil
|
||||
m.extendedMasterSecret = false
|
||||
m.customExtension = ""
|
||||
@@ -645,6 +651,21 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
m.signatureAlgorithms[i] = signatureAlgorithm(d[0])<<8 | signatureAlgorithm(d[1])
|
||||
d = d[2:]
|
||||
}
|
||||
case extensionSupportedVersions:
|
||||
if length < 1+2 {
|
||||
return false
|
||||
}
|
||||
l := int(data[0])
|
||||
if l != length-1 || l%2 == 1 || l < 2 {
|
||||
return false
|
||||
}
|
||||
n := l / 2
|
||||
d := data[1:]
|
||||
m.supportedVersions = make([]uint16, n)
|
||||
for i := range m.supportedVersions {
|
||||
m.supportedVersions[i] = uint16(d[0])<<8 | uint16(d[1])
|
||||
d = d[2:]
|
||||
}
|
||||
case extensionRenegotiationInfo:
|
||||
if length < 1 || length != int(data[0])+1 {
|
||||
return false
|
||||
|
||||
@@ -204,7 +204,10 @@ func (hs *serverHandshakeState) readClientHello() error {
|
||||
return fmt.Errorf("tls: client offered different version on renego")
|
||||
}
|
||||
}
|
||||
|
||||
c.clientVersion = hs.clientHello.vers
|
||||
|
||||
// Convert the ClientHello wire version to a protocol version.
|
||||
var clientVersion uint16
|
||||
if c.isDTLS {
|
||||
if hs.clientHello.vers <= 0xfefd {
|
||||
@@ -213,9 +216,7 @@ func (hs *serverHandshakeState) readClientHello() error {
|
||||
clientVersion = VersionTLS10
|
||||
}
|
||||
} else {
|
||||
if hs.clientHello.vers >= VersionTLS13 {
|
||||
clientVersion = VersionTLS13
|
||||
} else if hs.clientHello.vers >= VersionTLS12 {
|
||||
if hs.clientHello.vers >= VersionTLS12 {
|
||||
clientVersion = VersionTLS12
|
||||
} else if hs.clientHello.vers >= VersionTLS11 {
|
||||
clientVersion = VersionTLS11
|
||||
@@ -230,12 +231,34 @@ func (hs *serverHandshakeState) readClientHello() error {
|
||||
c.vers = config.Bugs.NegotiateVersion
|
||||
} else if c.haveVers && config.Bugs.NegotiateVersionOnRenego != 0 {
|
||||
c.vers = config.Bugs.NegotiateVersionOnRenego
|
||||
} else {
|
||||
c.vers, ok = config.mutualVersion(clientVersion, c.isDTLS)
|
||||
if !ok {
|
||||
} else if len(hs.clientHello.supportedVersions) > 0 {
|
||||
// Use the versions extension if supplied.
|
||||
var foundVersion bool
|
||||
for _, extVersion := range hs.clientHello.supportedVersions {
|
||||
extVersion, ok = wireToVersion(extVersion, c.isDTLS)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if config.isSupportedVersion(extVersion, c.isDTLS) {
|
||||
c.vers = extVersion
|
||||
foundVersion = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundVersion {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return errors.New("tls: client did not offer any supported protocol versions")
|
||||
}
|
||||
} else {
|
||||
// Otherwise, use the legacy ClientHello version.
|
||||
version := clientVersion
|
||||
if maxVersion := config.maxVersion(c.isDTLS); version > maxVersion {
|
||||
version = maxVersion
|
||||
}
|
||||
if version == 0 || !config.isSupportedVersion(version, c.isDTLS) {
|
||||
return fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
|
||||
}
|
||||
c.vers = version
|
||||
}
|
||||
c.haveVers = true
|
||||
|
||||
@@ -500,7 +523,7 @@ Curves:
|
||||
ResendHelloRetryRequest:
|
||||
// Send HelloRetryRequest.
|
||||
helloRetryRequestMsg := helloRetryRequestMsg{
|
||||
vers: c.vers,
|
||||
vers: versionToWire(c.vers, c.isDTLS),
|
||||
cipherSuite: hs.hello.cipherSuite,
|
||||
selectedGroup: selectedCurve,
|
||||
}
|
||||
|
||||
+104
-7
@@ -4084,6 +4084,7 @@ func addVersionNegotiationTests() {
|
||||
flags = append(flags, vers.flag)
|
||||
}
|
||||
|
||||
// Test configuring the runner's maximum version.
|
||||
for _, runnerVers := range tlsVersions {
|
||||
protocols := []protocol{tls}
|
||||
if runnerVers.hasDTLS && shimVers.hasDTLS {
|
||||
@@ -4171,34 +4172,117 @@ func addVersionNegotiationTests() {
|
||||
}
|
||||
}
|
||||
|
||||
// Test the version extension at all versions.
|
||||
for _, vers := range tlsVersions {
|
||||
protocols := []protocol{tls}
|
||||
if vers.hasDTLS {
|
||||
protocols = append(protocols, dtls)
|
||||
}
|
||||
for _, protocol := range protocols {
|
||||
suffix := vers.name
|
||||
if protocol == dtls {
|
||||
suffix += "-DTLS"
|
||||
}
|
||||
|
||||
wireVersion := versionToWire(vers.version, protocol == dtls)
|
||||
testCases = append(testCases, testCase{
|
||||
protocol: protocol,
|
||||
testType: serverTest,
|
||||
name: "VersionNegotiationExtension-" + suffix,
|
||||
config: Config{
|
||||
Bugs: ProtocolBugs{
|
||||
SendSupportedVersions: []uint16{0x1111, wireVersion, 0x2222},
|
||||
},
|
||||
},
|
||||
expectedVersion: vers.version,
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If all versions are unknown, negotiation fails.
|
||||
testCases = append(testCases, testCase{
|
||||
testType: serverTest,
|
||||
name: "NoSupportedVersions",
|
||||
config: Config{
|
||||
Bugs: ProtocolBugs{
|
||||
SendSupportedVersions: []uint16{0x1111},
|
||||
},
|
||||
},
|
||||
shouldFail: true,
|
||||
expectedError: ":UNSUPPORTED_PROTOCOL:",
|
||||
})
|
||||
testCases = append(testCases, testCase{
|
||||
protocol: dtls,
|
||||
testType: serverTest,
|
||||
name: "NoSupportedVersions-DTLS",
|
||||
config: Config{
|
||||
Bugs: ProtocolBugs{
|
||||
SendSupportedVersions: []uint16{0x1111},
|
||||
},
|
||||
},
|
||||
shouldFail: true,
|
||||
expectedError: ":UNSUPPORTED_PROTOCOL:",
|
||||
})
|
||||
|
||||
testCases = append(testCases, testCase{
|
||||
testType: serverTest,
|
||||
name: "ClientHelloVersionTooHigh",
|
||||
config: Config{
|
||||
MaxVersion: VersionTLS13,
|
||||
Bugs: ProtocolBugs{
|
||||
SendClientVersion: 0x0304,
|
||||
OmitSupportedVersions: true,
|
||||
},
|
||||
},
|
||||
expectedVersion: VersionTLS12,
|
||||
})
|
||||
|
||||
testCases = append(testCases, testCase{
|
||||
testType: serverTest,
|
||||
name: "ConflictingVersionNegotiation",
|
||||
config: Config{
|
||||
MaxVersion: VersionTLS13,
|
||||
Bugs: ProtocolBugs{
|
||||
SendClientVersion: 0x0304,
|
||||
SendSupportedVersions: []uint16{0x0303},
|
||||
},
|
||||
},
|
||||
expectedVersion: VersionTLS12,
|
||||
})
|
||||
|
||||
// Test for version tolerance.
|
||||
testCases = append(testCases, testCase{
|
||||
testType: serverTest,
|
||||
name: "MinorVersionTolerance",
|
||||
config: Config{
|
||||
Bugs: ProtocolBugs{
|
||||
SendClientVersion: 0x03ff,
|
||||
SendClientVersion: 0x03ff,
|
||||
OmitSupportedVersions: true,
|
||||
},
|
||||
},
|
||||
expectedVersion: VersionTLS13,
|
||||
expectedVersion: VersionTLS12,
|
||||
})
|
||||
testCases = append(testCases, testCase{
|
||||
testType: serverTest,
|
||||
name: "MajorVersionTolerance",
|
||||
config: Config{
|
||||
Bugs: ProtocolBugs{
|
||||
SendClientVersion: 0x0400,
|
||||
SendClientVersion: 0x0400,
|
||||
OmitSupportedVersions: true,
|
||||
},
|
||||
},
|
||||
expectedVersion: VersionTLS13,
|
||||
expectedVersion: VersionTLS12,
|
||||
})
|
||||
|
||||
testCases = append(testCases, testCase{
|
||||
protocol: dtls,
|
||||
testType: serverTest,
|
||||
name: "MinorVersionTolerance-DTLS",
|
||||
config: Config{
|
||||
Bugs: ProtocolBugs{
|
||||
SendClientVersion: 0xfe00,
|
||||
SendClientVersion: 0xfe00,
|
||||
OmitSupportedVersions: true,
|
||||
},
|
||||
},
|
||||
expectedVersion: VersionTLS12,
|
||||
@@ -4209,7 +4293,8 @@ func addVersionNegotiationTests() {
|
||||
name: "MajorVersionTolerance-DTLS",
|
||||
config: Config{
|
||||
Bugs: ProtocolBugs{
|
||||
SendClientVersion: 0xfdff,
|
||||
SendClientVersion: 0xfdff,
|
||||
OmitSupportedVersions: true,
|
||||
},
|
||||
},
|
||||
expectedVersion: VersionTLS12,
|
||||
@@ -4221,7 +4306,8 @@ func addVersionNegotiationTests() {
|
||||
name: "VersionTooLow",
|
||||
config: Config{
|
||||
Bugs: ProtocolBugs{
|
||||
SendClientVersion: 0x0200,
|
||||
SendClientVersion: 0x0200,
|
||||
OmitSupportedVersions: true,
|
||||
},
|
||||
},
|
||||
shouldFail: true,
|
||||
@@ -4317,12 +4403,20 @@ func addMinimumVersionTests() {
|
||||
}
|
||||
}
|
||||
|
||||
// Test the client enforces minimum
|
||||
// versions. Use the NegotiateVersion bug to
|
||||
// ensure the server does not decline to select
|
||||
// a version first. This may occur if the
|
||||
// versions extension is used.
|
||||
testCases = append(testCases, testCase{
|
||||
protocol: protocol,
|
||||
testType: clientTest,
|
||||
name: "MinimumVersion-Client-" + suffix,
|
||||
config: Config{
|
||||
MaxVersion: runnerVers.version,
|
||||
Bugs: ProtocolBugs{
|
||||
NegotiateVersion: runnerVers.version,
|
||||
},
|
||||
},
|
||||
flags: flags,
|
||||
expectedVersion: expectedVersion,
|
||||
@@ -4336,6 +4430,9 @@ func addMinimumVersionTests() {
|
||||
name: "MinimumVersion-Client2-" + suffix,
|
||||
config: Config{
|
||||
MaxVersion: runnerVers.version,
|
||||
Bugs: ProtocolBugs{
|
||||
NegotiateVersion: runnerVers.version,
|
||||
},
|
||||
},
|
||||
flags: []string{"-min-version", shimVersFlag},
|
||||
expectedVersion: expectedVersion,
|
||||
|
||||
+5
-2
@@ -71,9 +71,11 @@ static int ssl3_version_from_wire(uint16_t *out_version,
|
||||
case TLS1_VERSION:
|
||||
case TLS1_1_VERSION:
|
||||
case TLS1_2_VERSION:
|
||||
case TLS1_3_VERSION:
|
||||
*out_version = wire_version;
|
||||
return 1;
|
||||
case TLS1_3_DRAFT_VERSION:
|
||||
*out_version = TLS1_3_VERSION;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -85,8 +87,9 @@ static uint16_t ssl3_version_to_wire(uint16_t version) {
|
||||
case TLS1_VERSION:
|
||||
case TLS1_1_VERSION:
|
||||
case TLS1_2_VERSION:
|
||||
case TLS1_3_VERSION:
|
||||
return version;
|
||||
case TLS1_3_VERSION:
|
||||
return TLS1_3_DRAFT_VERSION;
|
||||
}
|
||||
|
||||
/* It is an error to use this function with an invalid version. */
|
||||
|
||||
Reference in New Issue
Block a user