diff options
author | Robert Sloan <varomodt@google.com> | 2017-09-18 09:38:15 -0700 |
---|---|---|
committer | Robert Sloan <varomodt@google.com> | 2017-09-18 09:38:27 -0700 |
commit | db4251af0823393f084e17c67401b51536ae4cea (patch) | |
tree | baf1909b793751f4be703b768f34d0d629fad513 /src | |
parent | 47949c54330cfe56de2f0d0ad9dfdfde9acd3e90 (diff) | |
download | boringssl-db4251af0823393f084e17c67401b51536ae4cea.tar.gz |
external/boringssl: Sync to 9a127b43b8b78a135d6b64a3e25b8a704c2c069f.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/54c259dec395bd991cce5691723214ffe588e51d..9a127b43b8b78a135d6b64a3e25b8a704c2c069f
Test: BoringSSL CTS Presubmits
Change-Id: I8c9fae592051cefd9b284fbebedc5c2240feda30
Diffstat (limited to 'src')
32 files changed, 926 insertions, 547 deletions
diff --git a/src/crypto/asn1/tasn_dec.c b/src/crypto/asn1/tasn_dec.c index bf008af1..2f5f132a 100644 --- a/src/crypto/asn1/tasn_dec.c +++ b/src/crypto/asn1/tasn_dec.c @@ -56,6 +56,7 @@ #include <openssl/asn1.h> +#include <limits.h> #include <string.h> #include <openssl/asn1t.h> @@ -147,15 +148,6 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, return NULL; } -int ASN1_template_d2i(ASN1_VALUE **pval, - const unsigned char **in, long len, - const ASN1_TEMPLATE *tt) -{ - ASN1_TLC c; - asn1_tlc_clear_nc(&c); - return asn1_template_ex_d2i(pval, in, len, tt, 0, &c); -} - /* * Decode an item, taking care of IMPLICIT tagging, if any. If 'opt' set and * tag mismatch return -1 to handle OPTIONAL @@ -188,6 +180,14 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, else asn1_cb = 0; + /* + * Bound |len| to comfortably fit in an int. Lengths in this module often + * switch between int and long without overflow checks. + */ + if (len > INT_MAX/2) { + len = INT_MAX/2; + } + switch (it->itype) { case ASN1_ITYPE_PRIMITIVE: if (it->templates) { diff --git a/src/crypto/asn1/tasn_enc.c b/src/crypto/asn1/tasn_enc.c index 9286ef64..cc87d349 100644 --- a/src/crypto/asn1/tasn_enc.c +++ b/src/crypto/asn1/tasn_enc.c @@ -256,12 +256,6 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, return 0; } -int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, - const ASN1_TEMPLATE *tt) -{ - return asn1_template_ex_i2d(pval, out, tt, -1, 0); -} - static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt, int tag, int iclass) { diff --git a/src/crypto/cipher_extra/e_aesgcmsiv.c b/src/crypto/cipher_extra/e_aesgcmsiv.c index e4c5bb36..654705b4 100644 --- a/src/crypto/cipher_extra/e_aesgcmsiv.c +++ b/src/crypto/cipher_extra/e_aesgcmsiv.c @@ -34,6 +34,10 @@ struct aead_aes_gcm_siv_asm_ctx { alignas(16) uint8_t key[16*15]; int is_128_bit; + // ptr contains the original pointer from |OPENSSL_malloc|, which may only be + // 8-byte aligned. When freeing this structure, actually call |OPENSSL_free| + // on this pointer. + void *ptr; }; // aes128gcmsiv_aes_ks writes an AES-128 key schedule for |key| to @@ -64,16 +68,18 @@ static int aead_aes_gcm_siv_asm_init(EVP_AEAD_CTX *ctx, const uint8_t *key, return 0; } - // The asm implementation expects a 16-byte-aligned address here, so we use - // |malloc| rather than |OPENSSL_malloc|, which would add a length prefix. - struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = - malloc(sizeof(struct aead_aes_gcm_siv_asm_ctx)); - if (gcm_siv_ctx == NULL) { + char *ptr = OPENSSL_malloc(sizeof(struct aead_aes_gcm_siv_asm_ctx) + 8); + if (ptr == NULL) { return 0; } + assert((((uintptr_t)ptr) & 7) == 0); + + // gcm_siv_ctx needs to be 16-byte aligned in a cross-platform way. + struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = + (struct aead_aes_gcm_siv_asm_ctx *)(ptr + (((uintptr_t)ptr) & 8)); - // malloc should return a 16-byte-aligned address. assert((((uintptr_t)gcm_siv_ctx) & 15) == 0); + gcm_siv_ctx->ptr = ptr; if (key_bits == 128) { aes128gcmsiv_aes_ks(key, &gcm_siv_ctx->key[0]); @@ -89,7 +95,8 @@ static int aead_aes_gcm_siv_asm_init(EVP_AEAD_CTX *ctx, const uint8_t *key, } static void aead_aes_gcm_siv_asm_cleanup(EVP_AEAD_CTX *ctx) { - free(ctx->aead_state); // allocated with native |malloc| + const struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = ctx->aead_state; + OPENSSL_free(gcm_siv_ctx->ptr); } // aesgcmsiv_polyval_horner updates the POLYVAL value in |in_out_poly| to diff --git a/src/crypto/cpu-arm-linux.c b/src/crypto/cpu-arm-linux.c index a5f1f8ac..839b632b 100644 --- a/src/crypto/cpu-arm-linux.c +++ b/src/crypto/cpu-arm-linux.c @@ -288,7 +288,7 @@ static int has_broken_neon(const STRING_PIECE *cpuinfo) { extern uint32_t OPENSSL_armcap_P; -static int g_has_broken_neon; +static int g_has_broken_neon, g_needs_hwcap2_workaround; void OPENSSL_cpuid_setup(void) { char *cpuinfo_data; @@ -336,6 +336,7 @@ void OPENSSL_cpuid_setup(void) { } if (hwcap2 == 0) { hwcap2 = get_hwcap2_cpuinfo(&cpuinfo); + g_needs_hwcap2_workaround = hwcap2 != 0; } if (hwcap2 & HWCAP2_AES) { @@ -357,4 +358,6 @@ void OPENSSL_cpuid_setup(void) { int CRYPTO_has_broken_NEON(void) { return g_has_broken_neon; } +int CRYPTO_needs_hwcap2_workaround(void) { return g_needs_hwcap2_workaround; } + #endif // OPENSSL_ARM && !OPENSSL_STATIC_ARMCAP diff --git a/src/crypto/rand_extra/fuchsia.c b/src/crypto/rand_extra/fuchsia.c index 9355d8c9..9c3783fb 100644 --- a/src/crypto/rand_extra/fuchsia.c +++ b/src/crypto/rand_extra/fuchsia.c @@ -19,20 +19,29 @@ #include <limits.h> #include <stdlib.h> +// TODO(davidben): Remove this once https://crbug.com/765754 is resolved. +#if defined(CHROMIUM_ROLLING_MAGENTA_TO_ZIRCON) +#include <zircon/syscalls.h> +#else #include <magenta/syscalls.h> +#define ZX_CPRNG_DRAW_MAX_LEN MX_CPRNG_DRAW_MAX_LEN +#define ZX_OK MX_OK +#define zx_status_t mx_status_t +#define zx_cprng_draw mx_cprng_draw +#endif #include "../fipsmodule/rand/internal.h" void CRYPTO_sysrand(uint8_t *out, size_t requested) { while (requested > 0) { - size_t output_bytes_this_pass = MX_CPRNG_DRAW_MAX_LEN; + size_t output_bytes_this_pass = ZX_CPRNG_DRAW_MAX_LEN; if (requested < output_bytes_this_pass) { output_bytes_this_pass = requested; } size_t bytes_drawn; - mx_status_t status = - mx_cprng_draw(out, output_bytes_this_pass, &bytes_drawn); - if (status != MX_OK) { + zx_status_t status = + zx_cprng_draw(out, output_bytes_this_pass, &bytes_drawn); + if (status != ZX_OK) { abort(); } requested -= bytes_drawn; diff --git a/src/include/openssl/asn1t.h b/src/include/openssl/asn1t.h index ae507ea4..7bd77017 100644 --- a/src/include/openssl/asn1t.h +++ b/src/include/openssl/asn1t.h @@ -862,12 +862,10 @@ int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it); void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); -int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt); int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx); int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); -int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt); void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it); int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); diff --git a/src/include/openssl/cpu.h b/src/include/openssl/cpu.h index 39e7264d..dd95ddc6 100644 --- a/src/include/openssl/cpu.h +++ b/src/include/openssl/cpu.h @@ -135,6 +135,10 @@ static inline int CRYPTO_is_NEON_capable(void) { // CRYPTO_has_broken_NEON returns one if the current CPU is known to have a // broken NEON unit. See https://crbug.com/341598. OPENSSL_EXPORT int CRYPTO_has_broken_NEON(void); + +// CRYPTO_needs_hwcap2_workaround returns one if the ARMv8 AArch32 AT_HWCAP2 +// workaround was needed. See https://crbug.com/boringssl/46. +OPENSSL_EXPORT int CRYPTO_needs_hwcap2_workaround(void); #endif // CRYPTO_is_ARMv8_AES_capable returns true if the current CPU supports the diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h index e917fb42..440c431d 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h @@ -146,7 +146,6 @@ #include <openssl/bio.h> #include <openssl/buf.h> -#include <openssl/hmac.h> #include <openssl/lhash.h> #include <openssl/pem.h> #include <openssl/span.h> @@ -590,6 +589,8 @@ OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl); #define TLS1_3_DRAFT_VERSION 0x7f12 #define TLS1_3_EXPERIMENT_VERSION 0x7e01 +#define TLS1_3_EXPERIMENT2_VERSION 0x7e02 +#define TLS1_3_EXPERIMENT3_VERSION 0x7e03 #define TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION 0x7a12 // SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to @@ -3177,6 +3178,8 @@ enum tls13_variant_t { tls13_experiment = 1, tls13_record_type_experiment = 2, tls13_no_session_id_experiment = 3, + tls13_experiment2 = 4, + tls13_experiment3 = 5, }; // SSL_CTX_set_tls13_variant sets which variant of TLS 1.3 we negotiate. On the @@ -3977,22 +3980,6 @@ typedef struct ssl_x509_method_st SSL_X509_METHOD; DECLARE_STACK_OF(SSL_CUSTOM_EXTENSION) -struct ssl_cipher_st { - // name is the OpenSSL name for the cipher. - const char *name; - // standard_name is the IETF name for the cipher. - const char *standard_name; - // id is the cipher suite value bitwise OR-d with 0x03000000. - uint32_t id; - - // algorithm_* are internal fields. See ssl/internal.h for their values. - uint32_t algorithm_mkey; - uint32_t algorithm_auth; - uint32_t algorithm_enc; - uint32_t algorithm_mac; - uint32_t algorithm_prf; -}; - #define SSL_MAX_SSL_SESSION_ID_LENGTH 32 #define SSL_MAX_SID_CTX_LENGTH 32 #define SSL_MAX_MASTER_KEY_LENGTH 48 diff --git a/src/ssl/dtls_record.cc b/src/ssl/dtls_record.cc index dbc8fa2d..5009f044 100644 --- a/src/ssl/dtls_record.cc +++ b/src/ssl/dtls_record.cc @@ -192,14 +192,27 @@ enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, !CBS_get_u16(&cbs, &version) || !CBS_copy_bytes(&cbs, sequence, 8) || !CBS_get_u16_length_prefixed(&cbs, &body) || - (ssl->s3->have_version && version != ssl->version) || - (version >> 8) != DTLS1_VERSION_MAJOR || CBS_len(&body) > SSL3_RT_MAX_ENCRYPTED_LENGTH) { // The record header was incomplete or malformed. Drop the entire packet. *out_consumed = in_len; return ssl_open_record_discard; } + bool version_ok; + if (ssl->s3->aead_read_ctx->is_null_cipher()) { + // Only check the first byte. Enforcing beyond that can prevent decoding + // version negotiation failure alerts. + version_ok = (version >> 8) == DTLS1_VERSION_MAJOR; + } else { + version_ok = version == ssl->s3->aead_read_ctx->RecordVersion(); + } + + if (!version_ok) { + // The record header was incomplete or malformed. Drop the entire packet. + *out_consumed = in_len; + return ssl_open_record_discard; + } + ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in, DTLS1_RT_HEADER_LENGTH); @@ -300,9 +313,9 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, out[0] = type; - uint16_t wire_version = ssl->s3->have_version ? ssl->version : DTLS1_VERSION; - out[1] = wire_version >> 8; - out[2] = wire_version & 0xff; + uint16_t record_version = ssl->s3->aead_write_ctx->RecordVersion(); + out[1] = record_version >> 8; + out[2] = record_version & 0xff; out[3] = epoch >> 8; out[4] = epoch & 0xff; @@ -310,7 +323,7 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, size_t ciphertext_len; if (!aead->Seal(out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len, - max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version, + max_out - DTLS1_RT_HEADER_LENGTH, type, record_version, &out[3] /* seq */, in, in_len) || !ssl_record_sequence_update(&seq[2], 6)) { return 0; diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc index 52d2e944..18dd58f8 100644 --- a/src/ssl/handshake_client.cc +++ b/src/ssl/handshake_client.cc @@ -316,7 +316,7 @@ int ssl_write_client_hello(SSL_HANDSHAKE *hs) { // In TLS 1.3 experimental encodings, send a fake placeholder session ID // when we do not otherwise have one to send. if (hs->max_version >= TLS1_3_VERSION && - ssl->tls13_variant == tls13_experiment && + ssl_is_resumption_variant(ssl->tls13_variant) && !CBB_add_bytes(&child, hs->session_id, hs->session_id_len)) { return 0; } @@ -438,6 +438,12 @@ static enum ssl_hs_wait_t do_start_connect(SSL_HANDSHAKE *hs) { return ssl_hs_error; } + // SSL 3.0 ClientHellos should use SSL 3.0 not TLS 1.0, for the record-layer + // version. + if (hs->max_version == SSL3_VERSION) { + ssl->s3->aead_write_ctx->SetVersionIfNullCipher(SSL3_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. @@ -468,7 +474,7 @@ static enum ssl_hs_wait_t do_start_connect(SSL_HANDSHAKE *hs) { // Initialize a random session ID for the experimental TLS 1.3 variant // requiring a session id. - if (ssl->tls13_variant == tls13_experiment) { + if (ssl_is_resumption_variant(ssl->tls13_variant)) { hs->session_id_len = sizeof(hs->session_id); if (!RAND_bytes(hs->session_id, hs->session_id_len)) { return ssl_hs_error; @@ -584,6 +590,7 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) { // At this point, the connection's version is known and ssl->version is // fixed. Begin enforcing the record-layer version. ssl->s3->have_version = true; + ssl->s3->aead_write_ctx->SetVersionIfNullCipher(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); diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc index 10e618d1..cd99ec92 100644 --- a/src/ssl/handshake_server.cc +++ b/src/ssl/handshake_server.cc @@ -276,6 +276,7 @@ static int negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert, // At this point, the connection's version is known and |ssl->version| is // fixed. Begin enforcing the record-layer version. ssl->s3->have_version = true; + ssl->s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version); // Handle FALLBACK_SCSV. if (ssl_client_cipher_list_contains_cipher(client_hello, diff --git a/src/ssl/internal.h b/src/ssl/internal.h index 0e44de84..9e674575 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -282,9 +282,46 @@ int ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert, // call this function before the version is determined. uint16_t ssl3_protocol_version(const SSL *ssl); +// ssl_is_resumption_experiment returns whether the version corresponds to a +// TLS 1.3 resumption experiment. +bool ssl_is_resumption_experiment(uint16_t version); + +// ssl_is_resumption_variant returns whether the version corresponds to a +// TLS 1.3 resumption experiment. +bool ssl_is_resumption_variant(enum tls13_variant_t variant); + +// ssl_is_resumption_client_ccs_experiment returns whether the version +// corresponds to a TLS 1.3 resumption experiment that sends a client CCS. +bool ssl_is_resumption_client_ccs_experiment(uint16_t version); + +// ssl_is_resumption_record_version_experiment returns whether the version +// corresponds to a TLS 1.3 resumption experiment that modifies the record +// version. +bool ssl_is_resumption_record_version_experiment(uint16_t version); + // Cipher suites. +} // namespace bssl + +struct ssl_cipher_st { + // name is the OpenSSL name for the cipher. + const char *name; + // standard_name is the IETF name for the cipher. + const char *standard_name; + // id is the cipher suite value bitwise OR-d with 0x03000000. + uint32_t id; + + // algorithm_* determine the cipher suite. See constants below for the values. + uint32_t algorithm_mkey; + uint32_t algorithm_auth; + uint32_t algorithm_enc; + uint32_t algorithm_mac; + uint32_t algorithm_prf; +}; + +namespace bssl { + // Bits for |algorithm_mkey| (key exchange algorithm). #define SSL_kRSA 0x00000001u #define SSL_kECDHE 0x00000002u @@ -466,7 +503,7 @@ int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len, // encrypt an SSL connection. class SSLAEADContext { public: - SSLAEADContext(uint16_t version, const SSL_CIPHER *cipher); + SSLAEADContext(uint16_t version, bool is_dtls, const SSL_CIPHER *cipher); ~SSLAEADContext(); static constexpr bool kAllowUniquePtr = true; @@ -474,7 +511,7 @@ class SSLAEADContext { SSLAEADContext &operator=(const SSLAEADContext &&) = delete; // CreateNullCipher creates an |SSLAEADContext| for the null cipher. - static UniquePtr<SSLAEADContext> CreateNullCipher(); + static UniquePtr<SSLAEADContext> CreateNullCipher(bool is_dtls); // Create creates an |SSLAEADContext| using the supplied key material. It // returns nullptr on error. Only one of |Open| or |Seal| may be used with the @@ -486,7 +523,20 @@ class SSLAEADContext { const uint8_t *mac_key, size_t mac_key_len, const uint8_t *fixed_iv, size_t fixed_iv_len); - uint16_t version() const { return version_; } + // SetVersionIfNullCipher sets the version the SSLAEADContext for the null + // cipher, to make version-specific determinations in the record layer prior + // to a cipher being selected. + void SetVersionIfNullCipher(uint16_t version); + + // ProtocolVersion returns the protocol version associated with this + // SSLAEADContext. It can only be called once |version_| has been set to a + // valid value. + uint16_t ProtocolVersion() const; + + // RecordVersion returns the record version that should be used with this + // SSLAEADContext for record construction and crypto. + uint16_t RecordVersion() const; + const SSL_CIPHER *cipher() const { return cipher_; } // is_null_cipher returns true if this is the null cipher. @@ -509,7 +559,7 @@ class SSLAEADContext { // success, it sets |*out| to the plaintext in |in| and returns true. // Otherwise, it returns false. The output will always be |ExplicitNonceLen| // bytes ahead of |in|. - bool Open(CBS *out, uint8_t type, uint16_t wire_version, + bool Open(CBS *out, uint8_t type, uint16_t record_version, const uint8_t seqnum[8], uint8_t *in, size_t in_len); // Seal encrypts and authenticates |in_len| bytes from |in| and writes the @@ -517,7 +567,7 @@ class SSLAEADContext { // // If |in| and |out| alias then |out| + |ExplicitNonceLen| must be == |in|. bool Seal(uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, - uint16_t wire_version, const uint8_t seqnum[8], const uint8_t *in, + uint16_t record_version, const uint8_t seqnum[8], const uint8_t *in, size_t in_len); // SealScatter encrypts and authenticates |in_len| bytes from |in| and splits @@ -536,17 +586,18 @@ class SSLAEADContext { // If |in| and |out| alias then |out| must be == |in|. Other arguments may not // alias anything. bool SealScatter(uint8_t *out_prefix, uint8_t *out, uint8_t *out_suffix, - uint8_t type, uint16_t wire_version, const uint8_t seqnum[8], - const uint8_t *in, size_t in_len, const uint8_t *extra_in, - size_t extra_in_len); + uint8_t type, uint16_t record_version, + const uint8_t seqnum[8], const uint8_t *in, size_t in_len, + const uint8_t *extra_in, size_t extra_in_len); bool GetIV(const uint8_t **out_iv, size_t *out_iv_len) const; private: // GetAdditionalData writes the additional data into |out| and returns the // number of bytes written. - size_t GetAdditionalData(uint8_t out[13], uint8_t type, uint16_t wire_version, - const uint8_t seqnum[8], size_t plaintext_len); + size_t GetAdditionalData(uint8_t out[13], uint8_t type, + uint16_t record_version, const uint8_t seqnum[8], + size_t plaintext_len); const SSL_CIPHER *cipher_; ScopedEVP_AEAD_CTX ctx_; @@ -554,8 +605,10 @@ class SSLAEADContext { // records. uint8_t fixed_nonce_[12]; uint8_t fixed_nonce_len_ = 0, variable_nonce_len_ = 0; - // version_ is the protocol version that should be used with this AEAD. + // version_ is the wire version that should be used with this AEAD. uint16_t version_; + // is_dtls_ is whether DTLS is being used with this AEAD. + bool is_dtls_; // variable_nonce_included_in_record_ is true if the variable nonce // for a record is included as a prefix before the ciphertext. bool variable_nonce_included_in_record_ : 1; @@ -1437,8 +1490,11 @@ int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret, // ClientHello functions. -int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, - const SSLMessage &msg); +// ssl_client_hello_init parses |msg| as a ClientHello and writes the result to +// |*out|. It returns one on success and zero on error. This function is +// exported for unit tests. +OPENSSL_EXPORT int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, + const SSLMessage &msg); int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello, CBS *out, uint16_t extension_type); @@ -1446,6 +1502,10 @@ int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello, int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello, uint16_t id); +// ssl_is_probably_java returns true if |client_hello| looks like a Java +// ClientHello and false otherwise. This function is exported for tests. +OPENSSL_EXPORT bool ssl_is_probably_java(const SSL_CLIENT_HELLO *client_hello); + // GREASE. diff --git a/src/ssl/s3_lib.cc b/src/ssl/s3_lib.cc index dcf9559f..3df8e1b3 100644 --- a/src/ssl/s3_lib.cc +++ b/src/ssl/s3_lib.cc @@ -165,8 +165,10 @@ namespace bssl { int ssl3_new(SSL *ssl) { - UniquePtr<SSLAEADContext> aead_read_ctx = SSLAEADContext::CreateNullCipher(); - UniquePtr<SSLAEADContext> aead_write_ctx = SSLAEADContext::CreateNullCipher(); + UniquePtr<SSLAEADContext> aead_read_ctx = + SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); + UniquePtr<SSLAEADContext> aead_write_ctx = + SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); if (!aead_read_ctx || !aead_write_ctx) { return 0; } diff --git a/src/ssl/ssl_aead_ctx.cc b/src/ssl/ssl_aead_ctx.cc index 69129af3..d03a4a05 100644 --- a/src/ssl/ssl_aead_ctx.cc +++ b/src/ssl/ssl_aead_ctx.cc @@ -33,10 +33,11 @@ namespace bssl { -SSLAEADContext::SSLAEADContext(uint16_t version_arg, +SSLAEADContext::SSLAEADContext(uint16_t version_arg, bool is_dtls_arg, const SSL_CIPHER *cipher_arg) : cipher_(cipher_arg), version_(version_arg), + is_dtls_(is_dtls_arg), variable_nonce_included_in_record_(false), random_variable_nonce_(false), omit_length_in_ad_(false), @@ -48,8 +49,9 @@ SSLAEADContext::SSLAEADContext(uint16_t version_arg, SSLAEADContext::~SSLAEADContext() {} -UniquePtr<SSLAEADContext> SSLAEADContext::CreateNullCipher() { - return MakeUnique<SSLAEADContext>(0 /* version */, nullptr /* cipher */); +UniquePtr<SSLAEADContext> SSLAEADContext::CreateNullCipher(bool is_dtls) { + return MakeUnique<SSLAEADContext>(0 /* version */, is_dtls, + nullptr /* cipher */); } UniquePtr<SSLAEADContext> SSLAEADContext::Create( @@ -57,10 +59,13 @@ UniquePtr<SSLAEADContext> SSLAEADContext::Create( const SSL_CIPHER *cipher, const uint8_t *enc_key, size_t enc_key_len, const uint8_t *mac_key, size_t mac_key_len, const uint8_t *fixed_iv, size_t fixed_iv_len) { + const EVP_AEAD *aead; + uint16_t protocol_version; size_t expected_mac_key_len, expected_fixed_iv_len; - if (!ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len, - &expected_fixed_iv_len, cipher, version, + if (!ssl_protocol_version_from_wire(&protocol_version, version) || + !ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len, + &expected_fixed_iv_len, cipher, protocol_version, is_dtls) || // Ensure the caller returned correct key sizes. expected_fixed_iv_len != fixed_iv_len || @@ -87,12 +92,14 @@ UniquePtr<SSLAEADContext> SSLAEADContext::Create( } UniquePtr<SSLAEADContext> aead_ctx = - MakeUnique<SSLAEADContext>(version, cipher); + MakeUnique<SSLAEADContext>(version, is_dtls, cipher); if (!aead_ctx) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return nullptr; } + assert(aead_ctx->ProtocolVersion() == protocol_version); + if (!EVP_AEAD_CTX_init_with_direction( aead_ctx->ctx_.get(), aead, enc_key, enc_key_len, EVP_AEAD_DEFAULT_TAG_LENGTH, direction)) { @@ -125,7 +132,7 @@ UniquePtr<SSLAEADContext> SSLAEADContext::Create( // The TLS 1.3 construction XORs the fixed nonce into the sequence number // and omits the additional data. - if (version >= TLS1_3_VERSION) { + if (protocol_version >= TLS1_3_VERSION) { aead_ctx->xor_fixed_nonce_ = true; aead_ctx->variable_nonce_len_ = 8; aead_ctx->variable_nonce_included_in_record_ = false; @@ -133,16 +140,47 @@ UniquePtr<SSLAEADContext> SSLAEADContext::Create( assert(fixed_iv_len >= aead_ctx->variable_nonce_len_); } } else { - assert(version < TLS1_3_VERSION); + assert(protocol_version < TLS1_3_VERSION); aead_ctx->variable_nonce_included_in_record_ = true; aead_ctx->random_variable_nonce_ = true; aead_ctx->omit_length_in_ad_ = true; - aead_ctx->omit_version_in_ad_ = (version == SSL3_VERSION); + aead_ctx->omit_version_in_ad_ = (protocol_version == SSL3_VERSION); } return aead_ctx; } +void SSLAEADContext::SetVersionIfNullCipher(uint16_t version) { + if (is_null_cipher()) { + version_ = version; + } +} + +uint16_t SSLAEADContext::ProtocolVersion() const { + uint16_t protocol_version; + if(!ssl_protocol_version_from_wire(&protocol_version, version_)) { + assert(false); + return 0; + } + return protocol_version; +} + +uint16_t SSLAEADContext::RecordVersion() const { + if (version_ == 0) { + assert(is_null_cipher()); + return is_dtls_ ? DTLS1_VERSION : TLS1_VERSION; + } + + if (ProtocolVersion() <= TLS1_2_VERSION) { + return version_; + } + + if (ssl_is_resumption_record_version_experiment(version_)) { + return TLS1_2_VERSION; + } + return TLS1_VERSION; +} + size_t SSLAEADContext::ExplicitNonceLen() const { if (!FUZZER_MODE && variable_nonce_included_in_record_) { return variable_nonce_len_; @@ -168,7 +206,7 @@ size_t SSLAEADContext::MaxOverhead() const { } size_t SSLAEADContext::GetAdditionalData(uint8_t out[13], uint8_t type, - uint16_t wire_version, + uint16_t record_version, const uint8_t seqnum[8], size_t plaintext_len) { if (omit_ad_) { @@ -179,8 +217,8 @@ size_t SSLAEADContext::GetAdditionalData(uint8_t out[13], uint8_t type, size_t len = 8; out[len++] = type; if (!omit_version_in_ad_) { - out[len++] = static_cast<uint8_t>((wire_version >> 8)); - out[len++] = static_cast<uint8_t>(wire_version); + out[len++] = static_cast<uint8_t>((record_version >> 8)); + out[len++] = static_cast<uint8_t>(record_version); } if (!omit_length_in_ad_) { out[len++] = static_cast<uint8_t>((plaintext_len >> 8)); @@ -189,7 +227,7 @@ size_t SSLAEADContext::GetAdditionalData(uint8_t out[13], uint8_t type, return len; } -bool SSLAEADContext::Open(CBS *out, uint8_t type, uint16_t wire_version, +bool SSLAEADContext::Open(CBS *out, uint8_t type, uint16_t record_version, const uint8_t seqnum[8], uint8_t *in, size_t in_len) { if (is_null_cipher() || FUZZER_MODE) { // Handle the initial NULL cipher. @@ -211,7 +249,7 @@ bool SSLAEADContext::Open(CBS *out, uint8_t type, uint16_t wire_version, } uint8_t ad[13]; size_t ad_len = - GetAdditionalData(ad, type, wire_version, seqnum, plaintext_len); + GetAdditionalData(ad, type, record_version, seqnum, plaintext_len); // Assemble the nonce. uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; @@ -262,9 +300,10 @@ bool SSLAEADContext::Open(CBS *out, uint8_t type, uint16_t wire_version, bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out, uint8_t *out_suffix, uint8_t type, - uint16_t wire_version, const uint8_t seqnum[8], - const uint8_t *in, size_t in_len, - const uint8_t *extra_in, size_t extra_in_len) { + uint16_t record_version, + const uint8_t seqnum[8], const uint8_t *in, + size_t in_len, const uint8_t *extra_in, + size_t extra_in_len) { const size_t prefix_len = ExplicitNonceLen(); size_t suffix_len; if (!SuffixLen(&suffix_len, in_len, extra_in_len)) { @@ -286,7 +325,7 @@ bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out, } uint8_t ad[13]; - size_t ad_len = GetAdditionalData(ad, type, wire_version, seqnum, in_len); + size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum, in_len); // Assemble the nonce. uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; @@ -343,7 +382,7 @@ bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out, } bool SSLAEADContext::Seal(uint8_t *out, size_t *out_len, size_t max_out_len, - uint8_t type, uint16_t wire_version, + uint8_t type, uint16_t record_version, const uint8_t seqnum[8], const uint8_t *in, size_t in_len) { const size_t prefix_len = ExplicitNonceLen(); @@ -363,7 +402,7 @@ bool SSLAEADContext::Seal(uint8_t *out, size_t *out_len, size_t max_out_len, } if (!SealScatter(out, out + prefix_len, out + prefix_len + in_len, type, - wire_version, seqnum, in, in_len, 0, 0)) { + record_version, seqnum, in, in_len, 0, 0)) { return false; } *out_len = prefix_len + in_len + suffix_len; diff --git a/src/ssl/ssl_session.cc b/src/ssl/ssl_session.cc index c21c2826..e885324e 100644 --- a/src/ssl/ssl_session.cc +++ b/src/ssl/ssl_session.cc @@ -142,6 +142,7 @@ #include <utility> #include <openssl/err.h> +#include <openssl/hmac.h> #include <openssl/lhash.h> #include <openssl/mem.h> #include <openssl/rand.h> @@ -721,6 +722,72 @@ static enum ssl_hs_wait_t ssl_lookup_session( return ssl_hs_ok; } +bool ssl_is_probably_java(const SSL_CLIENT_HELLO *client_hello) { + CBS extension, groups; + if (SSL_is_dtls(client_hello->ssl) || + !ssl_client_hello_get_extension(client_hello, &extension, + TLSEXT_TYPE_supported_groups) || + !CBS_get_u16_length_prefixed(&extension, &groups) || + CBS_len(&extension) != 0) { + return false; + } + + // Original Java curve list. + static const uint8_t kCurveList1[] = { + 0x00, 0x17, 0x00, 0x01, 0x00, 0x03, 0x00, 0x13, 0x00, 0x15, + 0x00, 0x06, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x18, + 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x0e, + 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x02, 0x00, 0x12, + 0x00, 0x04, 0x00, 0x05, 0x00, 0x14, 0x00, 0x08, 0x00, 0x16}; + + // Newer Java curve list. + static const uint8_t kCurveList2[] = { + 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, + 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x16}; + + // IcedTea curve list. + static const uint8_t kCurveList3[] = {0x00, 0x17, 0x00, 0x18, 0x00, 0x19}; + + auto groups_span = MakeConstSpan(CBS_data(&groups), CBS_len(&groups)); + if (groups_span != kCurveList1 && groups_span != kCurveList2 && + groups_span != kCurveList3) { + return false; + } + + // Java has a very distinctive curve list, but IcedTea patches it to a more + // standard [P-256, P-384, P-521]. Additionally check the extension + // order. This may still flag other clients, but false positives only mean a + // loss of resumption. Any client new enough to support one of X25519, + // extended master secret, session tickets, or TLS 1.3 will be unaffected. + // + // Java sends different extensions depending on configuration and version, but + // those which are present are always in the same order. Check if the + // extensions are an ordered subset of |kJavaExtensions|. + static const uint16_t kJavaExtensions[] = { + TLSEXT_TYPE_supported_groups, + TLSEXT_TYPE_ec_point_formats, + TLSEXT_TYPE_signature_algorithms, + TLSEXT_TYPE_server_name, + 17 /* status_request_v2 */, + TLSEXT_TYPE_status_request, + TLSEXT_TYPE_application_layer_protocol_negotiation, + TLSEXT_TYPE_renegotiate, + }; + CBS extensions; + CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len); + for (uint16_t expected : kJavaExtensions) { + CBS extensions_copy = extensions, body; + uint16_t type; + // Peek at the next extension. + if (CBS_get_u16(&extensions_copy, &type) && + CBS_get_u16_length_prefixed(&extensions_copy, &body) && + type == expected) { + extensions = extensions_copy; + } + } + return CBS_len(&extensions) == 0; +} + enum ssl_hs_wait_t ssl_get_prev_session(SSL *ssl, UniquePtr<SSL_SESSION> *out_session, bool *out_tickets_supported, @@ -728,8 +795,6 @@ enum ssl_hs_wait_t ssl_get_prev_session(SSL *ssl, const SSL_CLIENT_HELLO *client_hello) { // This is used only by servers. assert(ssl->server); - UniquePtr<SSL_SESSION> session; - bool renew_ticket = false; // If tickets are disabled, always behave as if no tickets are present. const uint8_t *ticket = NULL; @@ -739,6 +804,37 @@ enum ssl_hs_wait_t ssl_get_prev_session(SSL *ssl, ssl->version > SSL3_VERSION && SSL_early_callback_ctx_extension_get( client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len); + + if (ssl_is_probably_java(client_hello)) { + // The Java client implementation of the 3SHAKE mitigation incorrectly + // rejects initial handshakes when all of the following are true: + // + // 1. The ClientHello offered a session. + // 2. The session was successfully resumed previously. + // 3. The server declines the session. + // 4. The server sends a certificate with a different (see below) SAN list + // than in the previous session. + // + // (Note the 3SHAKE mitigation is to reject certificates changes on + // renegotiation, while Java's logic applies to initial handshakes as well.) + // + // The end result is long-lived Java clients break on certificate rotations + // where the SAN list changes too much. Older versions of Java break if the + // first DNS name of the two certificates is different. Newer ones will + // break if there is no intersection. The new logic mostly mitigates this, + // but this can still cause problems if switching to or from wildcards. + // + // Thus, fingerprint Java clients and decline all offered sessions. This + // avoids (2) while still introducing new sessions to clear any existing + // problematic sessions. + *out_session = nullptr; + *out_tickets_supported = tickets_supported; + *out_renew_ticket = false; + return ssl_hs_ok; + } + + UniquePtr<SSL_SESSION> session; + bool renew_ticket = false; if (tickets_supported && ticket_len > 0) { switch (ssl_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len, client_hello->session_id, diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index 66f03047..f032b25b 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -3816,6 +3816,179 @@ TEST(SSLTest, NoCiphersAvailable) { EXPECT_EQ(SSL_R_NO_CIPHERS_AVAILABLE, ERR_GET_REASON(err)); } +TEST(SSLTest, IsProbablyJava) { + bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); + ASSERT_TRUE(ctx); + bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get())); + ASSERT_TRUE(ssl); + + const struct { + const char *name; + std::vector<uint8_t> in; + bool is_probably_java; + } kTests[] = { + {"JDK 6 with IcedTea curve list", + {0x03, 0x01, 0x59, 0xb3, 0x10, 0xea, 0x17, 0xfe, 0x9e, 0x69, 0x7e, 0x79, + 0xc7, 0x33, 0x10, 0x81, 0x73, 0x9e, 0xe7, 0xbf, 0x78, 0x4a, 0x33, 0x76, + 0x12, 0x1f, 0xc5, 0x6d, 0x28, 0x8d, 0xd7, 0x60, 0xf0, 0x5e, 0x00, 0x00, + 0x2c, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x35, 0xc0, 0x05, 0xc0, 0x0f, 0x00, + 0x39, 0x00, 0x38, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x2f, 0xc0, 0x04, 0xc0, + 0x0e, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x0a, 0xc0, + 0x03, 0xc0, 0x0d, 0x00, 0x16, 0x00, 0x13, 0x00, 0xff, 0x01, 0x00, 0x00, + 0x12, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, + 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00}, + true}, + {"JDK 7 with IcedTea curve list", + {0x03, 0x03, 0x59, 0xb3, 0x10, 0xc8, 0x03, 0x7d, 0x10, 0x5a, 0x6b, 0x6e, + 0x84, 0xa5, 0xbe, 0x6e, 0xe2, 0xd0, 0xb4, 0xb5, 0xcf, 0x6d, 0xa1, 0x58, + 0xb5, 0xc0, 0x05, 0x63, 0xf6, 0x81, 0xda, 0xc2, 0xa0, 0xb0, 0x00, 0x00, + 0x48, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x3d, 0xc0, 0x26, 0xc0, 0x2a, 0x00, + 0x6b, 0x00, 0x6a, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x35, 0xc0, 0x05, 0xc0, + 0x0f, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x3c, 0xc0, + 0x25, 0xc0, 0x29, 0x00, 0x67, 0x00, 0x40, 0xc0, 0x09, 0xc0, 0x13, 0x00, + 0x2f, 0xc0, 0x04, 0xc0, 0x0e, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x08, 0xc0, + 0x12, 0x00, 0x0a, 0xc0, 0x03, 0xc0, 0x0d, 0x00, 0x16, 0x00, 0x13, 0x00, + 0xff, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, + 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, + 0x0d, 0x00, 0x18, 0x00, 0x16, 0x06, 0x03, 0x06, 0x01, 0x05, 0x03, 0x05, + 0x01, 0x04, 0x03, 0x04, 0x01, 0x03, 0x03, 0x03, 0x01, 0x02, 0x03, 0x02, + 0x01, 0x02, 0x02}, + true}, + {"JDK 8", + {0x03, 0x03, 0x59, 0xb3, 0x10, 0xfc, 0xc7, 0xcb, 0x36, 0x85, 0x8c, 0x00, + 0xd6, 0xa7, 0x5b, 0xfb, 0x98, 0xbe, 0xf9, 0xa3, 0xa0, 0x01, 0xff, 0x35, + 0xb9, 0x1a, 0xc1, 0x72, 0xf1, 0x51, 0x4b, 0x49, 0x96, 0x1a, 0x00, 0x00, + 0x70, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x3d, 0xc0, 0x26, 0xc0, 0x2a, 0x00, + 0x6b, 0x00, 0x6a, 0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x35, 0xc0, 0x05, 0xc0, + 0x0f, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x3c, 0xc0, + 0x25, 0xc0, 0x29, 0x00, 0x67, 0x00, 0x40, 0xc0, 0x09, 0xc0, 0x13, 0x00, + 0x2f, 0xc0, 0x04, 0xc0, 0x0e, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x2c, 0xc0, + 0x2b, 0xc0, 0x30, 0x00, 0x9d, 0xc0, 0x2e, 0xc0, 0x32, 0x00, 0x9f, 0x00, + 0xa3, 0xc0, 0x2f, 0x00, 0x9c, 0xc0, 0x2d, 0xc0, 0x31, 0x00, 0x9e, 0x00, + 0xa2, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x0a, 0xc0, 0x03, 0xc0, 0x0d, 0x00, + 0x16, 0x00, 0x13, 0xc0, 0x07, 0xc0, 0x11, 0x00, 0x05, 0xc0, 0x02, 0xc0, + 0x0c, 0x00, 0x04, 0x00, 0xff, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x0a, 0x00, + 0x34, 0x00, 0x32, 0x00, 0x17, 0x00, 0x01, 0x00, 0x03, 0x00, 0x13, 0x00, + 0x15, 0x00, 0x06, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x18, 0x00, + 0x0b, 0x00, 0x0c, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, + 0x10, 0x00, 0x11, 0x00, 0x02, 0x00, 0x12, 0x00, 0x04, 0x00, 0x05, 0x00, + 0x14, 0x00, 0x08, 0x00, 0x16, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, + 0x0d, 0x00, 0x1a, 0x00, 0x18, 0x06, 0x03, 0x06, 0x01, 0x05, 0x03, 0x05, + 0x01, 0x04, 0x03, 0x04, 0x01, 0x03, 0x03, 0x03, 0x01, 0x02, 0x03, 0x02, + 0x01, 0x02, 0x02, 0x01, 0x01}, + true}, + {"JDK 9", + {0x03, 0x03, 0x0c, 0xe6, 0x06, 0xc6, 0x5d, 0x38, 0xb4, 0x5e, 0x3a, 0xd5, + 0xb0, 0x5f, 0x5b, 0x84, 0x3b, 0xff, 0x86, 0x4f, 0xb0, 0x3f, 0xc1, 0xfd, + 0x08, 0xf0, 0x97, 0xf3, 0x56, 0x44, 0x08, 0xe2, 0xdd, 0x2a, 0x00, 0x00, + 0x64, 0xc0, 0x2c, 0xc0, 0x2b, 0xc0, 0x30, 0x00, 0x9d, 0xc0, 0x2e, 0xc0, + 0x32, 0x00, 0x9f, 0x00, 0xa3, 0xc0, 0x2f, 0x00, 0x9c, 0xc0, 0x2d, 0xc0, + 0x31, 0x00, 0x9e, 0x00, 0xa2, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x3d, 0xc0, + 0x26, 0xc0, 0x2a, 0x00, 0x6b, 0x00, 0x6a, 0xc0, 0x0a, 0xc0, 0x14, 0x00, + 0x35, 0xc0, 0x05, 0xc0, 0x0f, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x23, 0xc0, + 0x27, 0x00, 0x3c, 0xc0, 0x25, 0xc0, 0x29, 0x00, 0x67, 0x00, 0x40, 0xc0, + 0x09, 0xc0, 0x13, 0x00, 0x2f, 0xc0, 0x04, 0xc0, 0x0e, 0x00, 0x33, 0x00, + 0x32, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x0a, 0xc0, 0x03, 0xc0, 0x0d, 0x00, + 0x16, 0x00, 0x13, 0x00, 0xff, 0x01, 0x00, 0x00, 0x5d, 0x00, 0x0a, 0x00, + 0x16, 0x00, 0x14, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x09, 0x00, + 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x16, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a, 0x06, + 0x03, 0x06, 0x01, 0x05, 0x03, 0x05, 0x01, 0x04, 0x03, 0x04, 0x01, 0x04, + 0x02, 0x03, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x00, 0x11, 0x00, 0x10, 0x00, 0x0e, 0x02, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x05, 0x01, 0x00, 0x00, 0x00, 0x00}, + true}, + {"JDK 9 with SNI and ALPN enabled and no SCSV cipher", + {0x03, 0x03, 0x37, 0xa6, 0x4b, 0x58, 0x02, 0xd0, 0x77, 0xe4, 0x48, 0xaf, + 0x90, 0x50, 0x45, 0xd5, 0x2f, 0xe7, 0x98, 0x5d, 0x54, 0x93, 0x85, 0x3a, + 0xde, 0xb6, 0xaa, 0x47, 0xef, 0x7f, 0xb5, 0x52, 0xe6, 0xf8, 0x00, 0x00, + 0x02, 0xc0, 0x24, 0x01, 0x00, 0x00, 0x87, 0x00, 0x0a, 0x00, 0x16, 0x00, + 0x14, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, 0x00, + 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x0b, 0x00, + 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a, 0x06, 0x03, 0x06, + 0x01, 0x05, 0x03, 0x05, 0x01, 0x04, 0x03, 0x04, 0x01, 0x04, 0x02, 0x03, + 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x03, 0x02, 0x01, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x11, 0x00, 0x10, 0x00, + 0x0e, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x0d, 0x00, 0x0b, 0x07, 0x68, 0x74, 0x74, 0x70, 0x31, + 0x2e, 0x31, 0x02, 0x68, 0x32, 0xff, 0x01, 0x00, 0x01, 0x00}, + true}, + {"JDK 9 with EMS extension appended", + {0x03, 0x03, 0x0c, 0xe6, 0x06, 0xc6, 0x5d, 0x38, 0xb4, 0x5e, 0x3a, 0xd5, + 0xb0, 0x5f, 0x5b, 0x84, 0x3b, 0xff, 0x86, 0x4f, 0xb0, 0x3f, 0xc1, 0xfd, + 0x08, 0xf0, 0x97, 0xf3, 0x56, 0x44, 0x08, 0xe2, 0xdd, 0x2a, 0x00, 0x00, + 0x64, 0xc0, 0x2c, 0xc0, 0x2b, 0xc0, 0x30, 0x00, 0x9d, 0xc0, 0x2e, 0xc0, + 0x32, 0x00, 0x9f, 0x00, 0xa3, 0xc0, 0x2f, 0x00, 0x9c, 0xc0, 0x2d, 0xc0, + 0x31, 0x00, 0x9e, 0x00, 0xa2, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x3d, 0xc0, + 0x26, 0xc0, 0x2a, 0x00, 0x6b, 0x00, 0x6a, 0xc0, 0x0a, 0xc0, 0x14, 0x00, + 0x35, 0xc0, 0x05, 0xc0, 0x0f, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x23, 0xc0, + 0x27, 0x00, 0x3c, 0xc0, 0x25, 0xc0, 0x29, 0x00, 0x67, 0x00, 0x40, 0xc0, + 0x09, 0xc0, 0x13, 0x00, 0x2f, 0xc0, 0x04, 0xc0, 0x0e, 0x00, 0x33, 0x00, + 0x32, 0xc0, 0x08, 0xc0, 0x12, 0x00, 0x0a, 0xc0, 0x03, 0xc0, 0x0d, 0x00, + 0x16, 0x00, 0x13, 0x00, 0xff, 0x01, 0x00, 0x00, 0x61, 0x00, 0x0a, 0x00, + 0x16, 0x00, 0x14, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x09, 0x00, + 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x16, 0x00, + 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a, 0x06, + 0x03, 0x06, 0x01, 0x05, 0x03, 0x05, 0x01, 0x04, 0x03, 0x04, 0x01, 0x04, + 0x02, 0x03, 0x03, 0x03, 0x01, 0x03, 0x02, 0x02, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x00, 0x11, 0x00, 0x10, 0x00, 0x0e, 0x02, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00}, + false}, + {"Chrome 61", + {0x03, 0x03, 0x33, 0x43, 0x8a, 0x6f, 0x76, 0xdd, 0x84, 0x3f, 0x8d, 0xaa, + 0x43, 0xf1, 0x86, 0xee, 0xdd, 0x97, 0x96, 0x54, 0xf6, 0x17, 0x2c, 0xde, + 0x69, 0xfe, 0x5e, 0x53, 0xaa, 0x47, 0xee, 0xad, 0xd7, 0x47, 0x00, 0x00, + 0x1c, 0x3a, 0x3a, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, + 0xa9, 0xcc, 0xa8, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, + 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x77, 0x8a, 0x8a, 0x00, + 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x0c, + 0x00, 0x00, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, + 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x14, + 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, + 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x05, 0x00, 0x05, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, + 0x31, 0x2e, 0x31, 0x75, 0x50, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, + 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x4a, 0x4a, 0x00, 0x1d, 0x00, + 0x17, 0x00, 0x18, 0x6a, 0x6a, 0x00, 0x01, 0x00}, + false}, + {"Firefox 55", + {0x03, 0x03, 0x06, 0x8e, 0xf8, 0xf7, 0x7a, 0xfd, 0xce, 0x45, 0xb0, 0x39, + 0xbe, 0xa4, 0x55, 0x27, 0xe2, 0x80, 0xc4, 0x0a, 0xbd, 0xce, 0x56, 0x7a, + 0xbc, 0x1f, 0x26, 0x2f, 0xfa, 0xb9, 0xa1, 0x7e, 0xe6, 0xde, 0x00, 0x00, + 0x1e, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, + 0x30, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x33, 0x00, + 0x39, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x6a, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, + 0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, + 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x18, 0x00, 0x16, 0x04, + 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, + 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01}, + false}, + }; + for (const auto &t : kTests) { + SCOPED_TRACE(t.name); + + bssl::SSLMessage msg; + msg.is_v2_hello = false; + msg.type = SSL3_MT_CLIENT_HELLO; + CBS_init(&msg.body, t.in.data(), t.in.size()); + CBS_init(&msg.raw, nullptr, 0); // unused + + SSL_CLIENT_HELLO client_hello; + ASSERT_TRUE(bssl::ssl_client_hello_init(ssl.get(), &client_hello, msg)); + EXPECT_EQ(t.is_probably_java, bssl::ssl_is_probably_java(&client_hello)); + } +} + // TODO(davidben): Convert this file to GTest properly. TEST(SSLTest, AllTests) { if (!TestSSL_SESSIONEncoding(kOpenSSLSession) || diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc index 184eb44f..560d0cfe 100644 --- a/src/ssl/ssl_versions.cc +++ b/src/ssl/ssl_versions.cc @@ -36,6 +36,8 @@ int ssl_protocol_version_from_wire(uint16_t *out, uint16_t version) { case TLS1_3_DRAFT_VERSION: case TLS1_3_EXPERIMENT_VERSION: + case TLS1_3_EXPERIMENT2_VERSION: + case TLS1_3_EXPERIMENT3_VERSION: case TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION: *out = TLS1_3_VERSION; return 1; @@ -58,6 +60,8 @@ int ssl_protocol_version_from_wire(uint16_t *out, uint16_t version) { // decreasing preference. static const uint16_t kTLSVersions[] = { + TLS1_3_EXPERIMENT3_VERSION, + TLS1_3_EXPERIMENT2_VERSION, TLS1_3_EXPERIMENT_VERSION, TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION, TLS1_3_DRAFT_VERSION, @@ -103,6 +107,8 @@ static int set_version_bound(const SSL_PROTOCOL_METHOD *method, uint16_t *out, // map it to some representative TLS 1.3 draft version. if (version == TLS1_3_DRAFT_VERSION || version == TLS1_3_EXPERIMENT_VERSION || + version == TLS1_3_EXPERIMENT2_VERSION || + version == TLS1_3_EXPERIMENT3_VERSION || version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION); return 0; @@ -229,6 +235,8 @@ static const char *ssl_version_to_string(uint16_t version) { // Report TLS 1.3 draft version as TLS 1.3 in the public API. case TLS1_3_DRAFT_VERSION: case TLS1_3_EXPERIMENT_VERSION: + case TLS1_3_EXPERIMENT2_VERSION: + case TLS1_3_EXPERIMENT3_VERSION: case TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION: return "TLSv1.3"; @@ -275,6 +283,8 @@ int ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) { if (ssl->server) { if (ssl->tls13_variant == tls13_default && (version == TLS1_3_EXPERIMENT_VERSION || + version == TLS1_3_EXPERIMENT2_VERSION || + version == TLS1_3_EXPERIMENT3_VERSION || version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION)) { return 0; } @@ -282,6 +292,10 @@ int ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) { if ((ssl->tls13_variant != tls13_experiment && ssl->tls13_variant != tls13_no_session_id_experiment && version == TLS1_3_EXPERIMENT_VERSION) || + (ssl->tls13_variant != tls13_experiment2 && + version == TLS1_3_EXPERIMENT2_VERSION) || + (ssl->tls13_variant != tls13_experiment3 && + version == TLS1_3_EXPERIMENT3_VERSION) || (ssl->tls13_variant != tls13_record_type_experiment && version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) || (ssl->tls13_variant != tls13_default && @@ -341,6 +355,27 @@ int ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert, return 0; } +bool ssl_is_resumption_experiment(uint16_t version) { + return version == TLS1_3_EXPERIMENT_VERSION || + version == TLS1_3_EXPERIMENT2_VERSION || + version == TLS1_3_EXPERIMENT3_VERSION; +} + +bool ssl_is_resumption_variant(enum tls13_variant_t variant) { + return variant == tls13_experiment || variant == tls13_experiment2 || + variant == tls13_experiment3; +} + +bool ssl_is_resumption_client_ccs_experiment(uint16_t version) { + return version == TLS1_3_EXPERIMENT_VERSION || + version == TLS1_3_EXPERIMENT2_VERSION; +} + +bool ssl_is_resumption_record_version_experiment(uint16_t version) { + return version == TLS1_3_EXPERIMENT2_VERSION || + version == TLS1_3_EXPERIMENT3_VERSION; +} + } // namespace bssl using namespace bssl; @@ -364,7 +399,10 @@ int SSL_set_max_proto_version(SSL *ssl, uint16_t 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 || ret == TLS1_3_EXPERIMENT_VERSION || + if (ret == TLS1_3_DRAFT_VERSION || + ret == TLS1_3_EXPERIMENT_VERSION || + ret == TLS1_3_EXPERIMENT2_VERSION || + ret == TLS1_3_EXPERIMENT3_VERSION || ret == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) { return TLS1_3_VERSION; } diff --git a/src/ssl/t1_enc.cc b/src/ssl/t1_enc.cc index f917ed76..0283c6ee 100644 --- a/src/ssl/t1_enc.cc +++ b/src/ssl/t1_enc.cc @@ -422,7 +422,7 @@ int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which) { } UniquePtr<SSLAEADContext> aead_ctx = SSLAEADContext::Create( - is_read ? evp_aead_open : evp_aead_seal, ssl3_protocol_version(ssl), + is_read ? evp_aead_open : evp_aead_seal, ssl->version, SSL_is_dtls(ssl), hs->new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); if (!aead_ctx) { diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go index d5b017f1..19edb7f5 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -35,6 +35,8 @@ const ( const ( tls13DraftVersion = 0x7f12 tls13ExperimentVersion = 0x7e01 + tls13Experiment2Version = 0x7e02 + tls13Experiment3Version = 0x7e03 tls13RecordTypeExperimentVersion = 0x7a12 ) @@ -43,10 +45,14 @@ const ( TLS13Experiment = 1 TLS13RecordTypeExperiment = 2 TLS13NoSessionIDExperiment = 3 + TLS13Experiment2 = 4 + TLS13Experiment3 = 5 ) var allTLSWireVersions = []uint16{ tls13DraftVersion, + tls13Experiment3Version, + tls13Experiment2Version, tls13ExperimentVersion, tls13RecordTypeExperimentVersion, VersionTLS12, @@ -276,6 +282,7 @@ type ClientSessionState struct { sessionId []uint8 // Session ID supplied by the server. nil if the session has a ticket. sessionTicket []uint8 // Encrypted ticket used for session resumption with server vers uint16 // SSL/TLS version negotiated for the session + wireVersion uint16 // Wire SSL/TLS version negotiated for the session cipherSuite uint16 // Ciphersuite negotiated for the session masterSecret []byte // MasterSecret generated by client on a full handshake handshakeHash []byte // Handshake hash for Channel ID purposes. @@ -1439,6 +1446,11 @@ type ProtocolBugs struct { // PadClientHello, if non-zero, pads the ClientHello to a multiple of // that many bytes. PadClientHello int + + // SendOnlyECExtensions omits all extensions except supported_groups and + // ec_point_formats, in order to trigger the Java ClientHello + // fingerprint. + SendOnlyECExtensions bool } func (c *Config) serverInit() { @@ -1539,11 +1551,45 @@ func (c *Config) defaultCurves() map[CurveID]bool { return defaultCurves } +func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) { + if isDTLS { + switch vers { + case VersionDTLS12: + return VersionTLS12, true + case VersionDTLS10: + return VersionTLS10, true + } + } else { + switch vers { + case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12: + return vers, true + case tls13DraftVersion, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version, tls13RecordTypeExperimentVersion: + return VersionTLS13, true + } + } + + return 0, false +} + +func isResumptionExperiment(vers uint16) bool { + return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Experiment3Version +} + +func isResumptionClientCCSExperiment(vers uint16) bool { + return vers == tls13ExperimentVersion || vers == tls13Experiment2Version +} + +func isResumptionRecordVersionExperiment(vers uint16) bool { + return vers == tls13Experiment2Version || vers == tls13Experiment3Version +} + // 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) { if (c.TLS13Variant != TLS13Experiment && c.TLS13Variant != TLS13NoSessionIDExperiment && wireVers == tls13ExperimentVersion) || + (c.TLS13Variant != TLS13Experiment2 && wireVers == tls13Experiment2Version) || + (c.TLS13Variant != TLS13Experiment3 && wireVers == tls13Experiment3Version) || (c.TLS13Variant != TLS13RecordTypeExperiment && wireVers == tls13RecordTypeExperimentVersion) || (c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) { return 0, false diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go index 2332e6bf..25123b15 100644 --- a/src/ssl/test/runner/conn.go +++ b/src/ssl/test/runner/conn.go @@ -151,14 +151,15 @@ func (c *Conn) SetWriteDeadline(t time.Time) error { type halfConn struct { sync.Mutex - err error // first permanent error - version uint16 // protocol version - isDTLS bool - cipher interface{} // cipher algorithm - mac macFunction - seq [8]byte // 64-bit sequence number - outSeq [8]byte // Mapped sequence number - bfree *block // list of free blocks + err error // first permanent error + version uint16 // protocol version + wireVersion uint16 // wire version + isDTLS bool + cipher interface{} // cipher algorithm + mac macFunction + seq [8]byte // 64-bit sequence number + outSeq [8]byte // Mapped sequence number + bfree *block // list of free blocks nextCipher interface{} // next encryption state nextMac macFunction // next MAC algorithm @@ -188,7 +189,12 @@ func (hc *halfConn) error() error { // prepareCipherSpec sets the encryption and MAC states // that a subsequent changeCipherSpec will use. func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) { - hc.version = version + hc.wireVersion = version + protocolVersion, ok := wireToVersion(version, hc.isDTLS) + if !ok { + panic("TLS: unknown version") + } + hc.version = protocolVersion hc.nextCipher = cipher hc.nextMac = mac } @@ -215,7 +221,12 @@ func (hc *halfConn) changeCipherSpec(config *Config) error { // useTrafficSecret sets the current cipher state for TLS 1.3. func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) { - hc.version = version + hc.wireVersion = version + protocolVersion, ok := wireToVersion(version, hc.isDTLS) + if !ok { + panic("TLS: unknown version") + } + hc.version = protocolVersion hc.cipher = deriveTrafficAEAD(version, suite, secret, side) if hc.config.Bugs.NullAllCiphers { hc.cipher = nullCipher{} @@ -237,7 +248,7 @@ func (hc *halfConn) doKeyUpdate(c *Conn, isOutgoing bool) { if c.isClient == isOutgoing { side = clientWrite } - hc.useTrafficSecret(hc.version, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), side) + hc.useTrafficSecret(hc.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), side) } // incSeq increments the sequence number. @@ -781,6 +792,9 @@ RestartReadRecord: if c.vers >= VersionTLS13 { expect = VersionTLS10 } + if isResumptionRecordVersionExperiment(c.wireVersion) { + expect = VersionTLS12 + } } else { expect = c.config.Bugs.ExpectInitialRecordVersion } @@ -929,7 +943,7 @@ Again: c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) break } - if c.wireVersion != tls13ExperimentVersion { + if !isResumptionExperiment(c.wireVersion) { err := c.in.changeCipherSpec(c.config) if err != nil { c.in.setErrorLocked(c.sendAlert(err.(alert))) @@ -1125,6 +1139,11 @@ func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) { // layer to {3, 1}. vers = VersionTLS10 } + if isResumptionRecordVersionExperiment(c.wireVersion) || isResumptionRecordVersionExperiment(c.out.wireVersion) { + vers = VersionTLS12 + } else { + } + if c.config.Bugs.SendRecordVersion != 0 { vers = c.config.Bugs.SendRecordVersion } @@ -1156,7 +1175,7 @@ func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) { } c.out.freeBlock(b) - if typ == recordTypeChangeCipherSpec && c.wireVersion != tls13ExperimentVersion { + if typ == recordTypeChangeCipherSpec && !isResumptionExperiment(c.wireVersion) { err = c.out.changeCipherSpec(c.config) if err != nil { return n, c.sendAlertLocked(alertLevelError, err.(alert)) @@ -1458,6 +1477,7 @@ func (c *Conn) processTLS13NewSessionTicket(newSessionTicket *newSessionTicketMs session := &ClientSessionState{ sessionTicket: newSessionTicket.ticket, vers: c.vers, + wireVersion: c.wireVersion, cipherSuite: cipherSuite.id, masterSecret: c.resumptionSecret, serverCertificates: c.peerCertificates, @@ -1881,6 +1901,10 @@ func (c *Conn) sendFakeEarlyData(len int) error { payload[0] = byte(recordTypeApplicationData) payload[1] = 3 payload[2] = 1 + if c.config.TLS13Variant == TLS13Experiment2 || c.config.TLS13Variant == TLS13Experiment3 { + payload[1] = 3 + payload[2] = 3 + } payload[3] = byte(len >> 8) payload[4] = byte(len) _, err := c.conn.Write(payload) diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go index 619710c3..bd111e0b 100644 --- a/src/ssl/test/runner/dtls.go +++ b/src/ssl/test/runner/dtls.go @@ -23,26 +23,6 @@ import ( "net" ) -func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) { - if isDTLS { - switch vers { - case VersionDTLS12: - return VersionTLS12, true - case VersionDTLS10: - return VersionTLS10, true - } - } else { - switch vers { - case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12: - return vers, true - case tls13DraftVersion, tls13ExperimentVersion, tls13RecordTypeExperimentVersion: - return VersionTLS13, true - } - } - - return 0, false -} - func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) { recordHeaderLen := dtlsRecordHeaderLen diff --git a/src/ssl/test/runner/fuzzer_mode.json b/src/ssl/test/runner/fuzzer_mode.json index 9fa49b5b..f2ecae0b 100644 --- a/src/ssl/test/runner/fuzzer_mode.json +++ b/src/ssl/test/runner/fuzzer_mode.json @@ -44,7 +44,7 @@ "*-EarlyData-ALPNOmitted1-Server": "Trial decryption does not work with the NULL cipher.", "*-EarlyData-ALPNOmitted2-Server": "Trial decryption does not work with the NULL cipher.", "*-EarlyData-RejectUnfinishedWrite-Client-*": "Trial decryption does not work with the NULL cipher.", - "*-EarlyData-Reject-Client": "Trial decryption does not work with the NULL cipher.", + "EarlyData-Reject-Client-*": "Trial decryption does not work with the NULL cipher.", "*-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 83f2d7dc..a04ffd04 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -97,6 +97,7 @@ func (c *Conn) clientHandshake() error { pskBinderFirst: c.config.Bugs.PSKBinderFirst, omitExtensions: c.config.Bugs.OmitExtensions, emptyExtensions: c.config.Bugs.EmptyExtensions, + sendOnlyECExtensions: c.config.Bugs.SendOnlyECExtensions, } if maxVersion >= VersionTLS13 { @@ -411,7 +412,7 @@ NextCipherSuite: finishedHash.addEntropy(session.masterSecret) finishedHash.Write(helloBytes) earlyTrafficSecret := finishedHash.deriveSecret(earlyTrafficLabel) - c.out.useTrafficSecret(session.vers, pskCipherSuite, earlyTrafficSecret, clientWrite) + c.out.useTrafficSecret(session.wireVersion, pskCipherSuite, earlyTrafficSecret, clientWrite) for _, earlyData := range c.config.Bugs.SendEarlyData { if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil { return err @@ -690,7 +691,7 @@ NextCipherSuite: func (hs *clientHandshakeState) doTLS13Handshake() error { c := hs.c - if c.wireVersion == tls13ExperimentVersion && !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) { + if isResumptionExperiment(c.wireVersion) && !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) { return errors.New("tls: session IDs did not match.") } @@ -744,7 +745,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { hs.finishedHash.addEntropy(zeroSecret) } - if c.wireVersion == tls13ExperimentVersion { + if isResumptionExperiment(c.wireVersion) { if err := c.readRecord(recordTypeChangeCipherSpec); err != nil { return err } @@ -754,7 +755,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { // traffic key. clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) - c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret, serverWrite) msg, err := c.readHandshake() if err != nil { @@ -888,7 +889,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { // Switch to application data keys on read. In particular, any alerts // from the client certificate are read over these keys. - c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret, serverWrite) // If we're expecting 0.5-RTT messages from the server, read them // now. @@ -930,11 +931,11 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { c.sendAlert(alertEndOfEarlyData) } - if c.wireVersion == tls13ExperimentVersion { + if isResumptionClientCCSExperiment(c.wireVersion) { c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) } - c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite) + c.out.useTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret, clientWrite) if certReq != nil && !c.config.Bugs.SkipClientCertificate { certMsg := &certificateMsg{ @@ -1020,7 +1021,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { c.flushHandshake() // Switch to application data keys. - c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite) + c.out.useTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret, clientWrite) c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel) return nil @@ -1287,8 +1288,8 @@ func (hs *clientHandshakeState) establishKeys() error { serverCipher = hs.suite.aead(c.vers, serverKey, serverIV) } - c.in.prepareCipherSpec(c.vers, serverCipher, serverHash) - c.out.prepareCipherSpec(c.vers, clientCipher, clientHash) + c.in.prepareCipherSpec(c.wireVersion, serverCipher, serverHash) + c.out.prepareCipherSpec(c.wireVersion, clientCipher, clientHash) return nil } diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go index d65119f6..2e6d2865 100644 --- a/src/ssl/test/runner/handshake_messages.go +++ b/src/ssl/test/runner/handshake_messages.go @@ -176,6 +176,7 @@ type clientHelloMsg struct { omitExtensions bool emptyExtensions bool pad int + sendOnlyECExtensions bool } func (m *clientHelloMsg) equal(i interface{}) bool { @@ -224,7 +225,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool { m.pskBinderFirst == m1.pskBinderFirst && m.omitExtensions == m1.omitExtensions && m.emptyExtensions == m1.emptyExtensions && - m.pad == m1.pad + m.pad == m1.pad && + m.sendOnlyECExtensions == m1.sendOnlyECExtensions } func (m *clientHelloMsg) marshal() []byte { @@ -312,22 +314,6 @@ func (m *clientHelloMsg) marshal() []byte { certificateStatusRequest.addU16(0) // ResponderID length certificateStatusRequest.addU16(0) // Extensions length } - if len(m.supportedCurves) > 0 { - // http://tools.ietf.org/html/rfc4492#section-5.1.1 - extensions.addU16(extensionSupportedCurves) - supportedCurvesList := extensions.addU16LengthPrefixed() - supportedCurves := supportedCurvesList.addU16LengthPrefixed() - for _, curve := range m.supportedCurves { - supportedCurves.addU16(uint16(curve)) - } - } - if len(m.supportedPoints) > 0 { - // http://tools.ietf.org/html/rfc4492#section-5.1.2 - extensions.addU16(extensionSupportedPoints) - supportedPointsList := extensions.addU16LengthPrefixed() - supportedPoints := supportedPointsList.addU8LengthPrefixed() - supportedPoints.addBytes(m.supportedPoints) - } if m.hasKeyShares { extensions.addU16(extensionKeyShare) keyShareList := extensions.addU16LengthPrefixed() @@ -440,6 +426,30 @@ func (m *clientHelloMsg) marshal() []byte { customExt := extensions.addU16LengthPrefixed() customExt.addBytes([]byte(m.customExtension)) } + + // Discard all extensions but the curve-related ones to trigger the Java + // fingerprinter. + if m.sendOnlyECExtensions { + hello.discardChild() + extensions = hello.addU16LengthPrefixed() + } + if len(m.supportedCurves) > 0 { + // http://tools.ietf.org/html/rfc4492#section-5.1.1 + extensions.addU16(extensionSupportedCurves) + supportedCurvesList := extensions.addU16LengthPrefixed() + supportedCurves := supportedCurvesList.addU16LengthPrefixed() + for _, curve := range m.supportedCurves { + supportedCurves.addU16(uint16(curve)) + } + } + if len(m.supportedPoints) > 0 { + // http://tools.ietf.org/html/rfc4492#section-5.1.2 + extensions.addU16(extensionSupportedPoints) + supportedPointsList := extensions.addU16LengthPrefixed() + supportedPoints := supportedPointsList.addU8LengthPrefixed() + supportedPoints.addBytes(m.supportedPoints) + } + // The PSK extension must be last (draft-ietf-tls-tls13-18 section 4.2.6). if len(m.pskIdentities) > 0 && !m.pskBinderFirst { extensions.addU16(extensionPreSharedKey) @@ -456,6 +466,8 @@ func (m *clientHelloMsg) marshal() []byte { } } + // This must be swapped with PSK (with some length computation) if we + // ever need to support PadClientHello and TLS 1.3. if m.pad != 0 && hello.len()%m.pad != 0 { extensions.addU16(extensionPadding) padding := extensions.addU16LengthPrefixed() @@ -881,19 +893,19 @@ func (m *serverHelloMsg) marshal() []byte { } if m.versOverride != 0 { hello.addU16(m.versOverride) - } else if m.vers == tls13ExperimentVersion { + } else if isResumptionExperiment(m.vers) { hello.addU16(VersionTLS12) } else { hello.addU16(m.vers) } hello.addBytes(m.random) - if vers < VersionTLS13 || m.vers == tls13ExperimentVersion { + if vers < VersionTLS13 || isResumptionExperiment(m.vers) { sessionId := hello.addU8LengthPrefixed() sessionId.addBytes(m.sessionId) } hello.addU16(m.cipherSuite) - if vers < VersionTLS13 || m.vers == tls13ExperimentVersion { + if vers < VersionTLS13 || isResumptionExperiment(m.vers) { hello.addU8(m.compressionMethod) } @@ -912,7 +924,7 @@ func (m *serverHelloMsg) marshal() []byte { extensions.addU16(2) // Length extensions.addU16(m.pskIdentity) } - if m.vers == tls13ExperimentVersion || m.supportedVersOverride != 0 { + if isResumptionExperiment(m.vers) || m.supportedVersOverride != 0 { extensions.addU16(extensionSupportedVersions) extensions.addU16(2) // Length if m.supportedVersOverride != 0 { @@ -966,7 +978,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { } m.random = data[6:38] data = data[38:] - if vers < VersionTLS13 || m.vers == tls13ExperimentVersion { + if vers < VersionTLS13 || isResumptionExperiment(m.vers) { sessionIdLen := int(data[0]) if sessionIdLen > 32 || len(data) < 1+sessionIdLen { return false @@ -979,7 +991,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { } m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]) data = data[2:] - if vers < VersionTLS13 || m.vers == tls13ExperimentVersion { + if vers < VersionTLS13 || isResumptionExperiment(m.vers) { if len(data) < 1 { return false } @@ -1068,7 +1080,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { m.pskIdentity = uint16(d[0])<<8 | uint16(d[1]) m.hasPSKIdentity = true case extensionSupportedVersions: - if m.vers != tls13ExperimentVersion { + if !isResumptionExperiment(m.vers) { return false } default: diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index 4a056b92..0a67a80c 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -281,7 +281,7 @@ func (hs *serverHandshakeState) readClientHello() error { } if config.Bugs.ExpectNoTLS12Session { - if len(hs.clientHello.sessionId) > 0 && c.wireVersion != tls13ExperimentVersion { + if len(hs.clientHello.sessionId) > 0 && !isResumptionExperiment(c.wireVersion) { return fmt.Errorf("tls: client offered an unexpected session ID") } if len(hs.clientHello.sessionTicket) > 0 { @@ -668,7 +668,7 @@ ResendHelloRetryRequest: } if encryptedExtensions.extensions.hasEarlyData { earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyTrafficLabel) - c.in.useTrafficSecret(c.vers, hs.suite, earlyTrafficSecret, clientWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, earlyTrafficSecret, clientWrite) for _, expectedMsg := range config.Bugs.ExpectEarlyData { if err := c.readRecord(recordTypeApplicationData); err != nil { @@ -763,13 +763,13 @@ ResendHelloRetryRequest: } c.flushHandshake() - if c.wireVersion == tls13ExperimentVersion { + if isResumptionExperiment(c.wireVersion) { c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) } // Switch to handshake traffic keys. serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) - c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite) + c.out.useTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret, serverWrite) // Derive handshake traffic read key, but don't switch yet. clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) @@ -910,7 +910,7 @@ ResendHelloRetryRequest: // Switch to application data keys on write. In particular, any alerts // from the client certificate are sent over these keys. - c.out.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite) + c.out.useTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret, serverWrite) // Send 0.5-RTT messages. for _, halfRTTMsg := range config.Bugs.SendHalfRTTData { @@ -929,14 +929,14 @@ ResendHelloRetryRequest: } } - if c.wireVersion == tls13ExperimentVersion && !c.skipEarlyData { + if isResumptionClientCCSExperiment(c.wireVersion) && !c.skipEarlyData { if err := c.readRecord(recordTypeChangeCipherSpec); err != nil { return err } } // Switch input stream to handshake traffic keys. - c.in.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret, clientWrite) // If we requested a client certificate, then the client must send a // certificate message, even if it's empty. @@ -1040,7 +1040,7 @@ ResendHelloRetryRequest: hs.writeClientHash(clientFinished.marshal()) // Switch to application data keys on read. - c.in.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret, clientWrite) c.cipherSuite = hs.suite c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel) @@ -1697,8 +1697,8 @@ func (hs *serverHandshakeState) establishKeys() error { serverCipher = hs.suite.aead(c.vers, serverKey, serverIV) } - c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) - c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) + c.in.prepareCipherSpec(c.wireVersion, clientCipher, clientHash) + c.out.prepareCipherSpec(c.wireVersion, serverCipher, serverHash) return nil } diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index 2ffe795e..ee72c2ef 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -1303,6 +1303,20 @@ var tlsVersions = []tlsVersion{ tls13Variant: TLS13Experiment, }, { + name: "TLS13Experiment2", + version: VersionTLS13, + excludeFlag: "-no-tls13", + versionWire: tls13Experiment2Version, + tls13Variant: TLS13Experiment2, + }, + { + name: "TLS13Experiment3", + version: VersionTLS13, + excludeFlag: "-no-tls13", + versionWire: tls13Experiment3Version, + tls13Variant: TLS13Experiment3, + }, + { name: "TLS13RecordTypeExperiment", version: VersionTLS13, excludeFlag: "-no-tls13", @@ -2783,6 +2797,25 @@ read alert 1 0 shouldFail: true, expectedLocalError: "local error: record overflow", }, + { + // Test that Java-like ClientHellos are provided session + // IDs but resumption is always declined. This is to + // workaround a bug that causes connection failures when + // certificates rotate. + testType: serverTest, + name: "JavaWorkaround", + config: Config{ + MaxVersion: VersionTLS12, + CurvePreferences: []CurveID{CurveP256, CurveP384, CurveP521}, + SessionTicketsDisabled: true, + Bugs: ProtocolBugs{ + SendOnlyECExtensions: true, + }, + }, + flags: []string{"-expect-session-id"}, + resumeSession: true, + expectResumeRejected: true, + }, } testCases = append(testCases, basicTests...) @@ -4079,85 +4112,6 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { tests = append(tests, testCase{ testType: clientTest, - name: "TLS13-EarlyData-Client", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, - }, - }, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-accept-early-data", - "-on-resume-shim-writes-first", - }, - }) - - tests = append(tests, testCase{ - testType: clientTest, - name: "TLS13Experiment-EarlyData-Client", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, - }, - }, - tls13Variant: TLS13Experiment, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-accept-early-data", - "-on-resume-shim-writes-first", - }, - }) - - tests = append(tests, testCase{ - testType: clientTest, - name: "TLS13RecordTypeExperiment-EarlyData-Client", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - TLS13Variant: TLS13RecordTypeExperiment, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - TLS13Variant: TLS13RecordTypeExperiment, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, - }, - }, - tls13Variant: TLS13RecordTypeExperiment, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-accept-early-data", - "-on-resume-shim-writes-first", - }, - }) - - tests = append(tests, testCase{ - testType: clientTest, name: "TLS13-EarlyData-TooMuchData-Client", config: Config{ MaxVersion: VersionTLS13, @@ -4244,68 +4198,6 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { tests = append(tests, testCase{ testType: serverTest, - name: "TLS13-EarlyData-Server", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendEarlyData: [][]byte{{1, 2, 3, 4}}, - ExpectEarlyDataAccepted: true, - ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}}, - }, - }, - messageCount: 2, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-accept-early-data", - }, - }) - - tests = append(tests, testCase{ - testType: serverTest, - name: "TLS13Experiment-EarlyData-Server", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendEarlyData: [][]byte{{1, 2, 3, 4}}, - ExpectEarlyDataAccepted: true, - ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}}, - }, - }, - tls13Variant: TLS13Experiment, - messageCount: 2, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-accept-early-data", - }, - }) - - tests = append(tests, testCase{ - testType: serverTest, - name: "TLS13RecordTypeExperiment-EarlyData-Server", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendEarlyData: [][]byte{{1, 2, 3, 4}}, - ExpectEarlyDataAccepted: true, - ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}}, - }, - }, - tls13Variant: TLS13RecordTypeExperiment, - messageCount: 2, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-accept-early-data", - }, - }) - - tests = append(tests, testCase{ - testType: serverTest, name: "TLS13-MaxEarlyData-Server", config: Config{ MaxVersion: VersionTLS13, @@ -5163,6 +5055,9 @@ func addVersionNegotiationTests() { serverVers := expectedServerVersion if expectedServerVersion >= VersionTLS13 { serverVers = VersionTLS10 + if runnerVers.tls13Variant == TLS13Experiment2 || runnerVers.tls13Variant == TLS13Experiment3 { + serverVers = VersionTLS12 + } } serverVers = recordVersionToWire(serverVers, protocol) @@ -10815,40 +10710,170 @@ func addTLS13HandshakeTests() { expectedError: ":DUPLICATE_KEY_SHARE:", }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "SkipEarlyData", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendFakeEarlyDataLength: 4, + for _, version := range allVersions(tls) { + if version.version != VersionTLS13 { + continue + } + name := version.name + variant := version.tls13Variant + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendFakeEarlyDataLength: 4, + }, }, - }, - }) + tls13Variant: variant, + }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "SkipEarlyData-TLS13Experiment", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendFakeEarlyDataLength: 4, + // Test that enabling a TLS 1.3 variant does not interfere with + // TLS 1.2 session ID resumption. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ResumeTLS12SessionID-" + name, + config: Config{ + MaxVersion: VersionTLS12, + SessionTicketsDisabled: true, }, - }, - tls13Variant: TLS13Experiment, - }) + tls13Variant: variant, + resumeSession: true, + }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "SkipEarlyData-TLS13RecordTypeExperiment", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendFakeEarlyDataLength: 4, + // Test that the server correctly echoes back session IDs of + // various lengths. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "EmptySessionID-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientHelloSessionID: []byte{}, + }, }, - }, - tls13Variant: TLS13RecordTypeExperiment, - }) + tls13Variant: variant, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ShortSessionID-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientHelloSessionID: make([]byte, 16), + }, + }, + tls13Variant: variant, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "FullSessionID-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientHelloSessionID: make([]byte, 32), + }, + }, + tls13Variant: variant, + }) + + hasSessionID := false + hasEmptySessionID := false + if variant == TLS13NoSessionIDExperiment { + hasEmptySessionID = true + } else if variant != TLS13Default && variant != TLS13RecordTypeExperiment { + hasSessionID = true + } + + // Test that the client sends a fake session ID in the correct experiments. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "TLS13SessionID-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + ExpectClientHelloSessionID: hasSessionID, + ExpectEmptyClientHelloSessionID: hasEmptySessionID, + }, + }, + tls13Variant: variant, + }) + + testCases = append(testCases, testCase{ + testType: clientTest, + name: "EarlyData-Client-" + name, + config: Config{ + MaxVersion: VersionTLS13, + MinVersion: VersionTLS13, + MaxEarlyDataSize: 16384, + }, + resumeConfig: &Config{ + MaxVersion: VersionTLS13, + MinVersion: VersionTLS13, + MaxEarlyDataSize: 16384, + Bugs: ProtocolBugs{ + ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, + }, + }, + tls13Variant: variant, + resumeSession: true, + flags: []string{ + "-enable-early-data", + "-expect-early-data-info", + "-expect-accept-early-data", + "-on-resume-shim-writes-first", + }, + }) + + testCases = append(testCases, testCase{ + testType: clientTest, + name: "EarlyData-Reject-Client-" + name, + config: Config{ + MaxVersion: VersionTLS13, + MaxEarlyDataSize: 16384, + }, + resumeConfig: &Config{ + MaxVersion: VersionTLS13, + MaxEarlyDataSize: 16384, + Bugs: ProtocolBugs{ + AlwaysRejectEarlyData: true, + }, + }, + tls13Variant: variant, + resumeSession: true, + flags: []string{ + "-enable-early-data", + "-expect-early-data-info", + "-expect-reject-early-data", + "-on-resume-shim-writes-first", + }, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "EarlyData-Server-" + name, + config: Config{ + MaxVersion: VersionTLS13, + MinVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyData: [][]byte{{1, 2, 3, 4}}, + ExpectEarlyDataAccepted: true, + ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}}, + }, + }, + tls13Variant: variant, + messageCount: 2, + resumeSession: true, + flags: []string{ + "-enable-early-data", + "-expect-accept-early-data", + }, + }) + + } testCases = append(testCases, testCase{ testType: serverTest, @@ -11326,165 +11351,6 @@ func addTLS13HandshakeTests() { }, }, }) - - for _, noSessionID := range []bool{false, true} { - prefix := "TLS13Experiment" - variant := TLS13Experiment - if noSessionID { - prefix = "TLS13NoSessionIDExperiment" - variant = TLS13NoSessionIDExperiment - } - - // Test that enabling a TLS 1.3 variant does not interfere with - // TLS 1.2 session ID resumption. - testCases = append(testCases, testCase{ - testType: clientTest, - name: prefix + "-ResumeTLS12SessionID", - config: Config{ - MaxVersion: VersionTLS12, - SessionTicketsDisabled: true, - }, - resumeSession: true, - flags: []string{"-tls13-variant", strconv.Itoa(variant)}, - }) - - // Test that the server correctly echoes back session IDs of - // various lengths. - testCases = append(testCases, testCase{ - testType: serverTest, - name: prefix + "-EmptySessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendClientHelloSessionID: []byte{}, - }, - }, - tls13Variant: variant, - }) - - testCases = append(testCases, testCase{ - testType: serverTest, - name: prefix + "-ShortSessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendClientHelloSessionID: make([]byte, 16), - }, - }, - tls13Variant: variant, - }) - - testCases = append(testCases, testCase{ - testType: serverTest, - name: prefix + "-FullSessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendClientHelloSessionID: make([]byte, 32), - }, - }, - tls13Variant: variant, - }) - } - - // Test that the client sends a fake session ID in TLS13Experiment. - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13Experiment-RequireSessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - ExpectClientHelloSessionID: true, - }, - }, - tls13Variant: TLS13Experiment, - }) - - // Test that the client does not send a fake session ID in - // TLS13NoSessionIDExperiment. - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13NoSessionIDExperiment-RequireEmptySessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - ExpectEmptyClientHelloSessionID: true, - }, - }, - tls13Variant: TLS13NoSessionIDExperiment, - }) - - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13-EarlyData-Reject-Client", - config: Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - AlwaysRejectEarlyData: true, - }, - }, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-reject-early-data", - "-on-resume-shim-writes-first", - }, - }) - - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13Experiment-EarlyData-Reject-Client", - config: Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - AlwaysRejectEarlyData: true, - }, - }, - tls13Variant: TLS13Experiment, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-reject-early-data", - "-on-resume-shim-writes-first", - }, - }) - - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13RecordTypeExperiment-EarlyData-Reject-Client", - config: Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - AlwaysRejectEarlyData: true, - }, - }, - tls13Variant: TLS13RecordTypeExperiment, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-reject-early-data", - "-on-resume-shim-writes-first", - }, - }) - testCases = append(testCases, testCase{ testType: clientTest, name: "TLS13-EarlyData-RejectTicket-Client", diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc index 98ddaf30..f50b0777 100644 --- a/src/ssl/tls13_client.cc +++ b/src/ssl/tls13_client.cc @@ -159,10 +159,16 @@ static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) { static enum ssl_hs_wait_t do_send_second_client_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; // Restore the null cipher. We may have switched due to 0-RTT. - bssl::UniquePtr<SSLAEADContext> null_ctx = SSLAEADContext::CreateNullCipher(); + bssl::UniquePtr<SSLAEADContext> null_ctx = + SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); if (!null_ctx || - !ssl->method->set_write_state(ssl, std::move(null_ctx)) || - !ssl_write_client_hello(hs)) { + !ssl->method->set_write_state(ssl, std::move(null_ctx))) { + return ssl_hs_error; + } + + ssl->s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version); + + if (!ssl_write_client_hello(hs)) { return ssl_hs_error; } @@ -186,10 +192,10 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) { uint8_t compression_method; if (!CBS_get_u16(&body, &server_version) || !CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) || - (ssl->version == TLS1_3_EXPERIMENT_VERSION && + (ssl_is_resumption_experiment(ssl->version) && !CBS_get_u8_length_prefixed(&body, &session_id)) || !CBS_get_u16(&body, &cipher_suite) || - (ssl->version == TLS1_3_EXPERIMENT_VERSION && + (ssl_is_resumption_experiment(ssl->version) && (!CBS_get_u8(&body, &compression_method) || compression_method != 0)) || !CBS_get_u16_length_prefixed(&body, &extensions) || CBS_len(&body) != 0) { @@ -198,8 +204,9 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) { return ssl_hs_error; } - uint16_t expected_version = - ssl->version == TLS1_3_EXPERIMENT_VERSION ? TLS1_2_VERSION : ssl->version; + uint16_t expected_version = ssl_is_resumption_experiment(ssl->version) + ? TLS1_2_VERSION + : ssl->version; if (server_version != expected_version) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER); @@ -246,7 +253,7 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) { // supported_versions is parsed in handshake_client to select the experimental // TLS 1.3 version. - if (have_supported_versions && ssl->version != TLS1_3_EXPERIMENT_VERSION) { + if (have_supported_versions && !ssl_is_resumption_experiment(ssl->version)) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); return ssl_hs_error; @@ -351,7 +358,7 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) { ssl->method->next_message(ssl); hs->tls13_state = state_process_change_cipher_spec; - return ssl->version == TLS1_3_EXPERIMENT_VERSION + return ssl_is_resumption_experiment(ssl->version) ? ssl_hs_read_change_cipher_spec : ssl_hs_ok; } @@ -366,7 +373,7 @@ static enum ssl_hs_wait_t do_process_change_cipher_spec(SSL_HANDSHAKE *hs) { if (!hs->early_data_offered) { // If not sending early data, set client traffic keys now so that alerts are // encrypted. - if ((ssl->version == TLS1_3_EXPERIMENT_VERSION && + if ((ssl_is_resumption_client_ccs_experiment(ssl->version) && !ssl3_add_change_cipher_spec(ssl)) || !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret, hs->hash_len)) { @@ -574,7 +581,7 @@ static enum ssl_hs_wait_t do_send_end_of_early_data(SSL_HANDSHAKE *hs) { } if (hs->early_data_offered) { - if ((ssl->version == TLS1_3_EXPERIMENT_VERSION && + if ((ssl_is_resumption_client_ccs_experiment(ssl->version) && !ssl3_add_change_cipher_spec(ssl)) || !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret, hs->hash_len)) { diff --git a/src/ssl/tls13_enc.cc b/src/ssl/tls13_enc.cc index 7bd87c58..6ff9972e 100644 --- a/src/ssl/tls13_enc.cc +++ b/src/ssl/tls13_enc.cc @@ -150,8 +150,8 @@ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction, } UniquePtr<SSLAEADContext> traffic_aead = SSLAEADContext::Create( - direction, version, SSL_is_dtls(ssl), session->cipher, key, key_len, NULL, - 0, iv, iv_len); + direction, session->ssl_version, SSL_is_dtls(ssl), session->cipher, key, + key_len, NULL, 0, iv, iv_len); if (!traffic_aead) { return 0; } diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc index cd6baa42..550f3b50 100644 --- a/src/ssl/tls13_server.cc +++ b/src/ssl/tls13_server.cc @@ -528,7 +528,7 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; uint16_t version = ssl->version; - if (ssl->version == TLS1_3_EXPERIMENT_VERSION) { + if (ssl_is_resumption_experiment(ssl->version)) { version = TLS1_2_VERSION; } @@ -539,21 +539,21 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { !CBB_add_u16(&body, version) || !RAND_bytes(ssl->s3->server_random, sizeof(ssl->s3->server_random)) || !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) || - (ssl->version == TLS1_3_EXPERIMENT_VERSION && + (ssl_is_resumption_experiment(ssl->version) && (!CBB_add_u8_length_prefixed(&body, &session_id) || !CBB_add_bytes(&session_id, hs->session_id, hs->session_id_len))) || !CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) || - (ssl->version == TLS1_3_EXPERIMENT_VERSION && !CBB_add_u8(&body, 0)) || + (ssl_is_resumption_experiment(ssl->version) && !CBB_add_u8(&body, 0)) || !CBB_add_u16_length_prefixed(&body, &extensions) || !ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) || !ssl_ext_key_share_add_serverhello(hs, &extensions) || - (ssl->version == TLS1_3_EXPERIMENT_VERSION && + (ssl_is_resumption_experiment(ssl->version) && !ssl_ext_supported_versions_add_serverhello(hs, &extensions)) || !ssl_add_message_cbb(ssl, cbb.get())) { return ssl_hs_error; } - if (ssl->version == TLS1_3_EXPERIMENT_VERSION && + if (ssl_is_resumption_experiment(ssl->version) && !ssl3_add_change_cipher_spec(ssl)) { return ssl_hs_error; } @@ -706,7 +706,7 @@ static enum ssl_hs_wait_t do_process_end_of_early_data(SSL_HANDSHAKE *hs) { if (hs->early_data_offered && !hs->ssl->early_data_accepted) { return ssl_hs_ok; } - return hs->ssl->version == TLS1_3_EXPERIMENT_VERSION + return ssl_is_resumption_client_ccs_experiment(hs->ssl->version) ? ssl_hs_read_change_cipher_spec : ssl_hs_ok; } diff --git a/src/ssl/tls_record.cc b/src/ssl/tls_record.cc index 043ec621..5eeff3c5 100644 --- a/src/ssl/tls_record.cc +++ b/src/ssl/tls_record.cc @@ -143,7 +143,7 @@ static const uint8_t kMaxWarningAlerts = 4; static int ssl_needs_record_splitting(const SSL *ssl) { #if !defined(BORINGSSL_UNSAFE_FUZZER_MODE) return !ssl->s3->aead_write_ctx->is_null_cipher() && - ssl->s3->aead_write_ctx->version() < TLS1_1_VERSION && + ssl->s3->aead_write_ctx->ProtocolVersion() < TLS1_1_VERSION && (ssl->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0 && SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher()); #else @@ -205,17 +205,13 @@ enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, return ssl_open_record_partial; } - int version_ok; + bool version_ok; if (ssl->s3->aead_read_ctx->is_null_cipher()) { // Only check the first byte. Enforcing beyond that can prevent decoding // version negotiation failure alerts. version_ok = (version >> 8) == SSL3_VERSION_MAJOR; - } else if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) { - // Earlier versions of TLS switch the record version. - version_ok = version == ssl->version; } else { - // Starting TLS 1.3, the version field is frozen at {3, 1}. - version_ok = version == TLS1_VERSION; + version_ok = version == ssl->s3->aead_read_ctx->RecordVersion(); } if (!version_ok) { @@ -274,7 +270,7 @@ enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, // TLS 1.3 hides the record type inside the encrypted data. if (!ssl->s3->aead_read_ctx->is_null_cipher() && - ssl->s3->aead_read_ctx->version() >= TLS1_3_VERSION) { + ssl->s3->aead_read_ctx->ProtocolVersion() >= TLS1_3_VERSION) { // The outer record type is always application_data. if (type != SSL3_RT_APPLICATION_DATA) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_OUTER_RECORD_TYPE); @@ -350,7 +346,7 @@ static int do_seal_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out, uint8_t *extra_in = NULL; size_t extra_in_len = 0; if (!ssl->s3->aead_write_ctx->is_null_cipher() && - ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) { + ssl->s3->aead_write_ctx->ProtocolVersion() >= TLS1_3_VERSION) { // TLS 1.3 hides the actual record type inside the encrypted data. extra_in = &type; extra_in_len = 1; @@ -379,26 +375,17 @@ static int do_seal_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out, out_prefix[0] = type; } - // The TLS record-layer version number is meaningless and, starting in - // TLS 1.3, is frozen at TLS 1.0. But for historical reasons, SSL 3.0 - // 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->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; - } - out_prefix[1] = wire_version >> 8; - out_prefix[2] = wire_version & 0xff; + uint16_t record_version = ssl->s3->aead_write_ctx->RecordVersion(); + + out_prefix[1] = record_version >> 8; + out_prefix[2] = record_version & 0xff; out_prefix[3] = ciphertext_len >> 8; out_prefix[4] = ciphertext_len & 0xff; - if (!ssl->s3->aead_write_ctx->SealScatter(out_prefix + SSL3_RT_HEADER_LENGTH, - out, out_suffix, type, wire_version, - ssl->s3->write_sequence, in, in_len, - extra_in, extra_in_len) || + if (!ssl->s3->aead_write_ctx->SealScatter( + out_prefix + SSL3_RT_HEADER_LENGTH, out, out_suffix, type, + record_version, ssl->s3->write_sequence, in, in_len, extra_in, + extra_in_len) || !ssl_record_sequence_update(ssl->s3->write_sequence, 8)) { return 0; } @@ -429,7 +416,7 @@ static bool tls_seal_scatter_suffix_len(const SSL *ssl, size_t *out_suffix_len, uint8_t type, size_t in_len) { size_t extra_in_len = 0; if (!ssl->s3->aead_write_ctx->is_null_cipher() && - ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) { + ssl->s3->aead_write_ctx->ProtocolVersion() >= TLS1_3_VERSION) { // TLS 1.3 adds an extra byte for encrypted record type. extra_in_len = 1; } @@ -679,7 +666,7 @@ size_t SSL_max_seal_overhead(const SSL *ssl) { ret += ssl->s3->aead_write_ctx->MaxOverhead(); // TLS 1.3 needs an extra byte for the encrypted record type. if (!ssl->s3->aead_write_ctx->is_null_cipher() && - ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) { + ssl->s3->aead_write_ctx->ProtocolVersion() >= TLS1_3_VERSION) { ret += 1; } if (ssl_needs_record_splitting(ssl)) { diff --git a/src/tool/client.cc b/src/tool/client.cc index a5254b21..e2da29e7 100644 --- a/src/tool/client.cc +++ b/src/tool/client.cc @@ -318,6 +318,14 @@ static bool GetTLS13Variant(tls13_variant_t *out, const std::string &in) { *out = tls13_experiment; return true; } + if (in == "experiment2") { + *out = tls13_experiment2; + return true; + } + if (in == "experiment3") { + *out = tls13_experiment3; + return true; + } if (in == "record-type") { *out = tls13_record_type_experiment; return true; diff --git a/src/tool/server.cc b/src/tool/server.cc index 4cc183b1..1d649335 100644 --- a/src/tool/server.cc +++ b/src/tool/server.cc @@ -160,6 +160,13 @@ static void InfoCallback(const SSL *ssl, int type, int value) { } } +static FILE *g_keylog_file = nullptr; + +static void KeyLogCallback(const SSL *ssl, const char *line) { + fprintf(g_keylog_file, "%s\n", line); + fflush(g_keylog_file); +} + bool Server(const std::vector<std::string> &args) { if (!InitSocketLibrary()) { return false; @@ -174,6 +181,16 @@ bool Server(const std::vector<std::string> &args) { bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); + const char *keylog_file = getenv("SSLKEYLOGFILE"); + if (keylog_file) { + g_keylog_file = fopen(keylog_file, "a"); + if (g_keylog_file == nullptr) { + perror("fopen"); + return false; + } + SSL_CTX_set_keylog_callback(ctx.get(), KeyLogCallback); + } + // Server authentication is required. if (args_map.count("-key") != 0) { std::string key = args_map["-key"]; |