external/boringssl: Sync to ee7aa02744a78bf4630913b1c83d0fe36aa45efc.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/a93bc1124c00b1ac0a68ea5cb14b158d6c8366e1..ee7aa02744a78bf4630913b1c83d0fe36aa45efc
Test: BoringSSL CTS Presubmits.
Change-Id: I5a05899374e616003f841983b6545f5c90e7c71d
diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt
index 3e9cd40..0c09443 100644
--- a/src/ssl/CMakeLists.txt
+++ b/src/ssl/CMakeLists.txt
@@ -29,6 +29,7 @@
ssl_session.c
ssl_stat.c
ssl_transcript.c
+ ssl_versions.c
ssl_x509.c
t1_enc.c
t1_lib.c
diff --git a/src/ssl/dtls_method.c b/src/ssl/dtls_method.c
index 6084789..dd8d786 100644
--- a/src/ssl/dtls_method.c
+++ b/src/ssl/dtls_method.c
@@ -66,35 +66,6 @@
#include "internal.h"
-static int dtls1_version_from_wire(uint16_t *out_version,
- uint16_t wire_version) {
- switch (wire_version) {
- case DTLS1_VERSION:
- /* DTLS 1.0 maps to TLS 1.1, not TLS 1.0. */
- *out_version = TLS1_1_VERSION;
- return 1;
- case DTLS1_2_VERSION:
- *out_version = TLS1_2_VERSION;
- return 1;
- }
-
- return 0;
-}
-
-static uint16_t dtls1_version_to_wire(uint16_t version) {
- switch (version) {
- case TLS1_1_VERSION:
- /* DTLS 1.0 maps to TLS 1.1, not TLS 1.0. */
- return DTLS1_VERSION;
- case TLS1_2_VERSION:
- return DTLS1_2_VERSION;
- }
-
- /* It is an error to use this function with an invalid version. */
- assert(0);
- return 0;
-}
-
static int dtls1_supports_cipher(const SSL_CIPHER *cipher) {
return cipher->algorithm_enc != SSL_eNULL;
}
@@ -134,10 +105,6 @@
static const SSL_PROTOCOL_METHOD kDTLSProtocolMethod = {
1 /* is_dtls */,
- TLS1_1_VERSION,
- TLS1_2_VERSION,
- dtls1_version_from_wire,
- dtls1_version_to_wire,
dtls1_new,
dtls1_free,
dtls1_get_message,
diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c
index dddf602..c772f77 100644
--- a/src/ssl/handshake_client.c
+++ b/src/ssl/handshake_client.c
@@ -717,33 +717,26 @@
return -1;
}
- uint16_t max_wire_version = ssl->method->version_to_wire(hs->max_version);
- assert(hs->state == SSL3_ST_CW_CLNT_HELLO_A);
- if (!ssl->s3->have_version) {
- ssl->version = max_wire_version;
- }
-
/* Always advertise the ClientHello version from the original maximum version,
* even on renegotiation. The static RSA key exchange uses this field, and
* some servers fail when it changes across handshakes. */
- hs->client_version = max_wire_version;
- if (hs->max_version >= TLS1_3_VERSION) {
- hs->client_version = ssl->method->version_to_wire(TLS1_2_VERSION);
+ if (SSL_is_dtls(hs->ssl)) {
+ hs->client_version =
+ hs->max_version >= TLS1_2_VERSION ? DTLS1_2_VERSION : DTLS1_VERSION;
+ } else {
+ hs->client_version =
+ hs->max_version >= TLS1_2_VERSION ? TLS1_2_VERSION : hs->max_version;
}
/* If the configured session has expired or was created at a disabled
* version, drop it. */
if (ssl->session != NULL) {
- uint16_t session_version;
if (ssl->session->is_server ||
- !ssl->method->version_from_wire(&session_version,
- ssl->session->ssl_version) ||
- (session_version < TLS1_3_VERSION &&
- ssl->session->session_id_length == 0) ||
+ !ssl_supports_version(hs, ssl->session->ssl_version) ||
+ (ssl->session->session_id_length == 0 &&
+ ssl->session->tlsext_ticklen == 0) ||
ssl->session->not_resumable ||
- !ssl_session_is_time_valid(ssl, ssl->session) ||
- session_version < hs->min_version ||
- session_version > hs->max_version) {
+ !ssl_session_is_time_valid(ssl, ssl->session)) {
ssl_set_session(ssl, NULL);
}
}
@@ -798,7 +791,7 @@
static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
CBS server_hello, server_random, session_id;
- uint16_t server_wire_version, cipher_suite;
+ uint16_t server_version, cipher_suite;
uint8_t compression_method;
int ret = ssl->method->ssl_get_message(ssl);
@@ -826,15 +819,13 @@
CBS_init(&server_hello, ssl->init_msg, ssl->init_num);
- if (!CBS_get_u16(&server_hello, &server_wire_version)) {
+ if (!CBS_get_u16(&server_hello, &server_version)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return -1;
}
- uint16_t server_version;
- if (!ssl->method->version_from_wire(&server_version, server_wire_version) ||
- server_version < hs->min_version || server_version > hs->max_version) {
+ if (!ssl_supports_version(hs, server_version)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
return -1;
@@ -842,11 +833,11 @@
assert(ssl->s3->have_version == ssl->s3->initial_handshake_complete);
if (!ssl->s3->have_version) {
- ssl->version = server_wire_version;
+ ssl->version = server_version;
/* At this point, the connection's version is known and ssl->version is
* fixed. Begin enforcing the record-layer version. */
ssl->s3->have_version = 1;
- } else if (server_wire_version != ssl->version) {
+ } else if (server_version != ssl->version) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
return -1;
diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c
index d591c80..64abd5d 100644
--- a/src/ssl/handshake_server.c
+++ b/src/ssl/handshake_server.c
@@ -471,12 +471,9 @@
const SSL_CLIENT_HELLO *client_hello) {
SSL *const ssl = hs->ssl;
assert(!ssl->s3->have_version);
- uint16_t version = 0;
- /* Check supported_versions extension if it is present. */
- CBS supported_versions;
+ CBS supported_versions, versions;
if (ssl_client_hello_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) {
@@ -484,89 +481,63 @@
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
-
- /* Choose the newest commonly-supported version advertised by the client.
- * The client orders the versions according to its preferences, but we're
- * not required to honor the client's preferences. */
- 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 (hs->min_version <= ext_version &&
- ext_version <= hs->max_version &&
- (!found_version || version < ext_version)) {
- version = ext_version;
- found_version = 1;
- }
- }
-
- if (!found_version) {
- goto unsupported_protocol;
- }
} else {
- /* Process ClientHello.version instead. Note that versions beyond (D)TLS 1.2
- * do not use this mechanism. */
+ /* Convert the ClientHello version to an equivalent supported_versions
+ * extension. */
+ static const uint8_t kTLSVersions[] = {
+ 0x03, 0x03, /* TLS 1.2 */
+ 0x03, 0x02, /* TLS 1.1 */
+ 0x03, 0x01, /* TLS 1 */
+ 0x03, 0x00, /* SSL 3 */
+ };
+
+ static const uint8_t kDTLSVersions[] = {
+ 0xfe, 0xfd, /* DTLS 1.2 */
+ 0xfe, 0xff, /* DTLS 1.0 */
+ };
+
+ size_t versions_len = 0;
if (SSL_is_dtls(ssl)) {
if (client_hello->version <= DTLS1_2_VERSION) {
- version = TLS1_2_VERSION;
+ versions_len = 4;
} else if (client_hello->version <= DTLS1_VERSION) {
- version = TLS1_1_VERSION;
- } else {
- goto unsupported_protocol;
+ versions_len = 2;
}
+ CBS_init(&versions, kDTLSVersions + sizeof(kDTLSVersions) - versions_len,
+ versions_len);
} else {
if (client_hello->version >= TLS1_2_VERSION) {
- version = TLS1_2_VERSION;
+ versions_len = 8;
} else if (client_hello->version >= TLS1_1_VERSION) {
- version = TLS1_1_VERSION;
+ versions_len = 6;
} else if (client_hello->version >= TLS1_VERSION) {
- version = TLS1_VERSION;
+ versions_len = 4;
} else if (client_hello->version >= SSL3_VERSION) {
- version = SSL3_VERSION;
- } else {
- goto unsupported_protocol;
+ versions_len = 2;
}
- }
-
- /* Apply our minimum and maximum version. */
- if (version > hs->max_version) {
- version = hs->max_version;
- }
-
- if (version < hs->min_version) {
- goto unsupported_protocol;
+ CBS_init(&versions, kTLSVersions + sizeof(kTLSVersions) - versions_len,
+ versions_len);
}
}
- /* Handle FALLBACK_SCSV. */
- if (ssl_client_cipher_list_contains_cipher(client_hello,
- SSL3_CK_FALLBACK_SCSV & 0xffff) &&
- version < hs->max_version) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_INAPPROPRIATE_FALLBACK);
- *out_alert = SSL3_AD_INAPPROPRIATE_FALLBACK;
+ if (!ssl_negotiate_version(hs, out_alert, &ssl->version, &versions)) {
return 0;
}
- hs->client_version = client_hello->version;
- ssl->version = ssl->method->version_to_wire(version);
-
/* At this point, the connection's version is known and |ssl->version| is
* fixed. Begin enforcing the record-layer version. */
ssl->s3->have_version = 1;
- return 1;
+ /* Handle FALLBACK_SCSV. */
+ if (ssl_client_cipher_list_contains_cipher(client_hello,
+ SSL3_CK_FALLBACK_SCSV & 0xffff) &&
+ ssl3_protocol_version(ssl) < hs->max_version) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INAPPROPRIATE_FALLBACK);
+ *out_alert = SSL3_AD_INAPPROPRIATE_FALLBACK;
+ return 0;
+ }
-unsupported_protocol:
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
- *out_alert = SSL_AD_PROTOCOL_VERSION;
- return 0;
+ return 1;
}
static STACK_OF(SSL_CIPHER) *
@@ -611,12 +582,6 @@
uint32_t *out_mask_k,
uint32_t *out_mask_a) {
SSL *const ssl = hs->ssl;
- if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
- *out_mask_k = SSL_kGENERIC;
- *out_mask_a = SSL_aGENERIC;
- return;
- }
-
uint32_t mask_k = 0;
uint32_t mask_a = 0;
@@ -759,7 +724,7 @@
return -1;
}
- /* Load the client random. */
+ hs->client_version = client_hello.version;
if (client_hello.random_len != SSL3_RANDOM_SIZE) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
@@ -1083,7 +1048,7 @@
/* Determine the group to use. */
uint16_t group_id;
if (!tls1_get_shared_group(hs, &group_id)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_ECDH_KEY);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
goto err;
}
@@ -1478,7 +1443,7 @@
/* The key exchange state may now be discarded. */
SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
} else if (!(alg_k & SSL_kPSK)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_TYPE);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
goto err;
}
@@ -1487,7 +1452,7 @@
* pre-shared key. */
if (alg_a & SSL_aPSK) {
if (ssl->psk_server_callback == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_SERVER_CB);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
goto err;
}
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index d56c73b..f6cea7a 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -163,6 +163,57 @@
#endif
+typedef struct ssl_handshake_st SSL_HANDSHAKE;
+
+/* Protocol versions.
+ *
+ * Due to DTLS's historical wire version differences and to support multiple
+ * variants of the same protocol during development, we maintain two notions of
+ * version.
+ *
+ * The "version" or "wire version" is the actual 16-bit value that appears on
+ * the wire. It uniquely identifies a version and is also used at API
+ * boundaries. The set of supported versions differs between TLS and DTLS. Wire
+ * versions are opaque values and may not be compared numerically.
+ *
+ * The "protocol version" identifies the high-level handshake variant being
+ * used. DTLS versions map to the corresponding TLS versions. Draft TLS 1.3
+ * variants all map to TLS 1.3. Protocol versions are sequential and may be
+ * compared numerically. */
+
+/* ssl_protocol_version_from_wire sets |*out| to the protocol version
+ * corresponding to wire version |version| and returns one. If |version| is not
+ * a valid TLS or DTLS version, it returns zero.
+ *
+ * Note this simultaneously handles both DTLS and TLS. Use one of the
+ * higher-level functions below for most operations. */
+int ssl_protocol_version_from_wire(uint16_t *out, uint16_t version);
+
+/* ssl_get_version_range sets |*out_min_version| and |*out_max_version| to the
+ * minimum and maximum enabled protocol versions, respectively. */
+int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
+ uint16_t *out_max_version);
+
+/* ssl_supports_version returns one if |hs| supports |version| and zero
+ * otherwise. */
+int ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version);
+
+/* ssl_add_supported_versions writes the supported versions of |hs| to |cbb|, in
+ * decreasing preference order. */
+int ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb);
+
+/* ssl_negotiate_version negotiates a common version based on |hs|'s preferences
+ * and the peer preference list in |peer_versions|. On success, it returns one
+ * and sets |*out_version| to the selected version. Otherwise, it returns zero
+ * and sets |*out_alert| to an alert to send. */
+int ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ uint16_t *out_version, const CBS *peer_versions);
+
+/* ssl3_protocol_version returns |ssl|'s protocol version. It is an error to
+ * call this function before the version is determined. */
+uint16_t ssl3_protocol_version(const SSL *ssl);
+
+
/* Cipher suites. */
/* Bits for |algorithm_mkey| (key exchange algorithm). */
@@ -542,8 +593,6 @@
/* Private key operations. */
-typedef struct ssl_handshake_st SSL_HANDSHAKE;
-
/* ssl_has_private_key returns one if |ssl| has a private key
* configured and zero otherwise. */
int ssl_has_private_key(const SSL *ssl);
@@ -1414,17 +1463,6 @@
struct ssl_protocol_method_st {
/* is_dtls is one if the protocol is DTLS and zero otherwise. */
char is_dtls;
- /* min_version is the minimum implemented version. */
- uint16_t min_version;
- /* max_version is the maximum implemented version. */
- uint16_t max_version;
- /* version_from_wire maps |wire_version| to a protocol version. On success, it
- * sets |*out_version| to the result and returns one. If the version is
- * unknown, it returns zero. */
- int (*version_from_wire)(uint16_t *out_version, uint16_t wire_version);
- /* version_to_wire maps |version| to the wire representation. It is an error
- * to call it with an invalid version. */
- uint16_t (*version_to_wire)(uint16_t version);
int (*ssl_new)(SSL *ssl);
void (*ssl_free)(SSL *ssl);
/* ssl_get_message reads the next handshake message. On success, it returns
@@ -1846,7 +1884,7 @@
const SSL_PROTOCOL_METHOD *method;
/* version is the protocol version. */
- int version;
+ uint16_t version;
/* conf_max_version is the maximum acceptable protocol version configured by
* |SSL_set_max_proto_version|. Note this version is normalized in DTLS and is
@@ -2049,10 +2087,12 @@
int ssl_session_is_resumable(const SSL_HANDSHAKE *hs,
const SSL_SESSION *session);
-/* SSL_SESSION_get_digest returns the digest used in |session|. If the digest is
- * invalid, it returns NULL. */
-const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session,
- const SSL *ssl);
+/* SSL_SESSION_protocol_version returns the protocol version associated with
+ * |session|. */
+uint16_t SSL_SESSION_protocol_version(const SSL_SESSION *session);
+
+/* SSL_SESSION_get_digest returns the digest used in |session|. */
+const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session);
void ssl_set_session(SSL *ssl, SSL_SESSION *session);
@@ -2285,15 +2325,6 @@
/* ssl_can_read returns one if |ssl| is allowed to read and zero otherwise. */
int ssl_can_read(const SSL *ssl);
-/* ssl_get_version_range sets |*out_min_version| and |*out_max_version| to the
- * minimum and maximum enabled protocol versions, respectively. */
-int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
- uint16_t *out_max_version);
-
-/* ssl3_protocol_version returns |ssl|'s protocol version. It is an error to
- * call this function before the version is determined. */
-uint16_t ssl3_protocol_version(const SSL *ssl);
-
void ssl_get_current_time(const SSL *ssl, struct OPENSSL_timeval *out_clock);
/* ssl_reset_error_state resets state for |SSL_get_error|. */
diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c
index f368ff2..cc6a559 100644
--- a/src/ssl/ssl_asn1.c
+++ b/src/ssl/ssl_asn1.c
@@ -576,10 +576,17 @@
CBS session;
uint64_t version, ssl_version;
+ uint16_t unused;
if (!CBS_get_asn1(cbs, &session, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1_uint64(&session, &version) ||
version != kVersion ||
- !CBS_get_asn1_uint64(&session, &ssl_version)) {
+ !CBS_get_asn1_uint64(&session, &ssl_version) ||
+ /* Require sessions have versions valid in either TLS or DTLS. The session
+ * will not be used by the handshake if not applicable, but, for
+ * simplicity, never parse a session that does not pass
+ * |ssl_protocol_version_from_wire|. */
+ ssl_version > UINT16_MAX ||
+ !ssl_protocol_version_from_wire(&unused, ssl_version)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c
index 562c1f3..5d88878 100644
--- a/src/ssl/ssl_cipher.c
+++ b/src/ssl/ssl_cipher.c
@@ -1035,7 +1035,7 @@
uint32_t alg_mkey, alg_auth, alg_enc, alg_mac;
uint16_t min_version;
const char *l, *buf;
- int multi, skip_rule, rule, ok, in_group = 0, has_group = 0;
+ int multi, skip_rule, rule, in_group = 0, has_group = 0;
size_t j, buf_len;
uint32_t cipher_id;
char ch;
@@ -1082,10 +1082,7 @@
rule = CIPHER_SPECIAL;
l++;
} else if (ch == '[') {
- if (in_group) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NESTED_GROUP);
- return 0;
- }
+ assert(!in_group);
in_group = 1;
has_group = 1;
l++;
@@ -1185,15 +1182,11 @@
/* Ok, we have the rule, now apply it. */
if (rule == CIPHER_SPECIAL) {
- /* special command */
- ok = 0;
- if (buf_len == 8 && !strncmp(buf, "STRENGTH", 8)) {
- ok = ssl_cipher_strength_sort(head_p, tail_p);
- } else {
+ if (buf_len != 8 || strncmp(buf, "STRENGTH", 8) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND);
+ return 0;
}
-
- if (ok == 0) {
+ if (!ssl_cipher_strength_sort(head_p, tail_p)) {
return 0;
}
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index 1b002a5..109dfd0 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -978,60 +978,6 @@
return SSL_ERROR_SYSCALL;
}
-static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
- uint16_t version) {
- /* Zero is interpreted as the default minimum version. */
- if (version == 0) {
- *out = method->min_version;
- /* SSL 3.0 is disabled unless explicitly enabled. */
- if (*out < TLS1_VERSION) {
- *out = TLS1_VERSION;
- }
- return 1;
- }
-
- if (version == TLS1_3_VERSION) {
- version = TLS1_3_DRAFT_VERSION;
- }
-
- return method->version_from_wire(out, version);
-}
-
-static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
- uint16_t version) {
- /* Zero is interpreted as the default maximum version. */
- if (version == 0) {
- *out = method->max_version;
- /* TODO(svaldez): Enable TLS 1.3 by default once fully implemented. */
- if (*out > TLS1_2_VERSION) {
- *out = TLS1_2_VERSION;
- }
- return 1;
- }
-
- if (version == TLS1_3_VERSION) {
- version = TLS1_3_DRAFT_VERSION;
- }
-
- return method->version_from_wire(out, version);
-}
-
-int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, uint16_t version) {
- return set_min_version(ctx->method, &ctx->conf_min_version, version);
-}
-
-int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, uint16_t version) {
- return set_max_version(ctx->method, &ctx->conf_max_version, version);
-}
-
-int SSL_set_min_proto_version(SSL *ssl, uint16_t version) {
- return set_min_version(ssl->method, &ssl->conf_min_version, version);
-}
-
-int SSL_set_max_proto_version(SSL *ssl, uint16_t version) {
- return set_max_version(ssl->method, &ssl->conf_max_version, version);
-}
-
uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options) {
ctx->options |= options;
return ctx->options;
@@ -1901,43 +1847,6 @@
}
}
-static const char *ssl_get_version(int version) {
- switch (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:
- return "TLSv1.2";
-
- case TLS1_1_VERSION:
- return "TLSv1.1";
-
- case TLS1_VERSION:
- return "TLSv1";
-
- case SSL3_VERSION:
- return "SSLv3";
-
- case DTLS1_VERSION:
- return "DTLSv1";
-
- case DTLS1_2_VERSION:
- return "DTLSv1.2";
-
- default:
- return "unknown";
- }
-}
-
-const char *SSL_get_version(const SSL *ssl) {
- return ssl_get_version(ssl->version);
-}
-
-const char *SSL_SESSION_get_version(const SSL_SESSION *session) {
- return ssl_get_version(session->ssl_version);
-}
-
EVP_PKEY *SSL_get_privatekey(const SSL *ssl) {
if (ssl->cert != NULL) {
return ssl->cert->privatekey;
@@ -2015,15 +1924,6 @@
return ret;
}
-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; }
SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) {
@@ -2329,102 +2229,6 @@
cipher->algorithm_mac == SSL_AEAD;
}
-const struct {
- uint16_t version;
- uint32_t flag;
-} kVersions[] = {
- {SSL3_VERSION, SSL_OP_NO_SSLv3},
- {TLS1_VERSION, SSL_OP_NO_TLSv1},
- {TLS1_1_VERSION, SSL_OP_NO_TLSv1_1},
- {TLS1_2_VERSION, SSL_OP_NO_TLSv1_2},
- {TLS1_3_VERSION, SSL_OP_NO_TLSv1_3},
-};
-
-static const size_t kVersionsLen = OPENSSL_ARRAY_SIZE(kVersions);
-
-int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
- uint16_t *out_max_version) {
- /* For historical reasons, |SSL_OP_NO_DTLSv1| aliases |SSL_OP_NO_TLSv1|, but
- * DTLS 1.0 should be mapped to TLS 1.1. */
- uint32_t options = ssl->options;
- if (SSL_is_dtls(ssl)) {
- options &= ~SSL_OP_NO_TLSv1_1;
- if (options & SSL_OP_NO_DTLSv1) {
- options |= SSL_OP_NO_TLSv1_1;
- }
- }
-
- uint16_t min_version = ssl->conf_min_version;
- uint16_t max_version = ssl->conf_max_version;
-
- /* Bound the range to only those implemented in this protocol. */
- if (min_version < ssl->method->min_version) {
- min_version = ssl->method->min_version;
- }
- if (max_version > ssl->method->max_version) {
- max_version = ssl->method->max_version;
- }
-
- /* OpenSSL's API for controlling versions entails blacklisting individual
- * protocols. This has two problems. First, on the client, the protocol can
- * only express a contiguous range of versions. Second, a library consumer
- * trying to set a maximum version cannot disable protocol versions that get
- * added in a future version of the library.
- *
- * To account for both of these, OpenSSL interprets the client-side bitmask
- * as a min/max range by picking the lowest contiguous non-empty range of
- * enabled protocols. Note that this means it is impossible to set a maximum
- * version of the higest supported TLS version in a future-proof way. */
- int any_enabled = 0;
- for (size_t i = 0; i < kVersionsLen; i++) {
- /* Only look at the versions already enabled. */
- if (min_version > kVersions[i].version) {
- continue;
- }
- if (max_version < kVersions[i].version) {
- break;
- }
-
- if (!(options & kVersions[i].flag)) {
- /* The minimum version is the first enabled version. */
- if (!any_enabled) {
- any_enabled = 1;
- min_version = kVersions[i].version;
- }
- continue;
- }
-
- /* If there is a disabled version after the first enabled one, all versions
- * after it are implicitly disabled. */
- if (any_enabled) {
- max_version = kVersions[i-1].version;
- break;
- }
- }
-
- if (!any_enabled) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SUPPORTED_VERSIONS_ENABLED);
- return 0;
- }
-
- *out_min_version = min_version;
- *out_max_version = max_version;
- return 1;
-}
-
-uint16_t ssl3_protocol_version(const SSL *ssl) {
- assert(ssl->s3->have_version);
- uint16_t version;
- if (!ssl->method->version_from_wire(&version, ssl->version)) {
- /* TODO(davidben): Use the internal version representation for ssl->version
- * and map to the public API representation at API boundaries. */
- assert(0);
- return 0;
- }
-
- return version;
-}
-
int SSL_is_server(const SSL *ssl) { return ssl->server; }
int SSL_is_dtls(const SSL *ssl) { return ssl->method->is_dtls; }
diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c
index f025364..3e2c9f4 100644
--- a/src/ssl/ssl_session.c
+++ b/src/ssl/ssl_session.c
@@ -505,14 +505,21 @@
return CRYPTO_get_ex_data(&session->ex_data, idx);
}
-const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session,
- const SSL *ssl) {
- uint16_t version;
- if (!ssl->method->version_from_wire(&version, session->ssl_version)) {
- return NULL;
+uint16_t SSL_SESSION_protocol_version(const SSL_SESSION *session) {
+ uint16_t ret;
+ if (!ssl_protocol_version_from_wire(&ret, session->ssl_version)) {
+ /* An |SSL_SESSION| will never have an invalid version. This is enforced by
+ * the parser. */
+ assert(0);
+ return 0;
}
- return ssl_get_handshake_digest(session->cipher->algorithm_prf, version);
+ return ret;
+}
+
+const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session) {
+ return ssl_get_handshake_digest(session->cipher->algorithm_prf,
+ SSL_SESSION_protocol_version(session));
}
int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) {
@@ -952,7 +959,6 @@
}
if (ret) {
- found_session->not_resumable = 1;
if (ctx->remove_session_cb != NULL) {
ctx->remove_session_cb(ctx, found_session);
}
@@ -1031,7 +1037,6 @@
* save on locking overhead */
(void) lh_SSL_SESSION_delete(param->cache, session);
SSL_SESSION_list_remove(param->ctx, session);
- session->not_resumable = 1;
if (param->ctx->remove_session_cb != NULL) {
param->ctx->remove_session_cb(param->ctx, session);
}
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 84b7496..2c648ac 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -180,7 +180,7 @@
// Standard names may be used instead of OpenSSL names.
{
"[TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256|"
- "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]:"
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]:"
"[TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256]:"
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
{
@@ -214,6 +214,32 @@
},
false,
},
+ // Additional masks after @STRENGTH get silently discarded.
+ //
+ // TODO(davidben): Make this an error. If not silently discarded, they get
+ // interpreted as + opcodes which are very different.
+ {
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES256-GCM-SHA384:"
+ "@STRENGTH+AES256",
+ {
+ {TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ },
+ false,
+ },
+ {
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES256-GCM-SHA384:"
+ "@STRENGTH+AES256:"
+ "ECDHE-RSA-CHACHA20-POLY1305",
+ {
+ {TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0},
+ {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 0},
+ },
+ false,
+ },
// Exact ciphers may not be used in multi-part rules; they are treated
// as unknown aliases.
{
@@ -2567,6 +2593,10 @@
EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_3_VERSION));
EXPECT_EQ(TLS1_3_VERSION, ctx->conf_max_version);
+ // TLS1_3_DRAFT_VERSION is not an API-level version.
+ EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_3_DRAFT_VERSION));
+ ERR_clear_error();
+
ctx.reset(SSL_CTX_new(DTLS_method()));
ASSERT_TRUE(ctx);
diff --git a/src/ssl/ssl_versions.c b/src/ssl/ssl_versions.c
new file mode 100644
index 0000000..5d92771
--- /dev/null
+++ b/src/ssl/ssl_versions.c
@@ -0,0 +1,343 @@
+/* Copyright (c) 2017, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/ssl.h>
+
+#include <assert.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+#include "../crypto/internal.h"
+
+
+int ssl_protocol_version_from_wire(uint16_t *out, uint16_t version) {
+ switch (version) {
+ case SSL3_VERSION:
+ case TLS1_VERSION:
+ case TLS1_1_VERSION:
+ case TLS1_2_VERSION:
+ *out = version;
+ return 1;
+
+ case TLS1_3_DRAFT_VERSION:
+ *out = TLS1_3_VERSION;
+ return 1;
+
+ case DTLS1_VERSION:
+ /* DTLS 1.0 is analogous to TLS 1.1, not TLS 1.0. */
+ *out = TLS1_1_VERSION;
+ return 1;
+
+ case DTLS1_2_VERSION:
+ *out = TLS1_2_VERSION;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* The follow arrays are the supported versions for TLS and DTLS, in order of
+ * decreasing preference. */
+
+static const uint16_t kTLSVersions[] = {
+ TLS1_3_DRAFT_VERSION,
+ TLS1_2_VERSION,
+ TLS1_1_VERSION,
+ TLS1_VERSION,
+ SSL3_VERSION,
+};
+
+static const uint16_t kDTLSVersions[] = {
+ DTLS1_2_VERSION,
+ DTLS1_VERSION,
+};
+
+static void get_method_versions(const SSL_PROTOCOL_METHOD *method,
+ const uint16_t **out, size_t *out_num) {
+ if (method->is_dtls) {
+ *out = kDTLSVersions;
+ *out_num = OPENSSL_ARRAY_SIZE(kDTLSVersions);
+ } else {
+ *out = kTLSVersions;
+ *out_num = OPENSSL_ARRAY_SIZE(kTLSVersions);
+ }
+}
+
+static int method_supports_version(const SSL_PROTOCOL_METHOD *method,
+ uint16_t version) {
+ const uint16_t *versions;
+ size_t num_versions;
+ get_method_versions(method, &versions, &num_versions);
+ for (size_t i = 0; i < num_versions; i++) {
+ if (versions[i] == version) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int set_version_bound(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+ uint16_t version) {
+ /* The public API uses wire versions, except we use |TLS1_3_VERSION|
+ * everywhere to refer to any draft TLS 1.3 versions. In this direction, we
+ * map it to some representative TLS 1.3 draft version. */
+ if (version == TLS1_3_DRAFT_VERSION) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION);
+ return 0;
+ }
+ if (version == TLS1_3_VERSION) {
+ version = TLS1_3_DRAFT_VERSION;
+ }
+
+ if (!method_supports_version(method, version) ||
+ !ssl_protocol_version_from_wire(out, version)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+ uint16_t version) {
+ /* Zero is interpreted as the default minimum version. */
+ if (version == 0) {
+ /* SSL 3.0 is disabled by default and TLS 1.0 does not exist in DTLS. */
+ *out = method->is_dtls ? TLS1_1_VERSION : TLS1_VERSION;
+ return 1;
+ }
+
+ return set_version_bound(method, out, version);
+}
+
+static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
+ uint16_t version) {
+ /* Zero is interpreted as the default maximum version. */
+ if (version == 0) {
+ *out = TLS1_2_VERSION;
+ return 1;
+ }
+
+ return set_version_bound(method, out, version);
+}
+
+int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, uint16_t version) {
+ return set_min_version(ctx->method, &ctx->conf_min_version, version);
+}
+
+int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, uint16_t version) {
+ return set_max_version(ctx->method, &ctx->conf_max_version, version);
+}
+
+int SSL_set_min_proto_version(SSL *ssl, uint16_t version) {
+ return set_min_version(ssl->method, &ssl->conf_min_version, version);
+}
+
+int SSL_set_max_proto_version(SSL *ssl, uint16_t version) {
+ return set_max_version(ssl->method, &ssl->conf_max_version, version);
+}
+
+const struct {
+ uint16_t version;
+ uint32_t flag;
+} kProtocolVersions[] = {
+ {SSL3_VERSION, SSL_OP_NO_SSLv3},
+ {TLS1_VERSION, SSL_OP_NO_TLSv1},
+ {TLS1_1_VERSION, SSL_OP_NO_TLSv1_1},
+ {TLS1_2_VERSION, SSL_OP_NO_TLSv1_2},
+ {TLS1_3_VERSION, SSL_OP_NO_TLSv1_3},
+};
+
+int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
+ uint16_t *out_max_version) {
+ /* For historical reasons, |SSL_OP_NO_DTLSv1| aliases |SSL_OP_NO_TLSv1|, but
+ * DTLS 1.0 should be mapped to TLS 1.1. */
+ uint32_t options = ssl->options;
+ if (SSL_is_dtls(ssl)) {
+ options &= ~SSL_OP_NO_TLSv1_1;
+ if (options & SSL_OP_NO_DTLSv1) {
+ options |= SSL_OP_NO_TLSv1_1;
+ }
+ }
+
+ uint16_t min_version = ssl->conf_min_version;
+ uint16_t max_version = ssl->conf_max_version;
+
+ /* OpenSSL's API for controlling versions entails blacklisting individual
+ * protocols. This has two problems. First, on the client, the protocol can
+ * only express a contiguous range of versions. Second, a library consumer
+ * trying to set a maximum version cannot disable protocol versions that get
+ * added in a future version of the library.
+ *
+ * To account for both of these, OpenSSL interprets the client-side bitmask
+ * as a min/max range by picking the lowest contiguous non-empty range of
+ * enabled protocols. Note that this means it is impossible to set a maximum
+ * version of the higest supported TLS version in a future-proof way. */
+ int any_enabled = 0;
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kProtocolVersions); i++) {
+ /* Only look at the versions already enabled. */
+ if (min_version > kProtocolVersions[i].version) {
+ continue;
+ }
+ if (max_version < kProtocolVersions[i].version) {
+ break;
+ }
+
+ if (!(options & kProtocolVersions[i].flag)) {
+ /* The minimum version is the first enabled version. */
+ if (!any_enabled) {
+ any_enabled = 1;
+ min_version = kProtocolVersions[i].version;
+ }
+ continue;
+ }
+
+ /* If there is a disabled version after the first enabled one, all versions
+ * after it are implicitly disabled. */
+ if (any_enabled) {
+ max_version = kProtocolVersions[i-1].version;
+ break;
+ }
+ }
+
+ if (!any_enabled) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SUPPORTED_VERSIONS_ENABLED);
+ return 0;
+ }
+
+ *out_min_version = min_version;
+ *out_max_version = max_version;
+ return 1;
+}
+
+static uint16_t ssl_version(const SSL *ssl) {
+ /* In early data, we report the predicted version. */
+ if (SSL_in_early_data(ssl) && !ssl->server) {
+ return ssl->s3->hs->early_session->ssl_version;
+ }
+ return ssl->version;
+}
+
+int SSL_version(const SSL *ssl) {
+ uint16_t ret = ssl_version(ssl);
+ /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */
+ if (ret == TLS1_3_DRAFT_VERSION) {
+ return TLS1_3_VERSION;
+ }
+ return ret;
+}
+
+static const char *ssl_get_version(int version) {
+ switch (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:
+ return "TLSv1.2";
+
+ case TLS1_1_VERSION:
+ return "TLSv1.1";
+
+ case TLS1_VERSION:
+ return "TLSv1";
+
+ case SSL3_VERSION:
+ return "SSLv3";
+
+ case DTLS1_VERSION:
+ return "DTLSv1";
+
+ case DTLS1_2_VERSION:
+ return "DTLSv1.2";
+
+ default:
+ return "unknown";
+ }
+}
+
+const char *SSL_get_version(const SSL *ssl) {
+ return ssl_get_version(ssl_version(ssl));
+}
+
+const char *SSL_SESSION_get_version(const SSL_SESSION *session) {
+ return ssl_get_version(session->ssl_version);
+}
+
+uint16_t ssl3_protocol_version(const SSL *ssl) {
+ assert(ssl->s3->have_version);
+ uint16_t version;
+ if (!ssl_protocol_version_from_wire(&version, ssl->version)) {
+ /* |ssl->version| will always be set to a valid version. */
+ assert(0);
+ return 0;
+ }
+
+ return version;
+}
+
+int ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) {
+ uint16_t protocol_version;
+ return method_supports_version(hs->ssl->method, version) &&
+ ssl_protocol_version_from_wire(&protocol_version, version) &&
+ hs->min_version <= protocol_version &&
+ protocol_version <= hs->max_version;
+}
+
+int ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb) {
+ const uint16_t *versions;
+ size_t num_versions;
+ get_method_versions(hs->ssl->method, &versions, &num_versions);
+ for (size_t i = 0; i < num_versions; i++) {
+ if (ssl_supports_version(hs, versions[i]) &&
+ !CBB_add_u16(cbb, versions[i])) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
+ uint16_t *out_version, const CBS *peer_versions) {
+ const uint16_t *versions;
+ size_t num_versions;
+ get_method_versions(hs->ssl->method, &versions, &num_versions);
+ for (size_t i = 0; i < num_versions; i++) {
+ if (!ssl_supports_version(hs, versions[i])) {
+ continue;
+ }
+
+ CBS copy = *peer_versions;
+ while (CBS_len(©) != 0) {
+ uint16_t version;
+ if (!CBS_get_u16(©, &version)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (version == versions[i]) {
+ *out_version = version;
+ return 1;
+ }
+ }
+ }
+
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
+ *out_alert = SSL_AD_PROTOCOL_VERSION;
+ return 0;
+}
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index 1b14371..8e858c4 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -799,16 +799,24 @@
}
const uint8_t *d = CBS_data(&renegotiated_connection);
- if (CRYPTO_memcmp(d, ssl->s3->previous_client_finished,
- ssl->s3->previous_client_finished_len)) {
+ int ok = CRYPTO_memcmp(d, ssl->s3->previous_client_finished,
+ ssl->s3->previous_client_finished_len) == 0;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ ok = 1;
+#endif
+ if (!ok) {
OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
*out_alert = SSL_AD_HANDSHAKE_FAILURE;
return 0;
}
d += ssl->s3->previous_client_finished_len;
- if (CRYPTO_memcmp(d, ssl->s3->previous_server_finished,
- ssl->s3->previous_server_finished_len)) {
+ ok = CRYPTO_memcmp(d, ssl->s3->previous_server_finished,
+ ssl->s3->previous_server_finished_len) == 0;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ ok = 1;
+#endif
+ if (!ok) {
OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
@@ -970,14 +978,11 @@
* advertise the extension to avoid potentially breaking servers which carry
* over the state from the previous handshake, such as OpenSSL servers
* without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */
- uint16_t session_version;
if (!ssl->s3->initial_handshake_complete &&
ssl->session != NULL &&
ssl->session->tlsext_tick != NULL &&
/* Don't send TLS 1.3 session tickets in the ticket extension. */
- ssl->method->version_from_wire(&session_version,
- ssl->session->ssl_version) &&
- session_version < TLS1_3_VERSION) {
+ SSL_SESSION_protocol_version(ssl->session) < TLS1_3_VERSION) {
ticket_data = ssl->session->tlsext_tick;
ticket_len = ssl->session->tlsext_ticklen;
}
@@ -1863,31 +1868,19 @@
static size_t ext_pre_shared_key_clienthello_length(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- uint16_t session_version;
if (hs->max_version < TLS1_3_VERSION || ssl->session == NULL ||
- !ssl->method->version_from_wire(&session_version,
- ssl->session->ssl_version) ||
- session_version < TLS1_3_VERSION) {
+ SSL_SESSION_protocol_version(ssl->session) < TLS1_3_VERSION) {
return 0;
}
- const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
- if (digest == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- size_t binder_len = EVP_MD_size(digest);
+ size_t binder_len = EVP_MD_size(SSL_SESSION_get_digest(ssl->session));
return 15 + ssl->session->tlsext_ticklen + binder_len;
}
static int ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
SSL *const ssl = hs->ssl;
- uint16_t session_version;
if (hs->max_version < TLS1_3_VERSION || ssl->session == NULL ||
- !ssl->method->version_from_wire(&session_version,
- ssl->session->ssl_version) ||
- session_version < TLS1_3_VERSION) {
+ SSL_SESSION_protocol_version(ssl->session) < TLS1_3_VERSION) {
return 1;
}
@@ -1899,14 +1892,7 @@
/* Fill in a placeholder zero binder of the appropriate length. It will be
* computed and filled in later after length prefixes are computed. */
uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0};
-
- const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
- if (digest == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- size_t binder_len = EVP_MD_size(digest);
+ size_t binder_len = EVP_MD_size(SSL_SESSION_get_digest(ssl->session));
CBB contents, identity, ticket, binders, binder;
if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) ||
@@ -2071,11 +2057,8 @@
static int ext_early_data_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
SSL *const ssl = hs->ssl;
- uint16_t session_version;
if (ssl->session == NULL ||
- !ssl->method->version_from_wire(&session_version,
- ssl->session->ssl_version) ||
- session_version < TLS1_3_VERSION ||
+ SSL_SESSION_protocol_version(ssl->session) < TLS1_3_VERSION ||
ssl->session->ticket_max_early_data == 0 ||
hs->received_hello_retry_request ||
!ssl->cert->enable_early_data) {
@@ -2375,14 +2358,8 @@
return 0;
}
- for (uint16_t version = hs->max_version; version >= hs->min_version;
- version--) {
- if (!CBB_add_u16(&versions, ssl->method->version_to_wire(version))) {
- return 0;
- }
- }
-
- if (!CBB_flush(out)) {
+ if (!ssl_add_supported_versions(hs, &versions) ||
+ !CBB_flush(out)) {
return 0;
}
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 3cb2856..6d3e6d1 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -62,6 +62,7 @@
#include "../../crypto/internal.h"
#include "../internal.h"
#include "async_bio.h"
+#include "fuzzer.h"
#include "packeted_bio.h"
#include "test_config.h"
@@ -1371,6 +1372,13 @@
return false;
}
+ if (config->expect_version != 0 &&
+ SSL_version(ssl) != config->expect_version) {
+ fprintf(stderr, "want version %04x, got %04x\n", config->expect_version,
+ SSL_version(ssl));
+ return false;
+ }
+
bool expect_resume =
is_resume && (!config->expect_session_miss || SSL_in_early_data(ssl));
if (!!SSL_session_reused(ssl) != expect_resume) {
@@ -1645,6 +1653,61 @@
return true;
}
+static bool WriteSettings(int i, const TestConfig *config,
+ const SSL_SESSION *session) {
+ if (config->write_settings.empty()) {
+ return true;
+ }
+
+ // Treat write_settings as a path prefix for each connection in the run.
+ char buf[DECIMAL_SIZE(int)];
+ snprintf(buf, sizeof(buf), "%d", i);
+ std::string path = config->write_settings + buf;
+
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 64)) {
+ return false;
+ }
+
+ if (session != nullptr) {
+ uint8_t *data;
+ size_t len;
+ if (!SSL_SESSION_to_bytes(session, &data, &len)) {
+ return false;
+ }
+ bssl::UniquePtr<uint8_t> free_data(data);
+ CBB child;
+ if (!CBB_add_u16(cbb.get(), kSessionTag) ||
+ !CBB_add_u24_length_prefixed(cbb.get(), &child) ||
+ !CBB_add_bytes(&child, data, len) ||
+ !CBB_flush(cbb.get())) {
+ return false;
+ }
+ }
+
+ if (config->is_server &&
+ (config->require_any_client_certificate || config->verify_peer) &&
+ !CBB_add_u16(cbb.get(), kRequestClientCert)) {
+ return false;
+ }
+
+ uint8_t *settings;
+ size_t settings_len;
+ if (!CBB_add_u16(cbb.get(), kDataTag) ||
+ !CBB_finish(cbb.get(), &settings, &settings_len)) {
+ return false;
+ }
+ bssl::UniquePtr<uint8_t> free_settings(settings);
+
+ using ScopedFILE = std::unique_ptr<FILE, decltype(&fclose)>;
+ ScopedFILE file(fopen(path.c_str(), "w"), fclose);
+ if (!file) {
+ return false;
+ }
+
+ return fwrite(settings, settings_len, 1, file.get()) == 1;
+}
+
static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, SSL *ssl,
const TestConfig *config, bool is_resume, bool is_retry);
@@ -1683,12 +1746,20 @@
SSL_set_cert_cb(ssl.get(), CertCallback, nullptr);
}
if (config->require_any_client_certificate) {
- SSL_set_verify(ssl.get(), SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ SSL_set_verify(ssl.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
NULL);
}
if (config->verify_peer) {
SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, NULL);
}
+ if (config->verify_peer_if_no_obc) {
+ // Set SSL_VERIFY_FAIL_IF_NO_PEER_CERT so testing whether client
+ // certificates were requested is easy.
+ SSL_set_verify(ssl.get(),
+ SSL_VERIFY_PEER | SSL_VERIFY_PEER_IF_NO_OBC |
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ NULL);
+ }
if (config->false_start) {
SSL_set_mode(ssl.get(), SSL_MODE_ENABLE_FALSE_START);
}
@@ -2227,6 +2298,10 @@
}
bssl::UniquePtr<SSL_SESSION> offer_session = std::move(session);
+ if (!WriteSettings(i, config, offer_session.get())) {
+ fprintf(stderr, "Error writing settings.\n");
+ return 1;
+ }
if (!DoConnection(&session, ssl_ctx.get(), config, &retry_config, is_resume,
offer_session.get())) {
fprintf(stderr, "Connection %d failed.\n", i + 1);
diff --git a/src/ssl/test/fuzzer.h b/src/ssl/test/fuzzer.h
new file mode 100644
index 0000000..2f81653
--- /dev/null
+++ b/src/ssl/test/fuzzer.h
@@ -0,0 +1,271 @@
+/* Copyright (c) 2017, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef HEADER_SSL_TEST_FUZZER
+#define HEADER_SSL_TEST_FUZZER
+
+#include <openssl/bytestring.h>
+#include <openssl/ssl.h>
+
+
+// SSL fuzzer utilities.
+//
+// The TLS client and server fuzzers coordinate with bssl_shim on a common
+// format to encode configuration parameters in a fuzzer file. To add a new
+// configuration, define a tag, update |SetupTest| below to parse it, and
+// update |WriteSettings| in bssl_shim to serialize it. Finally, record
+// transcripts from a test run, and use the BORINGSSL_FUZZER_DEBUG environment
+// variable to confirm the transcripts are compatible.
+
+// kDataTag denotes that the remainder of the input should be passed to the TLS
+// stack.
+static const uint16_t kDataTag = 0;
+
+// kSessionTag is followed by a u24-length-prefixed serialized SSL_SESSION to
+// resume.
+static const uint16_t kSessionTag = 1;
+
+// kRequestClientCert denotes that the server should request client
+// certificates.
+static const uint16_t kRequestClientCert = 2;
+
+// SetupTest parses parameters from |cbs| and returns a newly-configured |SSL|
+// object or nullptr on error. On success, the caller should feed the remaining
+// input in |cbs| to the SSL stack.
+static inline bssl::UniquePtr<SSL> SetupTest(CBS *cbs, SSL_CTX *ctx,
+ bool is_server) {
+ // Clear any sessions saved in |ctx| from the previous run.
+ SSL_CTX_flush_sessions(ctx, 0);
+
+ bssl::UniquePtr<SSL> ssl(SSL_new(ctx));
+ if (is_server) {
+ SSL_set_accept_state(ssl.get());
+ } else {
+ SSL_set_connect_state(ssl.get());
+ }
+
+ for (;;) {
+ uint16_t tag;
+ if (!CBS_get_u16(cbs, &tag)) {
+ return nullptr;
+ }
+ switch (tag) {
+ case kDataTag:
+ return ssl;
+
+ case kSessionTag: {
+ CBS data;
+ if (!CBS_get_u24_length_prefixed(cbs, &data)) {
+ return nullptr;
+ }
+ bssl::UniquePtr<SSL_SESSION> session(
+ SSL_SESSION_from_bytes(CBS_data(&data), CBS_len(&data), ctx));
+ if (!session) {
+ return nullptr;
+ }
+
+ if (is_server) {
+ SSL_CTX_add_session(ctx, session.get());
+ } else {
+ SSL_set_session(ssl.get(), session.get());
+ }
+ break;
+ }
+
+ case kRequestClientCert:
+ if (!is_server) {
+ return nullptr;
+ }
+ SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, nullptr);
+ break;
+ }
+ }
+}
+
+
+// Additional shared constants.
+
+static const uint8_t kCertificateDER[] = {
+ 0x30, 0x82, 0x02, 0xff, 0x30, 0x82, 0x01, 0xe7, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x11, 0x00, 0xb1, 0x84, 0xee, 0x34, 0x99, 0x98, 0x76, 0xfb,
+ 0x6f, 0xb2, 0x15, 0xc8, 0x47, 0x79, 0x05, 0x9b, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
+ 0x12, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07,
+ 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+ 0x35, 0x31, 0x31, 0x30, 0x37, 0x30, 0x30, 0x32, 0x34, 0x35, 0x36, 0x5a,
+ 0x17, 0x0d, 0x31, 0x36, 0x31, 0x31, 0x30, 0x36, 0x30, 0x30, 0x32, 0x34,
+ 0x35, 0x36, 0x5a, 0x30, 0x12, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x30,
+ 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
+ 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xce, 0x47, 0xcb, 0x11,
+ 0xbb, 0xd2, 0x9d, 0x8e, 0x9e, 0xd2, 0x1e, 0x14, 0xaf, 0xc7, 0xea, 0xb6,
+ 0xc9, 0x38, 0x2a, 0x6f, 0xb3, 0x7e, 0xfb, 0xbc, 0xfc, 0x59, 0x42, 0xb9,
+ 0x56, 0xf0, 0x4c, 0x3f, 0xf7, 0x31, 0x84, 0xbe, 0xac, 0x03, 0x9e, 0x71,
+ 0x91, 0x85, 0xd8, 0x32, 0xbd, 0x00, 0xea, 0xac, 0x65, 0xf6, 0x03, 0xc8,
+ 0x0f, 0x8b, 0xfd, 0x6e, 0x58, 0x88, 0x04, 0x41, 0x92, 0x74, 0xa6, 0x57,
+ 0x2e, 0x8e, 0x88, 0xd5, 0x3d, 0xda, 0x14, 0x3e, 0x63, 0x88, 0x22, 0xe3,
+ 0x53, 0xe9, 0xba, 0x39, 0x09, 0xac, 0xfb, 0xd0, 0x4c, 0xf2, 0x3c, 0x20,
+ 0xd6, 0x97, 0xe6, 0xed, 0xf1, 0x62, 0x1e, 0xe5, 0xc9, 0x48, 0xa0, 0xca,
+ 0x2e, 0x3c, 0x14, 0x5a, 0x82, 0xd4, 0xed, 0xb1, 0xe3, 0x43, 0xc1, 0x2a,
+ 0x59, 0xa5, 0xb9, 0xc8, 0x48, 0xa7, 0x39, 0x23, 0x74, 0xa7, 0x37, 0xb0,
+ 0x6f, 0xc3, 0x64, 0x99, 0x6c, 0xa2, 0x82, 0xc8, 0xf6, 0xdb, 0x86, 0x40,
+ 0xce, 0xd1, 0x85, 0x9f, 0xce, 0x69, 0xf4, 0x15, 0x2a, 0x23, 0xca, 0xea,
+ 0xb7, 0x7b, 0xdf, 0xfb, 0x43, 0x5f, 0xff, 0x7a, 0x49, 0x49, 0x0e, 0xe7,
+ 0x02, 0x51, 0x45, 0x13, 0xe8, 0x90, 0x64, 0x21, 0x0c, 0x26, 0x2b, 0x5d,
+ 0xfc, 0xe4, 0xb5, 0x86, 0x89, 0x43, 0x22, 0x4c, 0xf3, 0x3b, 0xf3, 0x09,
+ 0xc4, 0xa4, 0x10, 0x80, 0xf2, 0x46, 0xe2, 0x46, 0x8f, 0x76, 0x50, 0xbf,
+ 0xaf, 0x2b, 0x90, 0x1b, 0x78, 0xc7, 0xcf, 0xc1, 0x77, 0xd0, 0xfb, 0xa9,
+ 0xfb, 0xc9, 0x66, 0x5a, 0xc5, 0x9b, 0x31, 0x41, 0x67, 0x01, 0xbe, 0x33,
+ 0x10, 0xba, 0x05, 0x58, 0xed, 0x76, 0x53, 0xde, 0x5d, 0xc1, 0xe8, 0xbb,
+ 0x9f, 0xf1, 0xcd, 0xfb, 0xdf, 0x64, 0x7f, 0xd7, 0x18, 0xab, 0x0f, 0x94,
+ 0x28, 0x95, 0x4a, 0xcc, 0x6a, 0xa9, 0x50, 0xc7, 0x05, 0x47, 0x10, 0x41,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x0e, 0x06,
+ 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05,
+ 0xa0, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a,
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x0c,
+ 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
+ 0x30, 0x19, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x12, 0x30, 0x10, 0x82,
+ 0x0e, 0x66, 0x75, 0x7a, 0x7a, 0x2e, 0x62, 0x6f, 0x72, 0x69, 0x6e, 0x67,
+ 0x73, 0x73, 0x6c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x92,
+ 0xde, 0xef, 0x96, 0x06, 0x7b, 0xff, 0x71, 0x7d, 0x4e, 0xa0, 0x7d, 0xae,
+ 0xb8, 0x22, 0xb4, 0x2c, 0xf7, 0x96, 0x9c, 0x37, 0x1d, 0x8f, 0xe7, 0xd9,
+ 0x47, 0xff, 0x3f, 0xe9, 0x35, 0x95, 0x0e, 0xdd, 0xdc, 0x7f, 0xc8, 0x8a,
+ 0x1e, 0x36, 0x1d, 0x38, 0x47, 0xfc, 0x76, 0xd2, 0x1f, 0x98, 0xa1, 0x36,
+ 0xac, 0xc8, 0x70, 0x38, 0x0a, 0x3d, 0x51, 0x8d, 0x0f, 0x03, 0x1b, 0xef,
+ 0x62, 0xa1, 0xcb, 0x2b, 0x4a, 0x8c, 0x12, 0x2b, 0x54, 0x50, 0x9a, 0x6b,
+ 0xfe, 0xaf, 0xd9, 0xf6, 0xbf, 0x58, 0x11, 0x58, 0x5e, 0xe5, 0x86, 0x1e,
+ 0x3b, 0x6b, 0x30, 0x7e, 0x72, 0x89, 0xe8, 0x6b, 0x7b, 0xb7, 0xaf, 0xef,
+ 0x8b, 0xa9, 0x3e, 0xb0, 0xcd, 0x0b, 0xef, 0xb0, 0x0c, 0x96, 0x2b, 0xc5,
+ 0x3b, 0xd5, 0xf1, 0xc2, 0xae, 0x3a, 0x60, 0xd9, 0x0f, 0x75, 0x37, 0x55,
+ 0x4d, 0x62, 0xd2, 0xed, 0x96, 0xac, 0x30, 0x6b, 0xda, 0xa1, 0x48, 0x17,
+ 0x96, 0x23, 0x85, 0x9a, 0x57, 0x77, 0xe9, 0x22, 0xa2, 0x37, 0x03, 0xba,
+ 0x49, 0x77, 0x40, 0x3b, 0x76, 0x4b, 0xda, 0xc1, 0x04, 0x57, 0x55, 0x34,
+ 0x22, 0x83, 0x45, 0x29, 0xab, 0x2e, 0x11, 0xff, 0x0d, 0xab, 0x55, 0xb1,
+ 0xa7, 0x58, 0x59, 0x05, 0x25, 0xf9, 0x1e, 0x3d, 0xb7, 0xac, 0x04, 0x39,
+ 0x2c, 0xf9, 0xaf, 0xb8, 0x68, 0xfb, 0x8e, 0x35, 0x71, 0x32, 0xff, 0x70,
+ 0xe9, 0x46, 0x6d, 0x5c, 0x06, 0x90, 0x88, 0x23, 0x48, 0x0c, 0x50, 0xeb,
+ 0x0a, 0xa9, 0xae, 0xe8, 0xfc, 0xbe, 0xa5, 0x76, 0x94, 0xd7, 0x64, 0x22,
+ 0x38, 0x98, 0x17, 0xa4, 0x3a, 0xa7, 0x59, 0x9f, 0x1d, 0x3b, 0x75, 0x90,
+ 0x1a, 0x81, 0xef, 0x19, 0xfb, 0x2b, 0xb7, 0xa7, 0x64, 0x61, 0x22, 0xa4,
+ 0x6f, 0x7b, 0xfa, 0x58, 0xbb, 0x8c, 0x4e, 0x77, 0x67, 0xd0, 0x5d, 0x58,
+ 0x76, 0x8a, 0xbb,
+};
+
+static const uint8_t kRSAPrivateKeyDER[] = {
+ 0x30, 0x82, 0x04, 0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
+ 0xce, 0x47, 0xcb, 0x11, 0xbb, 0xd2, 0x9d, 0x8e, 0x9e, 0xd2, 0x1e, 0x14,
+ 0xaf, 0xc7, 0xea, 0xb6, 0xc9, 0x38, 0x2a, 0x6f, 0xb3, 0x7e, 0xfb, 0xbc,
+ 0xfc, 0x59, 0x42, 0xb9, 0x56, 0xf0, 0x4c, 0x3f, 0xf7, 0x31, 0x84, 0xbe,
+ 0xac, 0x03, 0x9e, 0x71, 0x91, 0x85, 0xd8, 0x32, 0xbd, 0x00, 0xea, 0xac,
+ 0x65, 0xf6, 0x03, 0xc8, 0x0f, 0x8b, 0xfd, 0x6e, 0x58, 0x88, 0x04, 0x41,
+ 0x92, 0x74, 0xa6, 0x57, 0x2e, 0x8e, 0x88, 0xd5, 0x3d, 0xda, 0x14, 0x3e,
+ 0x63, 0x88, 0x22, 0xe3, 0x53, 0xe9, 0xba, 0x39, 0x09, 0xac, 0xfb, 0xd0,
+ 0x4c, 0xf2, 0x3c, 0x20, 0xd6, 0x97, 0xe6, 0xed, 0xf1, 0x62, 0x1e, 0xe5,
+ 0xc9, 0x48, 0xa0, 0xca, 0x2e, 0x3c, 0x14, 0x5a, 0x82, 0xd4, 0xed, 0xb1,
+ 0xe3, 0x43, 0xc1, 0x2a, 0x59, 0xa5, 0xb9, 0xc8, 0x48, 0xa7, 0x39, 0x23,
+ 0x74, 0xa7, 0x37, 0xb0, 0x6f, 0xc3, 0x64, 0x99, 0x6c, 0xa2, 0x82, 0xc8,
+ 0xf6, 0xdb, 0x86, 0x40, 0xce, 0xd1, 0x85, 0x9f, 0xce, 0x69, 0xf4, 0x15,
+ 0x2a, 0x23, 0xca, 0xea, 0xb7, 0x7b, 0xdf, 0xfb, 0x43, 0x5f, 0xff, 0x7a,
+ 0x49, 0x49, 0x0e, 0xe7, 0x02, 0x51, 0x45, 0x13, 0xe8, 0x90, 0x64, 0x21,
+ 0x0c, 0x26, 0x2b, 0x5d, 0xfc, 0xe4, 0xb5, 0x86, 0x89, 0x43, 0x22, 0x4c,
+ 0xf3, 0x3b, 0xf3, 0x09, 0xc4, 0xa4, 0x10, 0x80, 0xf2, 0x46, 0xe2, 0x46,
+ 0x8f, 0x76, 0x50, 0xbf, 0xaf, 0x2b, 0x90, 0x1b, 0x78, 0xc7, 0xcf, 0xc1,
+ 0x77, 0xd0, 0xfb, 0xa9, 0xfb, 0xc9, 0x66, 0x5a, 0xc5, 0x9b, 0x31, 0x41,
+ 0x67, 0x01, 0xbe, 0x33, 0x10, 0xba, 0x05, 0x58, 0xed, 0x76, 0x53, 0xde,
+ 0x5d, 0xc1, 0xe8, 0xbb, 0x9f, 0xf1, 0xcd, 0xfb, 0xdf, 0x64, 0x7f, 0xd7,
+ 0x18, 0xab, 0x0f, 0x94, 0x28, 0x95, 0x4a, 0xcc, 0x6a, 0xa9, 0x50, 0xc7,
+ 0x05, 0x47, 0x10, 0x41, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
+ 0x01, 0x00, 0xa8, 0x47, 0xb9, 0x4a, 0x06, 0x47, 0x93, 0x71, 0x3d, 0xef,
+ 0x7b, 0xca, 0xb4, 0x7c, 0x0a, 0xe6, 0x82, 0xd0, 0xe7, 0x0d, 0xa9, 0x08,
+ 0xf6, 0xa4, 0xfd, 0xd8, 0x73, 0xae, 0x6f, 0x56, 0x29, 0x5e, 0x25, 0x72,
+ 0xa8, 0x30, 0x44, 0x73, 0xcf, 0x56, 0x26, 0xb9, 0x61, 0xde, 0x42, 0x81,
+ 0xf4, 0xf0, 0x1f, 0x5d, 0xcb, 0x47, 0xf2, 0x26, 0xe9, 0xe0, 0x93, 0x28,
+ 0xa3, 0x10, 0x3b, 0x42, 0x1e, 0x51, 0x11, 0x12, 0x06, 0x5e, 0xaf, 0xce,
+ 0xb0, 0xa5, 0x14, 0xdd, 0x82, 0x58, 0xa1, 0xa4, 0x12, 0xdf, 0x65, 0x1d,
+ 0x51, 0x70, 0x64, 0xd5, 0x58, 0x68, 0x11, 0xa8, 0x6a, 0x23, 0xc2, 0xbf,
+ 0xa1, 0x25, 0x24, 0x47, 0xb3, 0xa4, 0x3c, 0x83, 0x96, 0xb7, 0x1f, 0xf4,
+ 0x44, 0xd4, 0xd1, 0xe9, 0xfc, 0x33, 0x68, 0x5e, 0xe2, 0x68, 0x99, 0x9c,
+ 0x91, 0xe8, 0x72, 0xc9, 0xd7, 0x8c, 0x80, 0x20, 0x8e, 0x77, 0x83, 0x4d,
+ 0xe4, 0xab, 0xf9, 0x74, 0xa1, 0xdf, 0xd3, 0xc0, 0x0d, 0x5b, 0x05, 0x51,
+ 0xc2, 0x6f, 0xb2, 0x91, 0x02, 0xec, 0xc0, 0x02, 0x1a, 0x5c, 0x91, 0x05,
+ 0xf1, 0xe3, 0xfa, 0x65, 0xc2, 0xad, 0x24, 0xe6, 0xe5, 0x3c, 0xb6, 0x16,
+ 0xf1, 0xa1, 0x67, 0x1a, 0x9d, 0x37, 0x56, 0xbf, 0x01, 0xd7, 0x3b, 0x35,
+ 0x30, 0x57, 0x73, 0xf4, 0xf0, 0x5e, 0xa7, 0xe8, 0x0a, 0xc1, 0x94, 0x17,
+ 0xcf, 0x0a, 0xbd, 0xf5, 0x31, 0xa7, 0x2d, 0xf7, 0xf5, 0xd9, 0x8c, 0xc2,
+ 0x01, 0xbd, 0xda, 0x16, 0x8e, 0xb9, 0x30, 0x40, 0xa6, 0x6e, 0xbd, 0xcd,
+ 0x4d, 0x84, 0x67, 0x4e, 0x0b, 0xce, 0xd5, 0xef, 0xf8, 0x08, 0x63, 0x02,
+ 0xc6, 0xc7, 0xf7, 0x67, 0x92, 0xe2, 0x23, 0x9d, 0x27, 0x22, 0x1d, 0xc6,
+ 0x67, 0x5e, 0x66, 0xbf, 0x03, 0xb8, 0xa9, 0x67, 0xd4, 0x39, 0xd8, 0x75,
+ 0xfa, 0xe8, 0xed, 0x56, 0xb8, 0x81, 0x02, 0x81, 0x81, 0x00, 0xf7, 0x46,
+ 0x68, 0xc6, 0x13, 0xf8, 0xba, 0x0f, 0x83, 0xdb, 0x05, 0xa8, 0x25, 0x00,
+ 0x70, 0x9c, 0x9e, 0x8b, 0x12, 0x34, 0x0d, 0x96, 0xcf, 0x0d, 0x98, 0x9b,
+ 0x8d, 0x9c, 0x96, 0x78, 0xd1, 0x3c, 0x01, 0x8c, 0xb9, 0x35, 0x5c, 0x20,
+ 0x42, 0xb4, 0x38, 0xe3, 0xd6, 0x54, 0xe7, 0x55, 0xd6, 0x26, 0x8a, 0x0c,
+ 0xf6, 0x1f, 0xe0, 0x04, 0xc1, 0x22, 0x42, 0x19, 0x61, 0xc4, 0x94, 0x7c,
+ 0x07, 0x2e, 0x80, 0x52, 0xfe, 0x8d, 0xe6, 0x92, 0x3a, 0x91, 0xfe, 0x72,
+ 0x99, 0xe1, 0x2a, 0x73, 0x76, 0xb1, 0x24, 0x20, 0x67, 0xde, 0x28, 0xcb,
+ 0x0e, 0xe6, 0x52, 0xb5, 0xfa, 0xfb, 0x8b, 0x1e, 0x6a, 0x1d, 0x09, 0x26,
+ 0xb9, 0xa7, 0x61, 0xba, 0xf8, 0x79, 0xd2, 0x66, 0x57, 0x28, 0xd7, 0x31,
+ 0xb5, 0x0b, 0x27, 0x19, 0x1e, 0x6f, 0x46, 0xfc, 0x54, 0x95, 0xeb, 0x78,
+ 0x01, 0xb6, 0xd9, 0x79, 0x5a, 0x4d, 0x02, 0x81, 0x81, 0x00, 0xd5, 0x8f,
+ 0x16, 0x53, 0x2f, 0x57, 0x93, 0xbf, 0x09, 0x75, 0xbf, 0x63, 0x40, 0x3d,
+ 0x27, 0xfd, 0x23, 0x21, 0xde, 0x9b, 0xe9, 0x73, 0x3f, 0x49, 0x02, 0xd2,
+ 0x38, 0x96, 0xcf, 0xc3, 0xba, 0x92, 0x07, 0x87, 0x52, 0xa9, 0x35, 0xe3,
+ 0x0c, 0xe4, 0x2f, 0x05, 0x7b, 0x37, 0xa5, 0x40, 0x9c, 0x3b, 0x94, 0xf7,
+ 0xad, 0xa0, 0xee, 0x3a, 0xa8, 0xfb, 0x1f, 0x11, 0x1f, 0xd8, 0x9a, 0x80,
+ 0x42, 0x3d, 0x7f, 0xa4, 0xb8, 0x9a, 0xaa, 0xea, 0x72, 0xc1, 0xe3, 0xed,
+ 0x06, 0x60, 0x92, 0x37, 0xf9, 0xba, 0xfb, 0x9e, 0xed, 0x05, 0xa6, 0xd4,
+ 0x72, 0x68, 0x4f, 0x63, 0xfe, 0xd6, 0x10, 0x0d, 0x4f, 0x0a, 0x93, 0xc6,
+ 0xb9, 0xd7, 0xaf, 0xfd, 0xd9, 0x57, 0x7d, 0xcb, 0x75, 0xe8, 0x93, 0x2b,
+ 0xae, 0x4f, 0xea, 0xd7, 0x30, 0x0b, 0x58, 0x44, 0x82, 0x0f, 0x84, 0x5d,
+ 0x62, 0x11, 0x78, 0xea, 0x5f, 0xc5, 0x02, 0x81, 0x81, 0x00, 0x82, 0x0c,
+ 0xc1, 0xe6, 0x0b, 0x72, 0xf1, 0x48, 0x5f, 0xac, 0xbd, 0x98, 0xe5, 0x7d,
+ 0x09, 0xbd, 0x15, 0x95, 0x47, 0x09, 0xa1, 0x6c, 0x03, 0x91, 0xbf, 0x05,
+ 0x70, 0xc1, 0x3e, 0x52, 0x64, 0x99, 0x0e, 0xa7, 0x98, 0x70, 0xfb, 0xf6,
+ 0xeb, 0x9e, 0x25, 0x9d, 0x8e, 0x88, 0x30, 0xf2, 0xf0, 0x22, 0x6c, 0xd0,
+ 0xcc, 0x51, 0x8f, 0x5c, 0x70, 0xc7, 0x37, 0xc4, 0x69, 0xab, 0x1d, 0xfc,
+ 0xed, 0x3a, 0x03, 0xbb, 0xa2, 0xad, 0xb6, 0xea, 0x89, 0x6b, 0x67, 0x4b,
+ 0x96, 0xaa, 0xd9, 0xcc, 0xc8, 0x4b, 0xfa, 0x18, 0x21, 0x08, 0xb2, 0xa3,
+ 0xb9, 0x3e, 0x61, 0x99, 0xdc, 0x5a, 0x97, 0x9c, 0x73, 0x6a, 0xb9, 0xf9,
+ 0x68, 0x03, 0x24, 0x5f, 0x55, 0x77, 0x9c, 0xb4, 0xbe, 0x7a, 0x78, 0x53,
+ 0x68, 0x48, 0x69, 0x53, 0xc8, 0xb1, 0xf5, 0xbf, 0x98, 0x2d, 0x11, 0x1e,
+ 0x98, 0xa8, 0x36, 0x50, 0xa0, 0xb1, 0x02, 0x81, 0x81, 0x00, 0x90, 0x88,
+ 0x30, 0x71, 0xc7, 0xfe, 0x9b, 0x6d, 0x95, 0x37, 0x6d, 0x79, 0xfc, 0x85,
+ 0xe7, 0x44, 0x78, 0xbc, 0x79, 0x6e, 0x47, 0x86, 0xc9, 0xf3, 0xdd, 0xc6,
+ 0xec, 0xa9, 0x94, 0x9f, 0x40, 0xeb, 0x87, 0xd0, 0xdb, 0xee, 0xcd, 0x1b,
+ 0x87, 0x23, 0xff, 0x76, 0xd4, 0x37, 0x8a, 0xcd, 0xb9, 0x6e, 0xd1, 0x98,
+ 0xf6, 0x97, 0x8d, 0xe3, 0x81, 0x6d, 0xc3, 0x4e, 0xd1, 0xa0, 0xc4, 0x9f,
+ 0xbd, 0x34, 0xe5, 0xe8, 0x53, 0x4f, 0xca, 0x10, 0xb5, 0xed, 0xe7, 0x16,
+ 0x09, 0x54, 0xde, 0x60, 0xa7, 0xd1, 0x16, 0x6e, 0x2e, 0xb7, 0xbe, 0x7a,
+ 0xd5, 0x9b, 0x26, 0xef, 0xe4, 0x0e, 0x77, 0xfa, 0xa9, 0xdd, 0xdc, 0xb9,
+ 0x88, 0x19, 0x23, 0x70, 0xc7, 0xe1, 0x60, 0xaf, 0x8c, 0x73, 0x04, 0xf7,
+ 0x71, 0x17, 0x81, 0x36, 0x75, 0xbb, 0x97, 0xd7, 0x75, 0xb6, 0x8e, 0xbc,
+ 0xac, 0x9c, 0x6a, 0x9b, 0x24, 0x89, 0x02, 0x81, 0x80, 0x5a, 0x2b, 0xc7,
+ 0x6b, 0x8c, 0x65, 0xdb, 0x04, 0x73, 0xab, 0x25, 0xe1, 0x5b, 0xbc, 0x3c,
+ 0xcf, 0x5a, 0x3c, 0x04, 0xae, 0x97, 0x2e, 0xfd, 0xa4, 0x97, 0x1f, 0x05,
+ 0x17, 0x27, 0xac, 0x7c, 0x30, 0x85, 0xb4, 0x82, 0x3f, 0x5b, 0xb7, 0x94,
+ 0x3b, 0x7f, 0x6c, 0x0c, 0xc7, 0x16, 0xc6, 0xa0, 0xbd, 0x80, 0xb0, 0x81,
+ 0xde, 0xa0, 0x23, 0xa6, 0xf6, 0x75, 0x33, 0x51, 0x35, 0xa2, 0x75, 0x55,
+ 0x70, 0x4d, 0x42, 0xbb, 0xcf, 0x54, 0xe4, 0xdb, 0x2d, 0x88, 0xa0, 0x7a,
+ 0xf2, 0x17, 0xa7, 0xdd, 0x13, 0x44, 0x9f, 0x5f, 0x6b, 0x2c, 0x42, 0x42,
+ 0x8b, 0x13, 0x4d, 0xf9, 0x5b, 0xf8, 0x33, 0x42, 0xd9, 0x9e, 0x50, 0x1c,
+ 0x7c, 0xbc, 0xfa, 0x62, 0x85, 0x0b, 0xcf, 0x99, 0xda, 0x9e, 0x04, 0x90,
+ 0xb2, 0xc6, 0xb2, 0x0a, 0x2a, 0x7c, 0x6d, 0x6a, 0x40, 0xfc, 0xf5, 0x50,
+ 0x98, 0x46, 0x89, 0x82, 0x40,
+};
+
+
+#endif // HEADER_SSL_TEST_FUZZER
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 0a6648f..9e7b204 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -26,9 +26,27 @@
VersionTLS13 = 0x0304
)
+const (
+ VersionDTLS10 = 0xfeff
+ VersionDTLS12 = 0xfefd
+)
+
// A draft version of TLS 1.3 that is sent over the wire for the current draft.
const tls13DraftVersion = 0x7f12
+var allTLSWireVersions = []uint16{
+ tls13DraftVersion,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+ VersionSSL30,
+}
+
+var allDTLSWireVersions = []uint16{
+ VersionDTLS12,
+ VersionDTLS10,
+}
+
const (
maxPlaintext = 16384 // maximum plaintext payload length
maxCiphertext = 16384 + 2048 // maximum ciphertext payload length
@@ -625,12 +643,12 @@
SendSupportedVersions []uint16
// NegotiateVersion, if non-zero, causes the server to negotiate the
- // specifed TLS version rather than the version supported by either
+ // specifed wire version rather than the version supported by either
// peer.
NegotiateVersion uint16
// NegotiateVersionOnRenego, if non-zero, causes the server to negotiate
- // the specified TLS version on renegotiation rather than retaining it.
+ // the specified wire version on renegotiation rather than retaining it.
NegotiateVersionOnRenego uint16
// ExpectFalseStart causes the server to, on full handshakes,
@@ -710,9 +728,13 @@
EmptyRenegotiationInfo bool
// BadRenegotiationInfo causes the renegotiation extension value in a
- // renegotiation handshake to be incorrect.
+ // renegotiation handshake to be incorrect at the start.
BadRenegotiationInfo bool
+ // BadRenegotiationInfoEnd causes the renegotiation extension value in
+ // a renegotiation handshake to be incorrect at the end.
+ BadRenegotiationInfoEnd bool
+
// NoRenegotiationInfo disables renegotiation info support in all
// handshakes.
NoRenegotiationInfo bool
@@ -1257,6 +1279,10 @@
// send in the ClientHello.
SendCompressionMethods []byte
+ // SendCompressionMethod is the compression method to send in the
+ // ServerHello.
+ SendCompressionMethod byte
+
// AlwaysSendPreSharedKeyIdentityHint, if true, causes the server to
// always send a ServerKeyExchange for PSK ciphers, even if the identity
// hint is empty.
@@ -1438,10 +1464,29 @@
return defaultCurves
}
-// 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)
+// isSupportedVersion checks if the specified wire version is acceptable. If so,
+// it returns true and the corresponding protocol version. Otherwise, it returns
+// false.
+func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) {
+ vers, ok := wireToVersion(wireVers, isDTLS)
+ if !ok || c.minVersion(isDTLS) > vers || vers > c.maxVersion(isDTLS) {
+ return 0, false
+ }
+ return vers, true
+}
+
+func (c *Config) supportedVersions(isDTLS bool) []uint16 {
+ versions := allTLSWireVersions
+ if isDTLS {
+ versions = allDTLSWireVersions
+ }
+ var ret []uint16
+ for _, vers := range versions {
+ if _, ok := c.isSupportedVersion(vers, isDTLS); ok {
+ ret = append(ret, vers)
+ }
+ }
+ return ret
}
// getCertificateForName returns the best certificate for the given name,
@@ -1717,3 +1762,12 @@
downgradeTLS13 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01}
downgradeTLS12 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00}
)
+
+func containsGREASE(values []uint16) bool {
+ for _, v := range values {
+ if isGREASEValue(v) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index fce0049..61fc9d3 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -35,6 +35,7 @@
// constant after handshake; protected by handshakeMutex
handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
handshakeErr error // error resulting from handshake
+ wireVersion uint16 // TLS wire version
vers uint16 // TLS version
haveVers bool // version has been negotiated
config *Config // configuration passed to constructor
diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go
index e273bc7..d46b247 100644
--- a/src/ssl/test/runner/dtls.go
+++ b/src/ssl/test/runner/dtls.go
@@ -23,32 +23,12 @@
"net"
)
-func versionToWire(vers uint16, isDTLS bool) uint16 {
- if isDTLS {
- switch vers {
- case VersionTLS12:
- return 0xfefd
- case VersionTLS10:
- return 0xfeff
- }
- } else {
- switch vers {
- case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
- return vers
- case VersionTLS13:
- return tls13DraftVersion
- }
- }
-
- panic("unknown version")
-}
-
func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) {
if isDTLS {
switch vers {
- case 0xfefd:
+ case VersionDTLS12:
return VersionTLS12, true
- case 0xfeff:
+ case VersionDTLS10:
return VersionTLS10, true
}
} else {
@@ -102,9 +82,9 @@
// version is irrelevant.)
if typ != recordTypeAlert {
if c.haveVers {
- if wireVers := versionToWire(c.vers, c.isDTLS); vers != wireVers {
+ if vers != c.wireVersion {
c.sendAlert(alertProtocolVersion)
- return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: received record with version %x when expecting version %x", vers, wireVers))
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: received record with version %x when expecting version %x", vers, c.wireVersion))
}
} else {
// Pre-version-negotiation alerts may be sent with any version.
@@ -368,13 +348,16 @@
// TODO(nharper): DTLS 1.3 will likely need to set this to
// recordTypeApplicationData if c.out.cipher != nil.
b.data[0] = byte(typ)
- vers := c.vers
+ vers := c.wireVersion
if vers == 0 {
// Some TLS servers fail if the record version is greater than
// TLS 1.0 for the initial ClientHello.
- vers = VersionTLS10
+ if c.isDTLS {
+ vers = VersionDTLS10
+ } else {
+ vers = VersionTLS10
+ }
}
- vers = versionToWire(vers, c.isDTLS)
b.data[1] = byte(vers >> 8)
b.data[2] = byte(vers)
// DTLS records include an explicit sequence number.
diff --git a/src/ssl/test/runner/fuzzer_mode.json b/src/ssl/test/runner/fuzzer_mode.json
index fd819f9..d2f64ef 100644
--- a/src/ssl/test/runner/fuzzer_mode.json
+++ b/src/ssl/test/runner/fuzzer_mode.json
@@ -46,6 +46,8 @@
"TLS13-EarlyData-ALPNOmitted2-Server": "Trial decryption does not work with the NULL cipher.",
"TLS13-EarlyData-RejectUnfinishedWrite-Client-*": "Trial decryption does not work with the NULL cipher.",
"TLS13-EarlyData-Reject-Client": "Trial decryption does not work with the NULL cipher.",
- "TLS13-EarlyData-RejectTicket-Client": "Trial decryption does not work with the NULL cipher."
+ "TLS13-EarlyData-RejectTicket-Client": "Trial decryption does not work with the NULL cipher.",
+
+ "Renegotiate-Client-BadExt*": "Fuzzer mode does not check renegotiation_info."
}
}
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index c531a28..f0bfca4 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -35,6 +35,21 @@
finishedBytes []byte
}
+func mapClientHelloVersion(vers uint16, isDTLS bool) uint16 {
+ if !isDTLS {
+ return vers
+ }
+
+ switch vers {
+ case VersionTLS12:
+ return VersionDTLS12
+ case VersionTLS10:
+ return VersionDTLS10
+ }
+
+ panic("Unknown ClientHello version.")
+}
+
func (c *Conn) clientHandshake() error {
if c.config == nil {
c.config = defaultConfig()
@@ -63,7 +78,6 @@
maxVersion := c.config.maxVersion(c.isDTLS)
hello := &clientHelloMsg{
isDTLS: c.isDTLS,
- vers: versionToWire(maxVersion, c.isDTLS),
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
ocspStapling: !c.config.Bugs.NoOCSPStapling,
@@ -85,6 +99,23 @@
pskBinderFirst: c.config.Bugs.PSKBinderFirst,
}
+ if maxVersion >= VersionTLS13 {
+ hello.vers = mapClientHelloVersion(VersionTLS12, c.isDTLS)
+ if !c.config.Bugs.OmitSupportedVersions {
+ hello.supportedVersions = c.config.supportedVersions(c.isDTLS)
+ }
+ } else {
+ hello.vers = mapClientHelloVersion(maxVersion, c.isDTLS)
+ }
+
+ if c.config.Bugs.SendClientVersion != 0 {
+ hello.vers = c.config.Bugs.SendClientVersion
+ }
+
+ if len(c.config.Bugs.SendSupportedVersions) > 0 {
+ hello.supportedVersions = c.config.Bugs.SendSupportedVersions
+ }
+
disableEMS := c.config.Bugs.NoExtendedMasterSecret
if c.cipherSuite != nil {
disableEMS = c.config.Bugs.NoExtendedMasterSecretOnRenegotiation
@@ -310,23 +341,6 @@
}
}
- 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
- }
-
if c.config.Bugs.SendCipherSuites != nil {
hello.cipherSuites = c.config.Bugs.SendCipherSuites
}
@@ -409,7 +423,7 @@
if c.isDTLS {
helloVerifyRequest, ok := msg.(*helloVerifyRequestMsg)
if ok {
- if helloVerifyRequest.vers != versionToWire(VersionTLS10, c.isDTLS) {
+ if helloVerifyRequest.vers != VersionDTLS10 {
// Per RFC 6347, the version field in
// HelloVerifyRequest SHOULD be always DTLS
// 1.0. Enforce this for testing purposes.
@@ -443,14 +457,12 @@
return fmt.Errorf("tls: received unexpected message of type %T when waiting for HelloRetryRequest or ServerHello", msg)
}
- serverVersion, ok := wireToVersion(serverWireVersion, c.isDTLS)
- if ok {
- ok = c.config.isSupportedVersion(serverVersion, c.isDTLS)
- }
+ serverVersion, ok := c.config.isSupportedVersion(serverWireVersion, c.isDTLS)
if !ok {
c.sendAlert(alertProtocolVersion)
return fmt.Errorf("tls: server selected unsupported protocol version %x", c.vers)
}
+ c.wireVersion = serverWireVersion
c.vers = serverVersion
c.haveVers = true
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 3a182ec..f70f469 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -161,7 +161,7 @@
// Per RFC 6347, the version field in HelloVerifyRequest SHOULD
// be always DTLS 1.0
helloVerifyRequest := &helloVerifyRequestMsg{
- vers: versionToWire(VersionTLS10, c.isDTLS),
+ vers: VersionDTLS10,
cookie: make([]byte, 32),
}
if _, err := io.ReadFull(c.config.rand(), helloVerifyRequest.cookie); err != nil {
@@ -210,74 +210,69 @@
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 {
- clientVersion = VersionTLS12
- } else if hs.clientHello.vers <= 0xfeff {
- clientVersion = VersionTLS10
+ // Use the versions extension if supplied, otherwise use the legacy ClientHello version.
+ if len(hs.clientHello.supportedVersions) == 0 {
+ if c.isDTLS {
+ if hs.clientHello.vers <= VersionDTLS12 {
+ hs.clientHello.supportedVersions = append(hs.clientHello.supportedVersions, VersionDTLS12)
+ }
+ if hs.clientHello.vers <= VersionDTLS10 {
+ hs.clientHello.supportedVersions = append(hs.clientHello.supportedVersions, VersionDTLS10)
+ }
+ } else {
+ if hs.clientHello.vers >= VersionTLS12 {
+ hs.clientHello.supportedVersions = append(hs.clientHello.supportedVersions, VersionTLS12)
+ }
+ if hs.clientHello.vers >= VersionTLS11 {
+ hs.clientHello.supportedVersions = append(hs.clientHello.supportedVersions, VersionTLS11)
+ }
+ if hs.clientHello.vers >= VersionTLS10 {
+ hs.clientHello.supportedVersions = append(hs.clientHello.supportedVersions, VersionTLS10)
+ }
+ if hs.clientHello.vers >= VersionSSL30 {
+ hs.clientHello.supportedVersions = append(hs.clientHello.supportedVersions, VersionSSL30)
+ }
}
- } else {
- if hs.clientHello.vers >= VersionTLS12 {
- clientVersion = VersionTLS12
- } else if hs.clientHello.vers >= VersionTLS11 {
- clientVersion = VersionTLS11
- } else if hs.clientHello.vers >= VersionTLS10 {
- clientVersion = VersionTLS10
- } else if hs.clientHello.vers >= VersionSSL30 {
- clientVersion = VersionSSL30
- }
+ } else if config.Bugs.ExpectGREASE && !containsGREASE(hs.clientHello.supportedVersions) {
+ return errors.New("tls: no GREASE version value found")
}
- if config.Bugs.NegotiateVersion != 0 {
- c.vers = config.Bugs.NegotiateVersion
- } else if c.haveVers && config.Bugs.NegotiateVersionOnRenego != 0 {
- c.vers = config.Bugs.NegotiateVersionOnRenego
- } else if len(hs.clientHello.supportedVersions) > 0 {
- // Use the versions extension if supplied.
- var foundVersion, foundGREASE bool
- for _, extVersion := range hs.clientHello.supportedVersions {
- if isGREASEValue(extVersion) {
- foundGREASE = true
+ if !c.haveVers {
+ if config.Bugs.NegotiateVersion != 0 {
+ c.wireVersion = config.Bugs.NegotiateVersion
+ } else {
+ var found bool
+ for _, vers := range hs.clientHello.supportedVersions {
+ if _, ok := config.isSupportedVersion(vers, c.isDTLS); ok {
+ c.wireVersion = vers
+ found = true
+ break
+ }
}
- extVersion, ok = wireToVersion(extVersion, c.isDTLS)
- if !ok {
- continue
- }
- if config.isSupportedVersion(extVersion, c.isDTLS) && !foundVersion {
- c.vers = extVersion
- foundVersion = true
- break
+ if !found {
+ c.sendAlert(alertProtocolVersion)
+ return errors.New("tls: client did not offer any supported protocol versions")
}
}
- if !foundVersion {
- c.sendAlert(alertProtocolVersion)
- return errors.New("tls: client did not offer any supported protocol versions")
- }
- if config.Bugs.ExpectGREASE && !foundGREASE {
- return errors.New("tls: no GREASE version value found")
- }
- } 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
+ } else if config.Bugs.NegotiateVersionOnRenego != 0 {
+ c.wireVersion = config.Bugs.NegotiateVersionOnRenego
+ }
+
+ c.vers, ok = wireToVersion(c.wireVersion, c.isDTLS)
+ if !ok {
+ panic("Could not map wire version")
}
c.haveVers = true
+ clientProtocol, ok := wireToVersion(c.clientVersion, c.isDTLS)
+
// Reject < 1.2 ClientHellos with signature_algorithms.
- if clientVersion < VersionTLS12 && len(hs.clientHello.signatureAlgorithms) > 0 {
+ if ok && clientProtocol < VersionTLS12 && len(hs.clientHello.signatureAlgorithms) > 0 {
return fmt.Errorf("tls: client included signature_algorithms before TLS 1.2")
}
// Check the client cipher list is consistent with the version.
- if clientVersion < VersionTLS12 {
+ if ok && clientProtocol < VersionTLS12 {
for _, id := range hs.clientHello.cipherSuites {
if isTLS12Cipher(id) {
return fmt.Errorf("tls: client offered TLS 1.2 cipher before TLS 1.2")
@@ -298,13 +293,11 @@
return fmt.Errorf("tls: client offered unexpected PSK identities")
}
- var scsvFound, greaseFound bool
+ var scsvFound bool
for _, cipherSuite := range hs.clientHello.cipherSuites {
if cipherSuite == fallbackSCSV {
scsvFound = true
- }
- if isGREASEValue(cipherSuite) {
- greaseFound = true
+ break
}
}
@@ -314,11 +307,11 @@
return errors.New("tls: fallback SCSV found when not expected")
}
- if !greaseFound && config.Bugs.ExpectGREASE {
+ if config.Bugs.ExpectGREASE && !containsGREASE(hs.clientHello.cipherSuites) {
return errors.New("tls: no GREASE cipher suite value found")
}
- greaseFound = false
+ var greaseFound bool
for _, curve := range hs.clientHello.supportedCurves {
if isGREASEValue(uint16(curve)) {
greaseFound = true
@@ -367,7 +360,7 @@
hs.hello = &serverHelloMsg{
isDTLS: c.isDTLS,
- vers: versionToWire(c.vers, c.isDTLS),
+ vers: c.wireVersion,
versOverride: config.Bugs.SendServerHelloVersion,
customExtension: config.Bugs.CustomUnencryptedExtension,
unencryptedALPN: config.Bugs.SendUnencryptedALPN,
@@ -526,7 +519,7 @@
ResendHelloRetryRequest:
var sendHelloRetryRequest bool
helloRetryRequest := &helloRetryRequestMsg{
- vers: versionToWire(c.vers, c.isDTLS),
+ vers: c.wireVersion,
duplicateExtensions: config.Bugs.DuplicateHelloRetryRequestExtensions,
}
@@ -1049,9 +1042,9 @@
hs.hello = &serverHelloMsg{
isDTLS: c.isDTLS,
- vers: versionToWire(c.vers, c.isDTLS),
+ vers: c.wireVersion,
versOverride: config.Bugs.SendServerHelloVersion,
- compressionMethod: compressionNone,
+ compressionMethod: config.Bugs.SendCompressionMethod,
}
hs.hello.random = make([]byte, 32)
@@ -1168,6 +1161,9 @@
if c.config.Bugs.BadRenegotiationInfo {
serverExtensions.secureRenegotiation[0] ^= 0x80
}
+ if c.config.Bugs.BadRenegotiationInfoEnd {
+ serverExtensions.secureRenegotiation[len(serverExtensions.secureRenegotiation)-1] ^= 0x80
+ }
} else {
serverExtensions.secureRenegotiation = hs.clientHello.secureRenegotiation
}
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index d9218f2..03ba755 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -263,6 +263,31 @@
panic("Unknown test certificate")
}
+// configVersionToWire maps a protocol version to the default wire version to
+// test at that protocol.
+//
+// TODO(davidben): Rather than mapping these, make tlsVersions contains a list
+// of wire versions and test all of them.
+func configVersionToWire(vers uint16, protocol protocol) uint16 {
+ if protocol == dtls {
+ switch vers {
+ case VersionTLS12:
+ return VersionDTLS12
+ case VersionTLS10:
+ return VersionDTLS10
+ }
+ } else {
+ switch vers {
+ case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
+ return vers
+ case VersionTLS13:
+ return tls13DraftVersion
+ }
+ }
+
+ panic("unknown version")
+}
+
// encodeDERValues encodes a series of bytestrings in comma-separated-hex form.
func encodeDERValues(values [][]byte) string {
var ret string
@@ -440,30 +465,20 @@
var testCases []testCase
-func writeTranscript(test *testCase, num int, data []byte) {
+func writeTranscript(test *testCase, path string, data []byte) {
if len(data) == 0 {
return
}
- protocol := "tls"
- if test.protocol == dtls {
- protocol = "dtls"
- }
-
- side := "client"
- if test.testType == serverTest {
- side = "server"
- }
-
- dir := path.Join(*transcriptDir, protocol, side)
- if err := os.MkdirAll(dir, 0755); err != nil {
- fmt.Fprintf(os.Stderr, "Error making %s: %s\n", dir, err)
+ settings, err := ioutil.ReadFile(path)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error reading %s: %s.\n", path, err)
return
}
- name := fmt.Sprintf("%s-%d", test.name, num)
- if err := ioutil.WriteFile(path.Join(dir, name), data, 0644); err != nil {
- fmt.Fprintf(os.Stderr, "Error writing %s: %s\n", name, err)
+ settings = append(settings, data...)
+ if err := ioutil.WriteFile(path, settings, 0644); err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing %s: %s\n", path, err)
}
}
@@ -487,7 +502,7 @@
return t.Conn.Write(b)
}
-func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool, num int) error {
+func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool, transcriptPrefix string, num int) error {
if !test.noSessionCache {
if config.ClientSessionCache == nil {
config.ClientSessionCache = NewLRUClientSessionCache(1)
@@ -536,9 +551,10 @@
if *flagDebug {
defer connDebug.WriteTo(os.Stdout)
}
- if len(*transcriptDir) != 0 {
+ if len(transcriptPrefix) != 0 {
defer func() {
- writeTranscript(test, num, connDebug.Transcript())
+ path := transcriptPrefix + strconv.Itoa(num)
+ writeTranscript(test, path, connDebug.Transcript())
}()
}
@@ -613,6 +629,8 @@
channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
return fmt.Errorf("incorrect channel ID")
}
+ } else if connState.ChannelID != nil {
+ return fmt.Errorf("channel ID unexpectedly negotiated")
}
if expected := test.expectedNextProto; expected != "" {
@@ -1000,6 +1018,26 @@
flags = append(flags, "-tls-unique")
}
+ var transcriptPrefix string
+ if len(*transcriptDir) != 0 {
+ protocol := "tls"
+ if test.protocol == dtls {
+ protocol = "dtls"
+ }
+
+ side := "client"
+ if test.testType == serverTest {
+ side = "server"
+ }
+
+ dir := filepath.Join(*transcriptDir, protocol, side)
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ return err
+ }
+ transcriptPrefix = filepath.Join(dir, test.name+"-")
+ flags = append(flags, "-write-settings", transcriptPrefix)
+ }
+
flags = append(flags, test.flags...)
var shim *exec.Cmd
@@ -1039,7 +1077,7 @@
conn, err := acceptOrWait(listener, waitChan)
if err == nil {
- err = doExchange(test, &config, conn, false /* not a resumption */, 0)
+ err = doExchange(test, &config, conn, false /* not a resumption */, transcriptPrefix, 0)
conn.Close()
}
@@ -1059,7 +1097,7 @@
var connResume net.Conn
connResume, err = acceptOrWait(listener, waitChan)
if err == nil {
- err = doExchange(test, &resumeConfig, connResume, true /* resumption */, i+1)
+ err = doExchange(test, &resumeConfig, connResume, true /* resumption */, transcriptPrefix, i+1)
connResume.Close()
}
}
@@ -1155,16 +1193,27 @@
type tlsVersion struct {
name string
version uint16
- flag string
- hasDTLS bool
+ // excludeFlag is the legacy shim flag to disable the version.
+ excludeFlag string
+ hasDTLS bool
+ // shimTLS and shimDTLS are values the shim uses to refer to these
+ // versions in TLS and DTLS, respectively.
+ shimTLS, shimDTLS int
+}
+
+func (vers tlsVersion) shimFlag(protocol protocol) string {
+ if protocol == dtls {
+ return strconv.Itoa(vers.shimDTLS)
+ }
+ return strconv.Itoa(vers.shimTLS)
}
var tlsVersions = []tlsVersion{
- {"SSL3", VersionSSL30, "-no-ssl3", false},
- {"TLS1", VersionTLS10, "-no-tls1", true},
- {"TLS11", VersionTLS11, "-no-tls11", false},
- {"TLS12", VersionTLS12, "-no-tls12", true},
- {"TLS13", VersionTLS13, "-no-tls13", false},
+ {"SSL3", VersionSSL30, "-no-ssl3", false, VersionSSL30, 0},
+ {"TLS1", VersionTLS10, "-no-tls1", true, VersionTLS10, VersionDTLS10},
+ {"TLS11", VersionTLS11, "-no-tls11", false, VersionTLS11, 0},
+ {"TLS12", VersionTLS12, "-no-tls12", true, VersionTLS12, VersionDTLS12},
+ {"TLS13", VersionTLS13, "-no-tls13", false, VersionTLS13, 0},
}
type testCipherSuite struct {
@@ -2461,6 +2510,21 @@
expectedError: ":INVALID_COMPRESSION_LIST:",
expectedLocalError: "remote error: illegal parameter",
},
+ // Test that the client rejects invalid compression methods
+ // from the server.
+ {
+ testType: clientTest,
+ name: "InvalidCompressionMethod",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendCompressionMethod: 1,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNSUPPORTED_COMPRESSION_ALGORITHM:",
+ expectedLocalError: "remote error: illegal parameter",
+ },
{
name: "GREASE-Client-TLS12",
config: Config{
@@ -2957,6 +3021,116 @@
shouldFail: true,
expectedError: ":NO_SHARED_CIPHER:",
})
+
+ // Test cipher suite negotiation works as expected. Configure a
+ // complicated cipher suite configuration.
+ const negotiationTestCiphers = "" +
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:" +
+ "[TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384|TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256|TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]:" +
+ "TLS_RSA_WITH_AES_128_GCM_SHA256:" +
+ "TLS_RSA_WITH_AES_128_CBC_SHA:" +
+ "[TLS_RSA_WITH_AES_256_GCM_SHA384|TLS_RSA_WITH_AES_256_CBC_SHA]"
+ negotiationTests := []struct {
+ ciphers []uint16
+ expected uint16
+ }{
+ // Server preferences are honored, including when
+ // equipreference groups are involved.
+ {
+ []uint16{
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ {
+ []uint16{
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ },
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ },
+ {
+ []uint16{
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ {
+ []uint16{
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ // Equipreference groups use the client preference.
+ {
+ []uint16{
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ },
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ },
+ {
+ []uint16{
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ },
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ },
+ {
+ []uint16{
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ },
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ },
+ {
+ []uint16{
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ },
+ {
+ []uint16{
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ },
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ },
+ // If there are two equipreference groups, the preferred one
+ // takes precedence.
+ {
+ []uint16{
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ },
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ },
+ }
+ for i, t := range negotiationTests {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CipherNegotiation-" + strconv.Itoa(i),
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: t.ciphers,
+ },
+ flags: []string{"-cipher", negotiationTestCiphers},
+ expectedCipher: t.expected,
+ })
+ }
}
func addBadECDSASignatureTests() {
@@ -3036,36 +3210,46 @@
}
func addCBCSplittingTests() {
- testCases = append(testCases, testCase{
- name: "CBCRecordSplitting",
- config: Config{
- MaxVersion: VersionTLS10,
- MinVersion: VersionTLS10,
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
- },
- messageLen: -1, // read until EOF
- resumeSession: true,
- flags: []string{
- "-async",
- "-write-different-record-sizes",
- "-cbc-record-splitting",
- },
- })
- testCases = append(testCases, testCase{
- name: "CBCRecordSplittingPartialWrite",
- config: Config{
- MaxVersion: VersionTLS10,
- MinVersion: VersionTLS10,
- CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
- },
- messageLen: -1, // read until EOF
- flags: []string{
- "-async",
- "-write-different-record-sizes",
- "-cbc-record-splitting",
- "-partial-write",
- },
- })
+ var cbcCiphers = []struct {
+ name string
+ cipher uint16
+ }{
+ {"3DES", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"AES128", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ {"AES256", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+ }
+ for _, t := range cbcCiphers {
+ testCases = append(testCases, testCase{
+ name: "CBCRecordSplitting-" + t.name,
+ config: Config{
+ MaxVersion: VersionTLS10,
+ MinVersion: VersionTLS10,
+ CipherSuites: []uint16{t.cipher},
+ },
+ messageLen: -1, // read until EOF
+ resumeSession: true,
+ flags: []string{
+ "-async",
+ "-write-different-record-sizes",
+ "-cbc-record-splitting",
+ },
+ })
+ testCases = append(testCases, testCase{
+ name: "CBCRecordSplittingPartialWrite-" + t.name,
+ config: Config{
+ MaxVersion: VersionTLS10,
+ MinVersion: VersionTLS10,
+ CipherSuites: []uint16{t.cipher},
+ },
+ messageLen: -1, // read until EOF
+ flags: []string{
+ "-async",
+ "-write-different-record-sizes",
+ "-cbc-record-splitting",
+ "-partial-write",
+ },
+ })
+ }
}
func addClientAuthTests() {
@@ -3209,6 +3393,37 @@
shouldFail: true,
expectedError: ":UNEXPECTED_MESSAGE:",
})
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "VerifyPeerIfNoOBC-NoChannelID-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ },
+ flags: []string{
+ "-enable-channel-id",
+ "-verify-peer-if-no-obc",
+ },
+ shouldFail: true,
+ expectedError: ":PEER_DID_NOT_RETURN_A_CERTIFICATE:",
+ expectedLocalError: certificateRequired,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "VerifyPeerIfNoOBC-ChannelID-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ ChannelID: channelIDKey,
+ },
+ expectChannelID: true,
+ flags: []string{
+ "-enable-channel-id",
+ "-verify-peer-if-no-obc",
+ },
+ })
}
testCases = append(testCases, testCase{
@@ -4363,6 +4578,36 @@
shouldFail: true,
expectedError: ":CHANNEL_ID_SIGNATURE_INVALID:",
})
+
+ if ver.version < VersionTLS13 {
+ // Channel ID requires ECDHE ciphers.
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ChannelID-NoECDHE-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+ ChannelID: channelIDKey,
+ },
+ expectChannelID: false,
+ flags: []string{"-enable-channel-id"},
+ })
+
+ // Sanity-check setting expectChannelID false works.
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ChannelID-ECDHE-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ ChannelID: channelIDKey,
+ },
+ expectChannelID: false,
+ flags: []string{"-enable-channel-id"},
+ shouldFail: true,
+ expectedLocalError: "channel ID unexpectedly negotiated",
+ })
+ }
}
// Channel ID and NPN at the same time, to ensure their relative
@@ -4541,7 +4786,7 @@
// Assemble flags to disable all newer versions on the shim.
var flags []string
for _, vers := range tlsVersions[i+1:] {
- flags = append(flags, vers.flag)
+ flags = append(flags, vers.excludeFlag)
}
// Test configuring the runner's maximum version.
@@ -4561,19 +4806,17 @@
suffix += "-DTLS"
}
- shimVersFlag := strconv.Itoa(int(versionToWire(shimVers.version, protocol == dtls)))
-
// Determine the expected initial record-layer versions.
clientVers := shimVers.version
if clientVers > VersionTLS10 {
clientVers = VersionTLS10
}
- clientVers = versionToWire(clientVers, protocol == dtls)
+ clientVers = configVersionToWire(clientVers, protocol)
serverVers := expectedVersion
if expectedVersion >= VersionTLS13 {
serverVers = VersionTLS10
}
- serverVers = versionToWire(serverVers, protocol == dtls)
+ serverVers = configVersionToWire(serverVers, protocol)
testCases = append(testCases, testCase{
protocol: protocol,
@@ -4598,7 +4841,7 @@
ExpectInitialRecordVersion: clientVers,
},
},
- flags: []string{"-max-version", shimVersFlag},
+ flags: []string{"-max-version", shimVers.shimFlag(protocol)},
expectedVersion: expectedVersion,
})
@@ -4625,7 +4868,7 @@
ExpectInitialRecordVersion: serverVers,
},
},
- flags: []string{"-max-version", shimVersFlag},
+ flags: []string{"-max-version", shimVers.shimFlag(protocol)},
expectedVersion: expectedVersion,
})
}
@@ -4644,7 +4887,7 @@
suffix += "-DTLS"
}
- wireVersion := versionToWire(vers.version, protocol == dtls)
+ wireVersion := configVersionToWire(vers.version, protocol)
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
@@ -4882,7 +5125,7 @@
// Assemble flags to disable all older versions on the shim.
var flags []string
for _, vers := range tlsVersions[:i] {
- flags = append(flags, vers.flag)
+ flags = append(flags, vers.excludeFlag)
}
for _, runnerVers := range tlsVersions {
@@ -4895,7 +5138,6 @@
if protocol == dtls {
suffix += "-DTLS"
}
- shimVersFlag := strconv.Itoa(int(versionToWire(shimVers.version, protocol == dtls)))
var expectedVersion uint16
var shouldFail bool
@@ -4918,7 +5160,7 @@
// Ensure the server does not decline to
// select a version (versions extension) or
// cipher (some ciphers depend on versions).
- NegotiateVersion: runnerVers.version,
+ NegotiateVersion: configVersionToWire(runnerVers.version, protocol),
IgnorePeerCipherPreferences: shouldFail,
},
},
@@ -4938,11 +5180,11 @@
// Ensure the server does not decline to
// select a version (versions extension) or
// cipher (some ciphers depend on versions).
- NegotiateVersion: runnerVers.version,
+ NegotiateVersion: configVersionToWire(runnerVers.version, protocol),
IgnorePeerCipherPreferences: shouldFail,
},
},
- flags: []string{"-min-version", shimVersFlag},
+ flags: []string{"-min-version", shimVers.shimFlag(protocol)},
expectedVersion: expectedVersion,
shouldFail: shouldFail,
expectedError: expectedError,
@@ -4969,7 +5211,7 @@
config: Config{
MaxVersion: runnerVers.version,
},
- flags: []string{"-min-version", shimVersFlag},
+ flags: []string{"-min-version", shimVers.shimFlag(protocol)},
expectedVersion: expectedVersion,
shouldFail: shouldFail,
expectedError: expectedError,
@@ -6464,6 +6706,19 @@
expectedError: ":RENEGOTIATION_MISMATCH:",
})
testCases = append(testCases, testCase{
+ name: "Renegotiate-Client-BadExt2",
+ renegotiate: 1,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ BadRenegotiationInfoEnd: true,
+ },
+ },
+ flags: []string{"-renegotiate-freely"},
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
+ })
+ testCases = append(testCases, testCase{
name: "Renegotiate-Client-Downgrade",
renegotiate: 1,
config: Config{
@@ -10900,6 +11155,24 @@
"-enable-early-data",
},
})
+
+ // Test that the client reports TLS 1.3 as the version while sending
+ // early data.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "TLS13-EarlyData-Client-VersionAPI",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-expect-accept-early-data",
+ "-expect-version", strconv.Itoa(VersionTLS13),
+ },
+ })
}
func addTLS13CipherPreferenceTests() {
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 960240e..195371f 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -95,6 +95,7 @@
{ "-shim-shuts-down", &TestConfig::shim_shuts_down },
{ "-verify-fail", &TestConfig::verify_fail },
{ "-verify-peer", &TestConfig::verify_peer },
+ { "-verify-peer-if-no-obc", &TestConfig::verify_peer_if_no_obc },
{ "-expect-verify-result", &TestConfig::expect_verify_result },
{ "-renegotiate-once", &TestConfig::renegotiate_once },
{ "-renegotiate-freely", &TestConfig::renegotiate_freely },
@@ -131,6 +132,7 @@
};
const Flag<std::string> kStringFlags[] = {
+ { "-write-settings", &TestConfig::write_settings },
{ "-digest-prefs", &TestConfig::digest_prefs },
{ "-key-file", &TestConfig::key_file },
{ "-cert-file", &TestConfig::cert_file },
@@ -172,6 +174,7 @@
{ "-resume-count", &TestConfig::resume_count },
{ "-min-version", &TestConfig::min_version },
{ "-max-version", &TestConfig::max_version },
+ { "-expect-version", &TestConfig::expect_version },
{ "-mtu", &TestConfig::mtu },
{ "-export-keying-material", &TestConfig::export_keying_material },
{ "-expect-total-renegotiations", &TestConfig::expect_total_renegotiations },
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 8bc8892..7b4b342 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -24,6 +24,7 @@
bool is_server = false;
bool is_dtls = false;
int resume_count = 0;
+ std::string write_settings;
bool fallback_scsv = false;
std::string digest_prefs;
std::vector<int> signing_prefs;
@@ -68,6 +69,7 @@
std::string expected_signed_cert_timestamps;
int min_version = 0;
int max_version = 0;
+ int expect_version = 0;
int mtu = 0;
bool implicit_handshake = false;
bool use_early_callback = false;
@@ -100,6 +102,7 @@
bool shim_shuts_down = false;
bool verify_fail = false;
bool verify_peer = false;
+ bool verify_peer_if_no_obc = false;
bool expect_verify_result = false;
std::string signed_cert_timestamps;
int expect_total_renegotiations = 0;
diff --git a/src/ssl/tls13_enc.c b/src/ssl/tls13_enc.c
index 2137fe2..97f0ed9 100644
--- a/src/ssl/tls13_enc.c
+++ b/src/ssl/tls13_enc.c
@@ -54,15 +54,8 @@
int tls13_init_early_key_schedule(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- uint16_t session_version;
- if (!ssl->method->version_from_wire(&session_version,
- ssl->session->ssl_version) ||
- !init_key_schedule(hs, session_version,
- ssl->session->cipher->algorithm_prf)) {
- return 0;
- }
-
- return 1;
+ return init_key_schedule(hs, SSL_SESSION_protocol_version(ssl->session),
+ ssl->session->cipher->algorithm_prf);
}
int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
@@ -122,11 +115,7 @@
const uint8_t *traffic_secret,
size_t traffic_secret_len) {
const SSL_SESSION *session = SSL_get_session(ssl);
- uint16_t version;
- if (!ssl->method->version_from_wire(&version, session->ssl_version)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
+ uint16_t version = SSL_SESSION_protocol_version(session);
if (traffic_secret_len > 0xff) {
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
@@ -141,8 +130,7 @@
return 0;
}
- const EVP_MD *digest = ssl_get_handshake_digest(
- session->cipher->algorithm_prf, version);
+ const EVP_MD *digest = SSL_SESSION_get_digest(session);
/* Derive the key. */
size_t key_len = EVP_AEAD_key_length(aead);
@@ -383,11 +371,7 @@
int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) {
SSL *const ssl = hs->ssl;
- const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
- if (digest == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
+ const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session);
size_t hash_len = EVP_MD_size(digest);
if (len < hash_len + 3) {
diff --git a/src/ssl/tls13_server.c b/src/ssl/tls13_server.c
index 0a5e1a2..fe2463b 100644
--- a/src/ssl/tls13_server.c
+++ b/src/ssl/tls13_server.c
@@ -537,11 +537,14 @@
goto err;
}
- /* Determine whether to request a client certificate. */
- hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER);
- /* CertificateRequest may only be sent in non-resumption handshakes. */
- if (ssl->s3->session_reused) {
- hs->cert_request = 0;
+ if (!ssl->s3->session_reused) {
+ /* Determine whether to request a client certificate. */
+ hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER);
+ /* Only request a certificate if Channel ID isn't negotiated. */
+ if ((ssl->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) &&
+ ssl->s3->tlsext_channel_id_valid) {
+ hs->cert_request = 0;
+ }
}
/* Send a CertificateRequest, if necessary. */
diff --git a/src/ssl/tls_method.c b/src/ssl/tls_method.c
index 6144f86..d039b7d 100644
--- a/src/ssl/tls_method.c
+++ b/src/ssl/tls_method.c
@@ -65,39 +65,6 @@
#include "internal.h"
-static int ssl3_version_from_wire(uint16_t *out_version,
- uint16_t wire_version) {
- switch (wire_version) {
- case SSL3_VERSION:
- case TLS1_VERSION:
- case TLS1_1_VERSION:
- case TLS1_2_VERSION:
- *out_version = wire_version;
- return 1;
- case TLS1_3_DRAFT_VERSION:
- *out_version = TLS1_3_VERSION;
- return 1;
- }
-
- return 0;
-}
-
-static uint16_t ssl3_version_to_wire(uint16_t version) {
- switch (version) {
- case SSL3_VERSION:
- case TLS1_VERSION:
- case TLS1_1_VERSION:
- case TLS1_2_VERSION:
- return version;
- case TLS1_3_VERSION:
- return TLS1_3_DRAFT_VERSION;
- }
-
- /* It is an error to use this function with an invalid version. */
- assert(0);
- return 0;
-}
-
static int ssl3_supports_cipher(const SSL_CIPHER *cipher) { return 1; }
static void ssl3_expect_flight(SSL *ssl) {}
@@ -130,10 +97,6 @@
static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = {
0 /* is_dtls */,
- SSL3_VERSION,
- TLS1_3_VERSION,
- ssl3_version_from_wire,
- ssl3_version_to_wire,
ssl3_new,
ssl3_free,
ssl3_get_message,
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
index a5bbe93..3bc0b29 100644
--- a/src/ssl/tls_record.c
+++ b/src/ssl/tls_record.c
@@ -389,8 +389,10 @@
* ClientHellos should use SSL 3.0 and pre-TLS-1.3 expects the version
* to change after version negotiation. */
uint16_t wire_version = TLS1_VERSION;
- if (ssl->version == SSL3_VERSION ||
- (ssl->s3->have_version && ssl3_protocol_version(ssl) < TLS1_3_VERSION)) {
+ if (ssl->s3->hs != NULL && ssl->s3->hs->max_version == SSL3_VERSION) {
+ wire_version = SSL3_VERSION;
+ }
+ if (ssl->s3->have_version && ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
wire_version = ssl->version;
}