Skip to content

Commit

Permalink
Moving TLS 1.3 version negotiation into extension.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
dvorak42 authored and CQ bot account: commit-bot@chromium.org committed Sep 27, 2016
1 parent 2fb2ffb commit fdd1099
Show file tree
Hide file tree
Showing 14 changed files with 339 additions and 120 deletions.
2 changes: 1 addition & 1 deletion include/openssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 1 addition & 8 deletions include/openssl/tls1.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions ssl/handshake_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
94 changes: 68 additions & 26 deletions ssl/handshake_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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) {
Expand Down
6 changes: 0 additions & 6 deletions ssl/ssl_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 19 additions & 3 deletions ssl/ssl_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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; }

Expand Down Expand Up @@ -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,
Expand Down
68 changes: 41 additions & 27 deletions ssl/t1_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2476,25 +2490,25 @@ static const struct tls_extension kExtensions[] = {
ext_ec_point_add_serverhello,
},
{
TLSEXT_TYPE_draft_version,
TLSEXT_TYPE_key_share,
NULL,
ext_draft_version_add_clienthello,
ext_key_share_add_clienthello,
forbid_parse_serverhello,
ignore_parse_clienthello,
dont_add_serverhello,
},
{
TLSEXT_TYPE_key_share,
TLSEXT_TYPE_pre_shared_key,
NULL,
ext_key_share_add_clienthello,
ext_pre_shared_key_add_clienthello,
forbid_parse_serverhello,
ignore_parse_clienthello,
dont_add_serverhello,
},
{
TLSEXT_TYPE_pre_shared_key,
TLSEXT_TYPE_supported_versions,
NULL,
ext_pre_shared_key_add_clienthello,
ext_supported_versions_add_clienthello,
forbid_parse_serverhello,
ignore_parse_clienthello,
dont_add_serverhello,
Expand Down
37 changes: 15 additions & 22 deletions ssl/test/runner/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit fdd1099

Please sign in to comment.