Update bogo to latest version for draft22 tests

This commit is contained in:
Peter Wu 2017-11-24 14:27:31 +00:00
parent 8d196e3081
commit 2eb6f2af1e
19 changed files with 3574 additions and 2064 deletions

View File

@ -6,7 +6,9 @@ Contributors to BoringSSL are required to follow the CLA rules for Chromium:
https://cla.developers.google.com/clas https://cla.developers.google.com/clas
Some files from Intel are under yet another license, which is also included Some files from Intel are under yet another license, which is also included
underneath. underneath. Files in third_party/ have their own licenses, as described
therein. The MIT license, for third_party/fiat, which, unlike other third_party
directories, is compiled into non-test libraries, is included below.
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
OpenSSL License and the original SSLeay license apply to the toolkit. See below OpenSSL License and the original SSLeay license apply to the toolkit. See below
@ -190,3 +192,27 @@ Some files from Intel carry the following license:
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The code in third_party/fiat carries the MIT license:
Copyright (c) 2015-2016 the fiat-crypto authors (see
https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -56,6 +56,7 @@ OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -63,7 +64,7 @@ OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
#include "../../crypto/internal.h" #include "../../crypto/internal.h"
#include "../internal.h" #include "../internal.h"
#include "async_bio.h" #include "async_bio.h"
#include "fuzzer.h" #include "fuzzer_tags.h"
#include "packeted_bio.h" #include "packeted_bio.h"
#include "test_config.h" #include "test_config.h"
@ -432,10 +433,7 @@ static ssl_private_key_result_t AsyncPrivateKeyComplete(
} }
static const SSL_PRIVATE_KEY_METHOD g_async_private_key_method = { static const SSL_PRIVATE_KEY_METHOD g_async_private_key_method = {
nullptr /* type */,
nullptr /* max_signature_len */,
AsyncPrivateKeySign, AsyncPrivateKeySign,
nullptr /* sign_digest */,
AsyncPrivateKeyDecrypt, AsyncPrivateKeyDecrypt,
AsyncPrivateKeyComplete, AsyncPrivateKeyComplete,
}; };
@ -452,27 +450,6 @@ static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
bssl::UniquePtr<EVP_PKEY> *out_pkey) { bssl::UniquePtr<EVP_PKEY> *out_pkey) {
const TestConfig *config = GetTestConfig(ssl); const TestConfig *config = GetTestConfig(ssl);
if (!config->digest_prefs.empty()) {
bssl::UniquePtr<char> digest_prefs(
OPENSSL_strdup(config->digest_prefs.c_str()));
std::vector<int> digest_list;
for (;;) {
char *token =
strtok(digest_list.empty() ? digest_prefs.get() : nullptr, ",");
if (token == nullptr) {
break;
}
digest_list.push_back(EVP_MD_type(EVP_get_digestbyname(token)));
}
if (!SSL_set_private_key_digest_prefs(ssl, digest_list.data(),
digest_list.size())) {
return false;
}
}
if (!config->signing_prefs.empty()) { if (!config->signing_prefs.empty()) {
std::vector<uint16_t> u16s(config->signing_prefs.begin(), std::vector<uint16_t> u16s(config->signing_prefs.begin(),
config->signing_prefs.end()); config->signing_prefs.end());
@ -854,7 +831,7 @@ static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) {
*out_pkey = GetTestState(ssl)->channel_id.release(); *out_pkey = GetTestState(ssl)->channel_id.release();
} }
static SSL_SESSION *GetSessionCallback(SSL *ssl, uint8_t *data, int len, static SSL_SESSION *GetSessionCallback(SSL *ssl, const uint8_t *data, int len,
int *copy) { int *copy) {
TestState *async_state = GetTestState(ssl); TestState *async_state = GetTestState(ssl);
if (async_state->session) { if (async_state->session) {
@ -1100,7 +1077,6 @@ static void MessageCallback(int is_write, int version, int content_type,
// Connect returns a new socket connected to localhost on |port| or -1 on // Connect returns a new socket connected to localhost on |port| or -1 on
// error. // error.
static int Connect(uint16_t port) { static int Connect(uint16_t port) {
time_t start_time = time(nullptr);
for (int af : { AF_INET6, AF_INET }) { for (int af : { AF_INET6, AF_INET }) {
int sock = socket(af, SOCK_STREAM, 0); int sock = socket(af, SOCK_STREAM, 0);
if (sock == -1) { if (sock == -1) {
@ -1147,11 +1123,6 @@ static int Connect(uint16_t port) {
} }
PrintSocketError("connect"); PrintSocketError("connect");
// TODO(davidben): Remove this logging when https://crbug.com/boringssl/199 is
// resolved.
fprintf(stderr, "start_time = %lld, end_time = %lld\n",
static_cast<long long>(start_time),
static_cast<long long>(time(nullptr)));
return -1; return -1;
} }
@ -1283,6 +1254,9 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(SSL_CTX *old_ctx,
if (!config->use_client_ca_list.empty()) { if (!config->use_client_ca_list.empty()) {
if (config->use_client_ca_list == "<NULL>") { if (config->use_client_ca_list == "<NULL>") {
SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr); SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr);
} else if (config->use_client_ca_list == "<EMPTY>") {
bssl::UniquePtr<STACK_OF(X509_NAME)> names;
SSL_CTX_set_client_CA_list(ssl_ctx.get(), names.release());
} else { } else {
bssl::UniquePtr<STACK_OF(X509_NAME)> names = bssl::UniquePtr<STACK_OF(X509_NAME)> names =
DecodeHexX509Names(config->use_client_ca_list); DecodeHexX509Names(config->use_client_ca_list);
@ -1408,6 +1382,32 @@ static bool RetryAsync(SSL *ssl, int ret) {
} }
} }
// CheckIdempotentError runs |func|, an operation on |ssl|, ensuring that
// errors are idempotent.
static int CheckIdempotentError(const char *name, SSL *ssl,
std::function<int()> func) {
int ret = func();
int ssl_err = SSL_get_error(ssl, ret);
uint32_t err = ERR_peek_error();
if (ssl_err == SSL_ERROR_SSL || ssl_err == SSL_ERROR_ZERO_RETURN) {
int ret2 = func();
int ssl_err2 = SSL_get_error(ssl, ret2);
uint32_t err2 = ERR_peek_error();
if (ret != ret2 || ssl_err != ssl_err2 || err != err2) {
fprintf(stderr, "Repeating %s did not replay the error.\n", name);
char buf[256];
ERR_error_string_n(err, buf, sizeof(buf));
fprintf(stderr, "Wanted: %d %d %s\n", ret, ssl_err, buf);
ERR_error_string_n(err2, buf, sizeof(buf));
fprintf(stderr, "Got: %d %d %s\n", ret2, ssl_err2, buf);
// runner treats exit code 90 as always failing. Otherwise, it may
// accidentally consider the result an expected protocol failure.
exit(90);
}
}
return ret;
}
// DoRead reads from |ssl|, resolving any asynchronous operations. It returns // DoRead reads from |ssl|, resolving any asynchronous operations. It returns
// the result value of the final |SSL_read| call. // the result value of the final |SSL_read| call.
static int DoRead(SSL *ssl, uint8_t *out, size_t max_out) { static int DoRead(SSL *ssl, uint8_t *out, size_t max_out) {
@ -1421,8 +1421,10 @@ static int DoRead(SSL *ssl, uint8_t *out, size_t max_out) {
// trigger a retransmit, so disconnect the write quota. // trigger a retransmit, so disconnect the write quota.
AsyncBioEnforceWriteQuota(test_state->async_bio, false); AsyncBioEnforceWriteQuota(test_state->async_bio, false);
} }
ret = config->peek_then_read ? SSL_peek(ssl, out, max_out) ret = CheckIdempotentError("SSL_peek/SSL_read", ssl, [&]() -> int {
return config->peek_then_read ? SSL_peek(ssl, out, max_out)
: SSL_read(ssl, out, max_out); : SSL_read(ssl, out, max_out);
});
if (config->async) { if (config->async) {
AsyncBioEnforceWriteQuota(test_state->async_bio, true); AsyncBioEnforceWriteQuota(test_state->async_bio, true);
} }
@ -2163,13 +2165,21 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, SSL *ssl,
int ret; int ret;
if (!config->implicit_handshake) { if (!config->implicit_handshake) {
do { do {
ret = SSL_do_handshake(ssl); ret = CheckIdempotentError("SSL_do_handshake", ssl, [&]() -> int {
return SSL_do_handshake(ssl);
});
} while (config->async && RetryAsync(ssl, ret)); } while (config->async && RetryAsync(ssl, ret));
if (ret != 1 || if (ret != 1 ||
!CheckHandshakeProperties(ssl, is_resume, config)) { !CheckHandshakeProperties(ssl, is_resume, config)) {
return false; return false;
} }
if (is_resume && !is_retry && !config->is_server &&
config->expect_no_offer_early_data && SSL_in_early_data(ssl)) {
fprintf(stderr, "Client unexpectedly offered early data.\n");
return false;
}
if (config->handshake_twice) { if (config->handshake_twice) {
do { do {
ret = SSL_do_handshake(ssl); ret = SSL_do_handshake(ssl);
@ -2365,14 +2375,13 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, SSL *ssl,
} }
if (expect_new_session) { if (expect_new_session) {
bool got_early_data_info = bool got_early_data =
GetTestState(ssl)->new_session->ticket_max_early_data != 0; GetTestState(ssl)->new_session->ticket_max_early_data != 0;
if (config->expect_early_data_info != got_early_data_info) { if (config->expect_ticket_supports_early_data != got_early_data) {
fprintf( fprintf(stderr,
stderr, "new session did%s support early data, but we expected the "
"new session did%s include ticket_early_data_info, but we expected " "opposite\n",
"the opposite\n", got_early_data ? "" : " not");
got_early_data_info ? "" : " not");
return false; return false;
} }
} }
@ -2407,6 +2416,11 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, SSL *ssl,
return false; return false;
} }
if (SSL_session_reused(ssl)) {
fprintf(stderr, "Renegotiations should never resume sessions.\n");
return false;
}
// Re-check authentication properties after a renegotiation. The reported // Re-check authentication properties after a renegotiation. The reported
// values should remain unchanged even if the server sent different SCT // values should remain unchanged even if the server sent different SCT
// lists. // lists.

View File

@ -15,104 +15,46 @@
#ifndef HEADER_SSL_TEST_FUZZER #ifndef HEADER_SSL_TEST_FUZZER
#define HEADER_SSL_TEST_FUZZER #define HEADER_SSL_TEST_FUZZER
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <openssl/bio.h>
#include <openssl/bytestring.h> #include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/x509.h>
#include "./fuzzer_tags.h"
// SSL fuzzer utilities. namespace {
//
// The TLS client and server fuzzers coordinate with bssl_shim on a common
// format to encode configuration parameters in a fuzzer file. To add a new
// configuration, define a tag, update |SetupTest| below to parse it, and
// update |WriteSettings| in bssl_shim to serialize it. Finally, record
// transcripts from a test run, and use the BORINGSSL_FUZZER_DEBUG environment
// variable to confirm the transcripts are compatible.
// kDataTag denotes that the remainder of the input should be passed to the TLS const uint8_t kP256KeyPKCS8[] = {
// stack. 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
static const uint16_t kDataTag = 0; 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
0x43, 0x09, 0xc0, 0x67, 0x75, 0x21, 0x47, 0x9d, 0xa8, 0xfa, 0x16, 0xdf,
0x15, 0x73, 0x61, 0x34, 0x68, 0x6f, 0xe3, 0x8e, 0x47, 0x91, 0x95, 0xab,
0x79, 0x4a, 0x72, 0x14, 0xcb, 0xe2, 0x49, 0x4f, 0xa1, 0x44, 0x03, 0x42,
0x00, 0x04, 0xde, 0x09, 0x08, 0x07, 0x03, 0x2e, 0x8f, 0x37, 0x9a, 0xd5,
0xad, 0xe5, 0xc6, 0x9d, 0xd4, 0x63, 0xc7, 0x4a, 0xe7, 0x20, 0xcb, 0x90,
0xa0, 0x1f, 0x18, 0x18, 0x72, 0xb5, 0x21, 0x88, 0x38, 0xc0, 0xdb, 0xba,
0xf6, 0x99, 0xd8, 0xa5, 0x3b, 0x83, 0xe9, 0xe3, 0xd5, 0x61, 0x99, 0x73,
0x42, 0xc6, 0x6c, 0xe8, 0x0a, 0x95, 0x40, 0x41, 0x3b, 0x0d, 0x10, 0xa7,
0x4a, 0x93, 0xdb, 0x5a, 0xe7, 0xec,
};
// kSessionTag is followed by a u24-length-prefixed serialized SSL_SESSION to const uint8_t kOCSPResponse[] = {0x01, 0x02, 0x03, 0x04};
// resume.
static const uint16_t kSessionTag = 1;
// kRequestClientCert denotes that the server should request client const uint8_t kSCT[] = {0x00, 0x06, 0x00, 0x04, 0x05, 0x06, 0x07, 0x08};
// certificates.
static const uint16_t kRequestClientCert = 2;
// kTLS13Variant is followed by a u8 denoting the TLS 1.3 variant to configure. const uint8_t kCertificateDER[] = {
static const uint16_t kTLS13Variant = 3;
// SetupTest parses parameters from |cbs| and returns a newly-configured |SSL|
// object or nullptr on error. On success, the caller should feed the remaining
// input in |cbs| to the SSL stack.
static inline bssl::UniquePtr<SSL> SetupTest(CBS *cbs, SSL_CTX *ctx,
bool is_server) {
// |ctx| is shared between runs, so we must clear any modifications to it made
// later on in this function.
SSL_CTX_flush_sessions(ctx, 0);
bssl::UniquePtr<SSL> ssl(SSL_new(ctx));
if (is_server) {
SSL_set_accept_state(ssl.get());
} else {
SSL_set_connect_state(ssl.get());
}
for (;;) {
uint16_t tag;
if (!CBS_get_u16(cbs, &tag)) {
return nullptr;
}
switch (tag) {
case kDataTag:
return ssl;
case kSessionTag: {
CBS data;
if (!CBS_get_u24_length_prefixed(cbs, &data)) {
return nullptr;
}
bssl::UniquePtr<SSL_SESSION> session(
SSL_SESSION_from_bytes(CBS_data(&data), CBS_len(&data), ctx));
if (!session) {
return nullptr;
}
if (is_server) {
SSL_CTX_add_session(ctx, session.get());
} else {
SSL_set_session(ssl.get(), session.get());
}
break;
}
case kRequestClientCert:
if (!is_server) {
return nullptr;
}
SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, nullptr);
break;
case kTLS13Variant: {
uint8_t variant;
if (!CBS_get_u8(cbs, &variant)) {
return nullptr;
}
SSL_set_tls13_variant(ssl.get(), static_cast<tls13_variant_t>(variant));
break;
}
default:
return nullptr;
}
}
}
// Additional shared constants.
static const uint8_t kCertificateDER[] = {
0x30, 0x82, 0x02, 0xff, 0x30, 0x82, 0x01, 0xe7, 0xa0, 0x03, 0x02, 0x01, 0x30, 0x82, 0x02, 0xff, 0x30, 0x82, 0x01, 0xe7, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x11, 0x00, 0xb1, 0x84, 0xee, 0x34, 0x99, 0x98, 0x76, 0xfb, 0x02, 0x02, 0x11, 0x00, 0xb1, 0x84, 0xee, 0x34, 0x99, 0x98, 0x76, 0xfb,
0x6f, 0xb2, 0x15, 0xc8, 0x47, 0x79, 0x05, 0x9b, 0x30, 0x0d, 0x06, 0x09, 0x6f, 0xb2, 0x15, 0xc8, 0x47, 0x79, 0x05, 0x9b, 0x30, 0x0d, 0x06, 0x09,
@ -180,7 +122,7 @@ static const uint8_t kCertificateDER[] = {
0x76, 0x8a, 0xbb, 0x76, 0x8a, 0xbb,
}; };
static const uint8_t kRSAPrivateKeyDER[] = { const uint8_t kRSAPrivateKeyDER[] = {
0x30, 0x82, 0x04, 0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0x30, 0x82, 0x04, 0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xce, 0x47, 0xcb, 0x11, 0xbb, 0xd2, 0x9d, 0x8e, 0x9e, 0xd2, 0x1e, 0x14, 0xce, 0x47, 0xcb, 0x11, 0xbb, 0xd2, 0x9d, 0x8e, 0x9e, 0xd2, 0x1e, 0x14,
0xaf, 0xc7, 0xea, 0xb6, 0xc9, 0x38, 0x2a, 0x6f, 0xb3, 0x7e, 0xfb, 0xbc, 0xaf, 0xc7, 0xea, 0xb6, 0xc9, 0x38, 0x2a, 0x6f, 0xb3, 0x7e, 0xfb, 0xbc,
@ -283,5 +225,294 @@ static const uint8_t kRSAPrivateKeyDER[] = {
0x98, 0x46, 0x89, 0x82, 0x40, 0x98, 0x46, 0x89, 0x82, 0x40,
}; };
const uint8_t kALPNProtocols[] = {
0x01, 'a', 0x02, 'a', 'a', 0x03, 'a', 'a', 'a',
};
int ALPNSelectCallback(SSL *ssl, const uint8_t **out, uint8_t *out_len,
const uint8_t *in, unsigned in_len, void *arg) {
static const uint8_t kProtocol[] = {'a', 'a'};
*out = kProtocol;
*out_len = sizeof(kProtocol);
return SSL_TLSEXT_ERR_OK;
}
int NPNSelectCallback(SSL *ssl, uint8_t **out, uint8_t *out_len,
const uint8_t *in, unsigned in_len, void *arg) {
static const uint8_t kProtocol[] = {'a', 'a'};
*out = const_cast<uint8_t *>(kProtocol);
*out_len = sizeof(kProtocol);
return SSL_TLSEXT_ERR_OK;
}
int NPNAdvertiseCallback(SSL *ssl, const uint8_t **out, unsigned *out_len,
void *arg) {
static const uint8_t kProtocols[] = {
0x01, 'a', 0x02, 'a', 'a', 0x03, 'a', 'a', 'a',
};
*out = kProtocols;
*out_len = sizeof(kProtocols);
return SSL_TLSEXT_ERR_OK;
}
class TLSFuzzer {
public:
enum Protocol {
kTLS,
kDTLS,
};
enum Role {
kClient,
kServer,
};
TLSFuzzer(Protocol protocol, Role role)
: debug_(getenv("BORINGSSL_FUZZER_DEBUG") != nullptr),
protocol_(protocol),
role_(role) {
if (!Init()) {
abort();
}
}
int TestOneInput(const uint8_t *buf, size_t len) {
RAND_reset_for_fuzzing();
CBS cbs;
CBS_init(&cbs, buf, len);
bssl::UniquePtr<SSL> ssl = SetupTest(&cbs);
if (!ssl) {
if (debug_) {
fprintf(stderr, "Error parsing parameters.\n");
}
return 0;
}
if (role_ == kClient) {
SSL_set_renegotiate_mode(ssl.get(), ssl_renegotiate_freely);
SSL_set_tlsext_host_name(ssl.get(), "hostname");
}
SSL_set0_rbio(ssl.get(), MakeBIO(CBS_data(&cbs), CBS_len(&cbs)).release());
SSL_set0_wbio(ssl.get(), BIO_new(BIO_s_mem()));
if (SSL_do_handshake(ssl.get()) == 1) {
// Keep reading application data until error or EOF.
uint8_t tmp[1024];
for (;;) {
if (SSL_read(ssl.get(), tmp, sizeof(tmp)) <= 0) {
break;
}
}
} else if (debug_) {
fprintf(stderr, "Handshake failed.\n");
}
if (debug_) {
ERR_print_errors_fp(stderr);
}
ERR_clear_error();
return 0;
}
private:
// Init initializes |ctx_| with settings common to all inputs.
bool Init() {
ctx_.reset(SSL_CTX_new(protocol_ == kDTLS ? DTLS_method() : TLS_method()));
bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
bssl::UniquePtr<RSA> privkey(RSA_private_key_from_bytes(
kRSAPrivateKeyDER, sizeof(kRSAPrivateKeyDER)));
if (!ctx_ || !privkey || !pkey ||
!EVP_PKEY_set1_RSA(pkey.get(), privkey.get()) ||
!SSL_CTX_use_PrivateKey(ctx_.get(), pkey.get())) {
return false;
}
const uint8_t *bufp = kCertificateDER;
bssl::UniquePtr<X509> cert(d2i_X509(NULL, &bufp, sizeof(kCertificateDER)));
if (!cert ||
!SSL_CTX_use_certificate(ctx_.get(), cert.get()) ||
!SSL_CTX_set_ocsp_response(ctx_.get(), kOCSPResponse,
sizeof(kOCSPResponse)) ||
!SSL_CTX_set_signed_cert_timestamp_list(ctx_.get(), kSCT,
sizeof(kSCT))) {
return false;
}
// When accepting peer certificates, allow any certificate.
SSL_CTX_set_cert_verify_callback(
ctx_.get(),
[](X509_STORE_CTX *store_ctx, void *arg) -> int { return 1; }, nullptr);
SSL_CTX_enable_signed_cert_timestamps(ctx_.get());
SSL_CTX_enable_ocsp_stapling(ctx_.get());
// Enable versions and ciphers that are off by default.
if (!SSL_CTX_set_strict_cipher_list(ctx_.get(), "ALL:NULL-SHA")) {
return false;
}
if (protocol_ == kTLS) {
if (!SSL_CTX_set_max_proto_version(ctx_.get(), TLS1_3_VERSION) ||
!SSL_CTX_set_min_proto_version(ctx_.get(), SSL3_VERSION)) {
return false;
}
}
SSL_CTX_set_early_data_enabled(ctx_.get(), 1);
SSL_CTX_set_next_proto_select_cb(ctx_.get(), NPNSelectCallback, nullptr);
SSL_CTX_set_next_protos_advertised_cb(ctx_.get(), NPNAdvertiseCallback,
nullptr);
SSL_CTX_set_alpn_select_cb(ctx_.get(), ALPNSelectCallback, nullptr);
if (SSL_CTX_set_alpn_protos(ctx_.get(), kALPNProtocols,
sizeof(kALPNProtocols)) != 0) {
return false;
}
CBS cbs;
CBS_init(&cbs, kP256KeyPKCS8, sizeof(kP256KeyPKCS8));
pkey.reset(EVP_parse_private_key(&cbs));
if (!pkey || !SSL_CTX_set1_tls_channel_id(ctx_.get(), pkey.get())) {
return false;
}
SSL_CTX_set_tls_channel_id_enabled(ctx_.get(), 1);
return true;
}
// SetupTest parses parameters from |cbs| and returns a newly-configured |SSL|
// object or nullptr on error. On success, the caller should feed the
// remaining input in |cbs| to the SSL stack.
bssl::UniquePtr<SSL> SetupTest(CBS *cbs) {
// |ctx| is shared between runs, so we must clear any modifications to it
// made later on in this function.
SSL_CTX_flush_sessions(ctx_.get(), 0);
bssl::UniquePtr<SSL> ssl(SSL_new(ctx_.get()));
if (role_ == kServer) {
SSL_set_accept_state(ssl.get());
} else {
SSL_set_connect_state(ssl.get());
}
for (;;) {
uint16_t tag;
if (!CBS_get_u16(cbs, &tag)) {
return nullptr;
}
switch (tag) {
case kDataTag:
return ssl;
case kSessionTag: {
CBS data;
if (!CBS_get_u24_length_prefixed(cbs, &data)) {
return nullptr;
}
bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(
CBS_data(&data), CBS_len(&data), ctx_.get()));
if (!session) {
return nullptr;
}
if (role_ == kServer) {
SSL_CTX_add_session(ctx_.get(), session.get());
} else {
SSL_set_session(ssl.get(), session.get());
}
break;
}
case kRequestClientCert:
if (role_ == kClient) {
return nullptr;
}
SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, nullptr);
break;
case kTLS13Variant: {
uint8_t variant;
if (!CBS_get_u8(cbs, &variant)) {
return nullptr;
}
SSL_set_tls13_variant(ssl.get(),
static_cast<tls13_variant_t>(variant));
break;
}
default:
return nullptr;
}
}
}
struct BIOData {
Protocol protocol;
CBS cbs;
};
bssl::UniquePtr<BIO> MakeBIO(const uint8_t *in, size_t len) {
BIOData *b = new BIOData;
b->protocol = protocol_;
CBS_init(&b->cbs, in, len);
bssl::UniquePtr<BIO> bio(BIO_new(&kBIOMethod));
bio->init = 1;
bio->ptr = b;
return bio;
}
static int BIORead(BIO *bio, char *out, int len) {
assert(bio->method == &kBIOMethod);
BIOData *b = reinterpret_cast<BIOData *>(bio->ptr);
if (b->protocol == kTLS) {
len = std::min(static_cast<size_t>(len), CBS_len(&b->cbs));
memcpy(out, CBS_data(&b->cbs), len);
CBS_skip(&b->cbs, len);
return len;
}
// Preserve packet boundaries for DTLS.
CBS packet;
if (!CBS_get_u24_length_prefixed(&b->cbs, &packet)) {
return -1;
}
len = std::min(static_cast<size_t>(len), CBS_len(&packet));
memcpy(out, CBS_data(&packet), len);
return len;
}
static int BIODestroy(BIO *bio) {
assert(bio->method == &kBIOMethod);
BIOData *b = reinterpret_cast<BIOData *>(bio->ptr);
delete b;
return 1;
}
static const BIO_METHOD kBIOMethod;
bool debug_;
Protocol protocol_;
Role role_;
bssl::UniquePtr<SSL_CTX> ctx_;
};
const BIO_METHOD TLSFuzzer::kBIOMethod = {
0, // type
nullptr, // name
nullptr, // bwrite
TLSFuzzer::BIORead,
nullptr, // bputs
nullptr, // bgets
nullptr, // ctrl
nullptr, // create
TLSFuzzer::BIODestroy,
nullptr, // callback_ctrl
};
} // namespace
#endif // HEADER_SSL_TEST_FUZZER #endif // HEADER_SSL_TEST_FUZZER

View File

@ -0,0 +1,45 @@
/* Copyright (c) 2017, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef HEADER_SSL_TEST_FUZZER_TAGS
#define HEADER_SSL_TEST_FUZZER_TAGS
#include <stdint.h>
// SSL fuzzer tag constants.
//
// The TLS client and server fuzzers coordinate with bssl_shim on a common
// format to encode configuration parameters in a fuzzer file. To add a new
// configuration, define a tag, update |SetupTest| in fuzzer.h to parse it, and
// update |WriteSettings| in bssl_shim to serialize it. Finally, record
// transcripts from a test run, and use the BORINGSSL_FUZZER_DEBUG environment
// variable to confirm the transcripts are compatible.
// kDataTag denotes that the remainder of the input should be passed to the TLS
// stack.
static const uint16_t kDataTag = 0;
// kSessionTag is followed by a u24-length-prefixed serialized SSL_SESSION to
// resume.
static const uint16_t kSessionTag = 1;
// kRequestClientCert denotes that the server should request client
// certificates.
static const uint16_t kRequestClientCert = 2;
// kTLS13Variant is followed by a u8 denoting the TLS 1.3 variant to configure.
static const uint16_t kTLS13Variant = 3;
#endif // HEADER_SSL_TEST_FUZZER_TAGS

View File

@ -11,7 +11,6 @@ import (
"crypto/des" "crypto/des"
"crypto/hmac" "crypto/hmac"
"crypto/md5" "crypto/md5"
"crypto/rc4"
"crypto/sha1" "crypto/sha1"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
@ -48,8 +47,6 @@ const (
// client indicates that it supports ECC with a curve and point format // client indicates that it supports ECC with a curve and point format
// that we're happy with. // that we're happy with.
suiteECDHE = 1 << iota suiteECDHE = 1 << iota
// suiteDHE indicates that the cipher suite involves Diffie-Hellman.
suiteDHE
// suiteECDSA indicates that the cipher suite involves an ECDSA // suiteECDSA indicates that the cipher suite involves an ECDSA
// signature and therefore may only be selected when the server's // signature and therefore may only be selected when the server's
// certificate is ECDSA. If this is not set then the cipher suite is // certificate is ECDSA. If this is not set then the cipher suite is
@ -64,9 +61,6 @@ const (
// suiteSHA384 indicates that the cipher suite uses SHA384 as the // suiteSHA384 indicates that the cipher suite uses SHA384 as the
// handshake hash. // handshake hash.
suiteSHA384 suiteSHA384
// suiteNoDTLS indicates that the cipher suite cannot be used
// in DTLS.
suiteNoDTLS
// suitePSK indicates that the cipher suite authenticates with // suitePSK indicates that the cipher suite authenticates with
// a pre-shared key rather than a server private key. // a pre-shared key rather than a server private key.
suitePSK suitePSK
@ -101,8 +95,6 @@ func (cs cipherSuite) hash() crypto.Hash {
} }
var cipherSuites = []*cipherSuite{ var cipherSuites = []*cipherSuite{
// Ciphersuite order is chosen so that ECDHE comes before plain RSA
// and RC4 comes before AES (because of the Lucky13 attack).
{TLS_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, nil, suiteTLS13, nil, nil, aeadCHACHA20POLY1305}, {TLS_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, nil, suiteTLS13, nil, nil, aeadCHACHA20POLY1305},
{TLS_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, nil, suiteTLS13, nil, nil, aeadAESGCM}, {TLS_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, nil, suiteTLS13, nil, nil, aeadAESGCM},
{TLS_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, nil, suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM}, {TLS_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, nil, suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM},
@ -112,8 +104,6 @@ var cipherSuites = []*cipherSuite{
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM}, {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, noIV, ecdheRSAKA, suiteECDHE | suiteNoDTLS, cipherRC4, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, noIV, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteNoDTLS, cipherRC4, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil}, {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, cipherAES, macSHA256, nil}, {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, cipherAES, macSHA256, nil},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
@ -124,8 +114,6 @@ var cipherSuites = []*cipherSuite{
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, rsaKA, suiteTLS12, nil, nil, aeadAESGCM}, {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_RC4_128_SHA, 16, 20, noIV, rsaKA, suiteNoDTLS, cipherRC4, macSHA1, nil},
{TLS_RSA_WITH_RC4_128_MD5, 16, 16, noIV, rsaKA, suiteNoDTLS, cipherRC4, macMD5, nil},
{TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, rsaKA, suiteTLS12, cipherAES, macSHA256, nil}, {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
{TLS_RSA_WITH_AES_256_CBC_SHA256, 32, 32, ivLenAES, rsaKA, suiteTLS12, cipherAES, macSHA256, nil}, {TLS_RSA_WITH_AES_256_CBC_SHA256, 32, 32, ivLenAES, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, rsaKA, 0, cipherAES, macSHA1, nil}, {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, rsaKA, 0, cipherAES, macSHA1, nil},
@ -135,10 +123,9 @@ var cipherSuites = []*cipherSuite{
{TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12, nil, nil, aeadCHACHA20POLY1305}, {TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
{TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil}, {TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
{TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil}, {TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
{TLS_PSK_WITH_RC4_128_SHA, 16, 20, noIV, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil},
{TLS_PSK_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, pskKA, suitePSK, cipherAES, macSHA1, nil}, {TLS_PSK_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, pskKA, suitePSK, cipherAES, macSHA1, nil},
{TLS_PSK_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, pskKA, suitePSK, cipherAES, macSHA1, nil}, {TLS_PSK_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, pskKA, suitePSK, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_NULL_SHA, 0, 20, noIV, rsaKA, suiteNoDTLS, cipherNull, macSHA1, nil}, {TLS_RSA_WITH_NULL_SHA, 0, 20, noIV, rsaKA, 0, cipherNull, macSHA1, nil},
} }
func noIV(vers uint16) int { func noIV(vers uint16) int {
@ -170,11 +157,6 @@ func cipherNull(key, iv []byte, isRead bool) interface{} {
return nullCipher{} return nullCipher{}
} }
func cipherRC4(key, iv []byte, isRead bool) interface{} {
cipher, _ := rc4.NewCipher(key)
return cipher
}
func cipher3DES(key, iv []byte, isRead bool) interface{} { func cipher3DES(key, iv []byte, isRead bool) interface{} {
block, _ := des.NewTripleDESCipher(key) block, _ := des.NewTripleDESCipher(key)
if isRead { if isRead {
@ -450,22 +432,17 @@ func cipherSuiteFromID(id uint16) *cipherSuite {
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
const ( const (
TLS_RSA_WITH_NULL_SHA uint16 = 0x0002 TLS_RSA_WITH_NULL_SHA uint16 = 0x0002
TLS_RSA_WITH_RC4_128_MD5 uint16 = 0x0004
TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035 TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003d TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003d
TLS_PSK_WITH_RC4_128_SHA uint16 = 0x008a
TLS_PSK_WITH_AES_128_CBC_SHA uint16 = 0x008c TLS_PSK_WITH_AES_128_CBC_SHA uint16 = 0x008c
TLS_PSK_WITH_AES_256_CBC_SHA uint16 = 0x008d TLS_PSK_WITH_AES_256_CBC_SHA uint16 = 0x008d
TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a
TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012 TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014

View File

@ -34,21 +34,29 @@ const (
// A draft version of TLS 1.3 that is sent over the wire for the current draft. // A draft version of TLS 1.3 that is sent over the wire for the current draft.
const ( const (
tls13DraftVersion = 0x7f12 tls13DraftVersion = 0x7f12
tls13Draft21Version = 0x7f15
tls13ExperimentVersion = 0x7e01 tls13ExperimentVersion = 0x7e01
tls13RecordTypeExperimentVersion = 0x7a12 tls13Experiment2Version = 0x7e02
tls13Experiment3Version = 0x7e03
tls13Draft22Version = 0x7e04
) )
const ( const (
TLS13Default = 0 TLS13Default = 0
TLS13Experiment = 1 TLS13Experiment = 1
TLS13RecordTypeExperiment = 2 TLS13Experiment2 = 2
TLS13NoSessionIDExperiment = 3 TLS13Experiment3 = 3
TLS13Draft21 = 4
TLS13Draft22 = 5
) )
var allTLSWireVersions = []uint16{ var allTLSWireVersions = []uint16{
tls13DraftVersion, tls13DraftVersion,
tls13Draft22Version,
tls13Draft21Version,
tls13Experiment3Version,
tls13Experiment2Version,
tls13ExperimentVersion, tls13ExperimentVersion,
tls13RecordTypeExperimentVersion,
VersionTLS12, VersionTLS12,
VersionTLS11, VersionTLS11,
VersionTLS10, VersionTLS10,
@ -89,6 +97,7 @@ const (
typeServerHello uint8 = 2 typeServerHello uint8 = 2
typeHelloVerifyRequest uint8 = 3 typeHelloVerifyRequest uint8 = 3
typeNewSessionTicket uint8 = 4 typeNewSessionTicket uint8 = 4
typeEndOfEarlyData uint8 = 5 // draft-ietf-tls-tls13-21
typeHelloRetryRequest uint8 = 6 // draft-ietf-tls-tls13-16 typeHelloRetryRequest uint8 = 6 // draft-ietf-tls-tls13-16
typeEncryptedExtensions uint8 = 8 // draft-ietf-tls-tls13-16 typeEncryptedExtensions uint8 = 8 // draft-ietf-tls-tls13-16
typeCertificate uint8 = 11 typeCertificate uint8 = 11
@ -102,6 +111,7 @@ const (
typeKeyUpdate uint8 = 24 // draft-ietf-tls-tls13-16 typeKeyUpdate uint8 = 24 // draft-ietf-tls-tls13-16
typeNextProtocol uint8 = 67 // Not IANA assigned typeNextProtocol uint8 = 67 // Not IANA assigned
typeChannelID uint8 = 203 // Not IANA assigned typeChannelID uint8 = 203 // Not IANA assigned
typeMessageHash uint8 = 254 // draft-ietf-tls-tls13-21
) )
// TLS compression types. // TLS compression types.
@ -119,6 +129,7 @@ const (
extensionUseSRTP uint16 = 14 extensionUseSRTP uint16 = 14
extensionALPN uint16 = 16 extensionALPN uint16 = 16
extensionSignedCertificateTimestamp uint16 = 18 extensionSignedCertificateTimestamp uint16 = 18
extensionPadding uint16 = 21
extensionExtendedMasterSecret uint16 = 23 extensionExtendedMasterSecret uint16 = 23
extensionSessionTicket uint16 = 35 extensionSessionTicket uint16 = 35
extensionKeyShare uint16 = 40 // draft-ietf-tls-tls13-16 extensionKeyShare uint16 = 40 // draft-ietf-tls-tls13-16
@ -128,6 +139,7 @@ const (
extensionCookie uint16 = 44 // draft-ietf-tls-tls13-16 extensionCookie uint16 = 44 // draft-ietf-tls-tls13-16
extensionPSKKeyExchangeModes uint16 = 45 // draft-ietf-tls-tls13-18 extensionPSKKeyExchangeModes uint16 = 45 // draft-ietf-tls-tls13-18
extensionTicketEarlyDataInfo uint16 = 46 // draft-ietf-tls-tls13-18 extensionTicketEarlyDataInfo uint16 = 46 // draft-ietf-tls-tls13-18
extensionCertificateAuthorities uint16 = 47 // draft-ietf-tls-tls13-21
extensionCustom uint16 = 1234 // not IANA assigned extensionCustom uint16 = 1234 // not IANA assigned
extensionNextProtoNeg uint16 = 13172 // not IANA assigned extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01 extensionRenegotiationInfo uint16 = 0xff01
@ -139,6 +151,12 @@ const (
scsvRenegotiation uint16 = 0x00ff scsvRenegotiation uint16 = 0x00ff
) )
var tls13HelloRetryRequest = []uint8{
0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c,
0x02, 0x1e, 0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb,
0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
}
// CurveID is the type of a TLS identifier for an elliptic curve. See // CurveID is the type of a TLS identifier for an elliptic curve. See
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
type CurveID uint16 type CurveID uint16
@ -275,6 +293,7 @@ type ClientSessionState struct {
sessionId []uint8 // Session ID supplied by the server. nil if the session has a ticket. 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 sessionTicket []uint8 // Encrypted ticket used for session resumption with server
vers uint16 // SSL/TLS version negotiated for the session 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 cipherSuite uint16 // Ciphersuite negotiated for the session
masterSecret []byte // MasterSecret generated by client on a full handshake masterSecret []byte // MasterSecret generated by client on a full handshake
handshakeHash []byte // Handshake hash for Channel ID purposes. handshakeHash []byte // Handshake hash for Channel ID purposes.
@ -452,8 +471,7 @@ type Config struct {
// MaxEarlyDataSize controls the maximum number of bytes that the // MaxEarlyDataSize controls the maximum number of bytes that the
// server will accept in early data and advertise in a // server will accept in early data and advertise in a
// NewSessionTicketMsg. If 0, no early data will be accepted and // NewSessionTicketMsg. If 0, no early data will be accepted and
// the TicketEarlyDataInfo extension in the NewSessionTicketMsg // the early_data extension in the NewSessionTicketMsg will be omitted.
// will be omitted.
MaxEarlyDataSize uint32 MaxEarlyDataSize uint32
// SRTPProtectionProfiles, if not nil, is the list of SRTP // SRTPProtectionProfiles, if not nil, is the list of SRTP
@ -493,7 +511,11 @@ const (
RSABadValueCorrupt RSABadValueCorrupt
RSABadValueTooLong RSABadValueTooLong
RSABadValueTooShort RSABadValueTooShort
RSABadValueWrongVersion RSABadValueWrongVersion1
RSABadValueWrongVersion2
RSABadValueWrongBlockType
RSABadValueWrongLeadingByte
RSABadValueNoZero
NumRSABadValues NumRSABadValues
) )
@ -556,6 +578,10 @@ type ProtocolBugs struct {
// NewSessionTicket message despite promising to in ServerHello. // NewSessionTicket message despite promising to in ServerHello.
SkipNewSessionTicket bool SkipNewSessionTicket bool
// UseFirstSessionTicket causes the client to cache only the first session
// ticket received.
UseFirstSessionTicket bool
// SkipClientCertificate causes the client to skip the Certificate // SkipClientCertificate causes the client to skip the Certificate
// message. // message.
SkipClientCertificate bool SkipClientCertificate bool
@ -569,18 +595,22 @@ type ProtocolBugs struct {
// message. // message.
SkipFinished bool SkipFinished bool
// SkipEndOfEarlyData causes the implementation to skip the // SkipEndOfEarlyData causes the implementation to skip
// end_of_early_data alert. // end_of_early_data.
SkipEndOfEarlyData bool SkipEndOfEarlyData bool
// NonEmptyEndOfEarlyData causes the implementation to end an extra byte in the
// EndOfEarlyData.
NonEmptyEndOfEarlyData bool
// SkipCertificateVerify, if true causes peer to skip sending a // SkipCertificateVerify, if true causes peer to skip sending a
// CertificateVerify message after the Certificate message. // CertificateVerify message after the Certificate message.
SkipCertificateVerify bool SkipCertificateVerify bool
// EarlyChangeCipherSpec causes the client to send an early // EarlyChangeCipherSpec causes the client to send an early
// ChangeCipherSpec message before the ClientKeyExchange. A value of // ChangeCipherSpec message before the ClientKeyExchange. A value of
// zero disables this behavior. One and two configure variants for 0.9.8 // zero disables this behavior. One and two configure variants for
// and 1.0.1 modes, respectively. // 1.0.1 and 0.9.8 modes, respectively.
EarlyChangeCipherSpec int EarlyChangeCipherSpec int
// StrayChangeCipherSpec causes every pre-ChangeCipherSpec handshake // StrayChangeCipherSpec causes every pre-ChangeCipherSpec handshake
@ -598,6 +628,14 @@ type ProtocolBugs struct {
// messages. // messages.
FragmentAcrossChangeCipherSpec bool FragmentAcrossChangeCipherSpec bool
// SendExtraChangeCipherSpec causes the implementation to send extra
// ChangeCipherSpec messages.
SendExtraChangeCipherSpec int
// SendPostHandshakeChangeCipherSpec causes the implementation to send
// a ChangeCipherSpec record before every application data record.
SendPostHandshakeChangeCipherSpec bool
// SendUnencryptedFinished, if true, causes the Finished message to be // SendUnencryptedFinished, if true, causes the Finished message to be
// send unencrypted before ChangeCipherSpec rather than after it. // send unencrypted before ChangeCipherSpec rather than after it.
SendUnencryptedFinished bool SendUnencryptedFinished bool
@ -735,10 +773,6 @@ type ProtocolBugs struct {
// connection if there is not a SessionID in the ClientHello. // connection if there is not a SessionID in the ClientHello.
ExpectClientHelloSessionID bool ExpectClientHelloSessionID bool
// ExpectEmptyClientHelloSessionID, if true, causes the server to fail the
// connection if there is a SessionID in the ClientHello.
ExpectEmptyClientHelloSessionID bool
// ExpectNoTLS12Session, if true, causes the server to fail the // ExpectNoTLS12Session, if true, causes the server to fail the
// connection if either a session ID or TLS 1.2 ticket is offered. // connection if either a session ID or TLS 1.2 ticket is offered.
ExpectNoTLS12Session bool ExpectNoTLS12Session bool
@ -747,6 +781,10 @@ type ProtocolBugs struct {
// if a TLS 1.3 PSK is offered. // if a TLS 1.3 PSK is offered.
ExpectNoTLS13PSK bool ExpectNoTLS13PSK bool
// ExpectNoTLS13PSKAfterHRR, if true, causes the server to fail the connection
// if a TLS 1.3 PSK is offered after HRR.
ExpectNoTLS13PSKAfterHRR bool
// RequireExtendedMasterSecret, if true, requires that the peer support // RequireExtendedMasterSecret, if true, requires that the peer support
// the extended master secret option. // the extended master secret option.
RequireExtendedMasterSecret bool RequireExtendedMasterSecret bool
@ -948,10 +986,22 @@ type ProtocolBugs struct {
// record size. // record size.
PackHandshakeFragments int PackHandshakeFragments int
// PackHandshakeRecords, if true, causes handshake records in DTLS to be // PackHandshakeRecords, if non-zero, causes handshake and
// packed into individual packets, up to the specified packet size. // ChangeCipherSpec records in DTLS to be packed into individual
// packets, up to the specified packet size.
PackHandshakeRecords int PackHandshakeRecords int
// PackAppDataWithHandshake, if true, extends PackHandshakeRecords to
// additionally include the first application data record sent after the
// final Finished message in a handshake. (If the final Finished message
// is sent by the peer, this option has no effect.) This requires that
// the runner rather than shim speak first in a given test.
PackAppDataWithHandshake bool
// SplitAndPackAppData, if true, causes application data in DTLS to be
// split into two records each and packed into one packet.
SplitAndPackAppData bool
// PackHandshakeFlight, if true, causes each handshake flight in TLS to // PackHandshakeFlight, if true, causes each handshake flight in TLS to
// be packed into records, up to the largest size record available. // be packed into records, up to the largest size record available.
PackHandshakeFlight bool PackHandshakeFlight bool
@ -1034,13 +1084,13 @@ type ProtocolBugs struct {
// receipt of a NewSessionTicket message. // receipt of a NewSessionTicket message.
ExpectNoNewSessionTicket bool ExpectNoNewSessionTicket bool
// DuplicateTicketEarlyDataInfo causes an extra empty extension of // DuplicateTicketEarlyData causes an extra empty extension of early_data to
// ticket_early_data_info to be sent in NewSessionTicket. // be sent in NewSessionTicket.
DuplicateTicketEarlyDataInfo bool DuplicateTicketEarlyData bool
// ExpectTicketEarlyDataInfo, if true, means that the client will fail upon // ExpectTicketEarlyData, if true, means that the client will fail upon
// absence of the ticket_early_data_info extension. // absence of the early_data extension.
ExpectTicketEarlyDataInfo bool ExpectTicketEarlyData bool
// ExpectTicketAge, if non-zero, is the expected age of the ticket that the // ExpectTicketAge, if non-zero, is the expected age of the ticket that the
// server receives from the client. // server receives from the client.
@ -1288,6 +1338,10 @@ type ProtocolBugs struct {
// the specified curve in a HelloRetryRequest. // the specified curve in a HelloRetryRequest.
SendHelloRetryRequestCurve CurveID SendHelloRetryRequestCurve CurveID
// SendHelloRetryRequestCipherSuite, if non-zero, causes the server to send
// the specified cipher suite in a HelloRetryRequest.
SendHelloRetryRequestCipherSuite uint16
// SendHelloRetryRequestCookie, if not nil, contains a cookie to be // SendHelloRetryRequestCookie, if not nil, contains a cookie to be
// sent by the server in HelloRetryRequest. // sent by the server in HelloRetryRequest.
SendHelloRetryRequestCookie []byte SendHelloRetryRequestCookie []byte
@ -1325,6 +1379,14 @@ type ProtocolBugs struct {
// a TLS 1.3 CertificateRequest. // a TLS 1.3 CertificateRequest.
SendRequestContext []byte SendRequestContext []byte
// OmitCertificateRequestAlgorithms, if true, omits the signature_algorithm
// extension in a TLS 1.3 CertificateRequest.
OmitCertificateRequestAlgorithms bool
// SendCustomCertificateRequest, if non-zero, send an additional custom
// extension in a TLS 1.3 CertificateRequest.
SendCustomCertificateRequest uint16
// SendSNIWarningAlert, if true, causes the server to send an // SendSNIWarningAlert, if true, causes the server to send an
// unrecognized_name alert before the ServerHello. // unrecognized_name alert before the ServerHello.
SendSNIWarningAlert bool SendSNIWarningAlert bool
@ -1386,6 +1448,12 @@ type ProtocolBugs struct {
// empty slice, no extension will be sent. // empty slice, no extension will be sent.
SendSupportedPointFormats []byte SendSupportedPointFormats []byte
// SendServerSupportedCurves, if true, causes the server to send its
// supported curves list in the ServerHello (TLS 1.2) or
// EncryptedExtensions (TLS 1.3) message. This is invalid in TLS 1.2 and
// valid in TLS 1.3.
SendServerSupportedCurves bool
// MaxReceivePlaintext, if non-zero, is the maximum plaintext record // MaxReceivePlaintext, if non-zero, is the maximum plaintext record
// length accepted from the peer. // length accepted from the peer.
MaxReceivePlaintext int MaxReceivePlaintext int
@ -1406,6 +1474,10 @@ type ProtocolBugs struct {
// renegotiation handshakes. // renegotiation handshakes.
RenegotiationCertificate *Certificate RenegotiationCertificate *Certificate
// ExpectNoCertificateAuthoritiesExtension, if true, causes the client to
// reject CertificateRequest with the CertificateAuthorities extension.
ExpectNoCertificateAuthoritiesExtension bool
// UseLegacySigningAlgorithm, if non-zero, is the signature algorithm // UseLegacySigningAlgorithm, if non-zero, is the signature algorithm
// to use when signing in TLS 1.1 and earlier where algorithms are not // to use when signing in TLS 1.1 and earlier where algorithms are not
// negotiated. // negotiated.
@ -1434,6 +1506,10 @@ type ProtocolBugs struct {
// ExpectRecordSplitting, if true, causes application records to only be // ExpectRecordSplitting, if true, causes application records to only be
// accepted if they follow a 1/n-1 record split. // accepted if they follow a 1/n-1 record split.
ExpectRecordSplitting bool ExpectRecordSplitting bool
// PadClientHello, if non-zero, pads the ClientHello to a multiple of
// that many bytes.
PadClientHello int
} }
func (c *Config) serverInit() { func (c *Config) serverInit() {
@ -1534,12 +1610,59 @@ func (c *Config) defaultCurves() map[CurveID]bool {
return defaultCurves 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, tls13Draft22Version, tls13Draft21Version, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version:
return VersionTLS13, true
}
}
return 0, false
}
func isDraft21(vers uint16) bool {
return vers == tls13Draft21Version || vers == tls13Draft22Version
}
func isDraft22(vers uint16) bool {
return vers == tls13Draft22Version
}
func isResumptionExperiment(vers uint16) bool {
return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Experiment3Version || vers == tls13Draft22Version
}
func isResumptionClientCCSExperiment(vers uint16) bool {
return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Draft22Version
}
func isResumptionRecordVersionExperiment(vers uint16) bool {
return vers == tls13Experiment2Version || vers == tls13Experiment3Version || vers == tls13Draft22Version
}
func isResumptionRecordVersionVariant(variant int) bool {
return variant == TLS13Experiment2 || variant == TLS13Experiment3 || variant == TLS13Draft22
}
// isSupportedVersion checks if the specified wire version is acceptable. If so, // isSupportedVersion checks if the specified wire version is acceptable. If so,
// it returns true and the corresponding protocol version. Otherwise, it returns // it returns true and the corresponding protocol version. Otherwise, it returns
// false. // false.
func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) { func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) {
if (c.TLS13Variant != TLS13Experiment && c.TLS13Variant != TLS13NoSessionIDExperiment && wireVers == tls13ExperimentVersion) || if (c.TLS13Variant != TLS13Experiment && wireVers == tls13ExperimentVersion) ||
(c.TLS13Variant != TLS13RecordTypeExperiment && wireVers == tls13RecordTypeExperimentVersion) || (c.TLS13Variant != TLS13Experiment2 && wireVers == tls13Experiment2Version) ||
(c.TLS13Variant != TLS13Experiment3 && wireVers == tls13Experiment3Version) ||
(c.TLS13Variant != TLS13Draft22 && wireVers == tls13Draft22Version) ||
(c.TLS13Variant != TLS13Draft21 && wireVers == tls13Draft21Version) ||
(c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) { (c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) {
return 0, false return 0, false
} }

View File

@ -96,10 +96,13 @@ type Conn struct {
handMsg []byte // pending assembled handshake message handMsg []byte // pending assembled handshake message
handMsgLen int // handshake message length, not including the header handMsgLen int // handshake message length, not including the header
pendingFragments [][]byte // pending outgoing handshake fragments. pendingFragments [][]byte // pending outgoing handshake fragments.
pendingPacket []byte // pending outgoing packet.
keyUpdateRequested bool keyUpdateRequested bool
seenOneByteRecord bool seenOneByteRecord bool
expectTLS13ChangeCipherSpec bool
tmp [16]byte tmp [16]byte
} }
@ -153,6 +156,7 @@ type halfConn struct {
err error // first permanent error err error // first permanent error
version uint16 // protocol version version uint16 // protocol version
wireVersion uint16 // wire version
isDTLS bool isDTLS bool
cipher interface{} // cipher algorithm cipher interface{} // cipher algorithm
mac macFunction mac macFunction
@ -188,7 +192,12 @@ func (hc *halfConn) error() error {
// prepareCipherSpec sets the encryption and MAC states // prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use. // that a subsequent changeCipherSpec will use.
func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) { 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.nextCipher = cipher
hc.nextMac = mac hc.nextMac = mac
} }
@ -215,7 +224,12 @@ func (hc *halfConn) changeCipherSpec(config *Config) error {
// useTrafficSecret sets the current cipher state for TLS 1.3. // useTrafficSecret sets the current cipher state for TLS 1.3.
func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) { 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) hc.cipher = deriveTrafficAEAD(version, suite, secret, side)
if hc.config.Bugs.NullAllCiphers { if hc.config.Bugs.NullAllCiphers {
hc.cipher = nullCipher{} hc.cipher = nullCipher{}
@ -232,14 +246,6 @@ func (hc *halfConn) resetCipher() {
hc.incEpoch() hc.incEpoch()
} }
func (hc *halfConn) doKeyUpdate(c *Conn, isOutgoing bool) {
side := serverWrite
if c.isClient == isOutgoing {
side = clientWrite
}
hc.useTrafficSecret(hc.version, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), side)
}
// incSeq increments the sequence number. // incSeq increments the sequence number.
func (hc *halfConn) incSeq(isOutgoing bool) { func (hc *halfConn) incSeq(isOutgoing bool) {
limit := 0 limit := 0
@ -725,6 +731,26 @@ func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
return b, bb return b, bb
} }
func (c *Conn) useInTrafficSecret(version uint16, suite *cipherSuite, secret []byte) error {
if c.hand.Len() != 0 {
return c.in.setErrorLocked(errors.New("tls: buffered handshake messages on cipher change"))
}
side := serverWrite
if !c.isClient {
side = clientWrite
}
c.in.useTrafficSecret(version, suite, secret, side)
return nil
}
func (c *Conn) useOutTrafficSecret(version uint16, suite *cipherSuite, secret []byte) {
side := serverWrite
if c.isClient {
side = clientWrite
}
c.out.useTrafficSecret(version, suite, secret, side)
}
func (c *Conn) doReadRecord(want recordType) (recordType, *block, error) { func (c *Conn) doReadRecord(want recordType) (recordType, *block, error) {
RestartReadRecord: RestartReadRecord:
if c.isDTLS { if c.isDTLS {
@ -763,11 +789,6 @@ RestartReadRecord:
return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received")) return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
} }
// Accept server_plaintext_handshake records when the content type TLS 1.3 variant is enabled.
if c.isClient && c.in.cipher == nil && c.config.TLS13Variant == TLS13RecordTypeExperiment && want == recordTypeHandshake && typ == recordTypePlaintextHandshake {
typ = recordTypeHandshake
}
vers := uint16(b.data[1])<<8 | uint16(b.data[2]) vers := uint16(b.data[1])<<8 | uint16(b.data[2])
n := int(b.data[3])<<8 | int(b.data[4]) n := int(b.data[3])<<8 | int(b.data[4])
@ -781,6 +802,9 @@ RestartReadRecord:
if c.vers >= VersionTLS13 { if c.vers >= VersionTLS13 {
expect = VersionTLS10 expect = VersionTLS10
} }
if isResumptionRecordVersionExperiment(c.wireVersion) {
expect = VersionTLS12
}
} else { } else {
expect = c.config.Bugs.ExpectInitialRecordVersion expect = c.config.Bugs.ExpectInitialRecordVersion
} }
@ -855,6 +879,47 @@ RestartReadRecord:
return typ, b, nil return typ, b, nil
} }
func (c *Conn) readTLS13ChangeCipherSpec() error {
if !c.expectTLS13ChangeCipherSpec {
panic("c.expectTLS13ChangeCipherSpec not set")
}
// Read the ChangeCipherSpec.
if c.rawInput == nil {
c.rawInput = c.in.newBlock()
}
b := c.rawInput
if err := b.readFromUntil(c.conn, 1); err != nil {
return c.in.setErrorLocked(fmt.Errorf("tls: error reading TLS 1.3 ChangeCipherSpec: %s", err))
}
if recordType(b.data[0]) == recordTypeAlert {
// If the client is sending an alert, allow the ChangeCipherSpec
// to be skipped. It may be rejecting a sufficiently malformed
// ServerHello that it can't parse out the version.
c.expectTLS13ChangeCipherSpec = false
return nil
}
if err := b.readFromUntil(c.conn, 6); err != nil {
return c.in.setErrorLocked(fmt.Errorf("tls: error reading TLS 1.3 ChangeCipherSpec: %s", err))
}
// Check they match that we expect.
expected := [6]byte{byte(recordTypeChangeCipherSpec), 3, 1, 0, 1, 1}
if isResumptionRecordVersionExperiment(c.wireVersion) {
expected[2] = 3
}
if !bytes.Equal(b.data[:6], expected[:]) {
return c.in.setErrorLocked(fmt.Errorf("tls: error invalid TLS 1.3 ChangeCipherSpec: %x", b.data[:6]))
}
// Discard the data.
b, c.rawInput = c.in.splitBlock(b, 6)
c.in.freeBlock(b)
c.expectTLS13ChangeCipherSpec = false
return nil
}
// readRecord reads the next TLS record from the connection // readRecord reads the next TLS record from the connection
// and updates the record layer state. // and updates the record layer state.
// c.in.Mutex <= L; c.input == nil. // c.in.Mutex <= L; c.input == nil.
@ -875,6 +940,12 @@ func (c *Conn) readRecord(want recordType) error {
break break
} }
if c.expectTLS13ChangeCipherSpec {
if err := c.readTLS13ChangeCipherSpec(); err != nil {
return err
}
}
Again: Again:
typ, b, err := c.doReadRecord(want) typ, b, err := c.doReadRecord(want)
if err != nil { if err != nil {
@ -929,11 +1000,12 @@ Again:
c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
break break
} }
if c.wireVersion != tls13ExperimentVersion { if c.hand.Len() != 0 {
err := c.in.changeCipherSpec(c.config) c.in.setErrorLocked(errors.New("tls: buffered handshake messages on cipher change"))
if err != nil { break
c.in.setErrorLocked(c.sendAlert(err.(alert)))
} }
if err := c.in.changeCipherSpec(c.config); err != nil {
c.in.setErrorLocked(c.sendAlert(err.(alert)))
} }
case recordTypeApplicationData: case recordTypeApplicationData:
@ -1063,6 +1135,12 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
return 0, err return 0, err
} }
if typ == recordTypeApplicationData && c.config.Bugs.SendPostHandshakeChangeCipherSpec {
if _, err := c.doWriteRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
return 0, err
}
}
return c.doWriteRecord(typ, data) return c.doWriteRecord(typ, data)
} }
@ -1125,6 +1203,10 @@ func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) {
// layer to {3, 1}. // layer to {3, 1}.
vers = VersionTLS10 vers = VersionTLS10
} }
if isResumptionRecordVersionExperiment(c.wireVersion) || isResumptionRecordVersionExperiment(c.out.wireVersion) {
vers = VersionTLS12
}
if c.config.Bugs.SendRecordVersion != 0 { if c.config.Bugs.SendRecordVersion != 0 {
vers = c.config.Bugs.SendRecordVersion vers = c.config.Bugs.SendRecordVersion
} }
@ -1156,7 +1238,7 @@ func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) {
} }
c.out.freeBlock(b) c.out.freeBlock(b)
if typ == recordTypeChangeCipherSpec && c.wireVersion != tls13ExperimentVersion { if typ == recordTypeChangeCipherSpec && !isResumptionExperiment(c.wireVersion) {
err = c.out.changeCipherSpec(c.config) err = c.out.changeCipherSpec(c.config)
if err != nil { if err != nil {
return n, c.sendAlertLocked(alertLevelError, err.(alert)) return n, c.sendAlertLocked(alertLevelError, err.(alert))
@ -1244,7 +1326,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(helloRetryRequestMsg) m = new(helloRetryRequestMsg)
case typeNewSessionTicket: case typeNewSessionTicket:
m = &newSessionTicketMsg{ m = &newSessionTicketMsg{
version: c.vers, vers: c.wireVersion,
isDTLS: c.isDTLS,
} }
case typeEncryptedExtensions: case typeEncryptedExtensions:
m = new(encryptedExtensionsMsg) m = new(encryptedExtensionsMsg)
@ -1254,6 +1337,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
} }
case typeCertificateRequest: case typeCertificateRequest:
m = &certificateRequestMsg{ m = &certificateRequestMsg{
vers: c.wireVersion,
hasSignatureAlgorithm: c.vers >= VersionTLS12, hasSignatureAlgorithm: c.vers >= VersionTLS12,
hasRequestContext: c.vers >= VersionTLS13, hasRequestContext: c.vers >= VersionTLS13,
} }
@ -1279,6 +1363,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(channelIDMsg) m = new(channelIDMsg)
case typeKeyUpdate: case typeKeyUpdate:
m = new(keyUpdateMsg) m = new(keyUpdateMsg)
case typeEndOfEarlyData:
m = new(endOfEarlyDataMsg)
default: default:
return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
} }
@ -1288,6 +1374,14 @@ func (c *Conn) readHandshake() (interface{}, error) {
// so pass in a fresh copy that won't be overwritten. // so pass in a fresh copy that won't be overwritten.
data = append([]byte(nil), data...) data = append([]byte(nil), data...)
if data[0] == typeServerHello && len(data) >= 38 {
vers := uint16(data[4])<<8 | uint16(data[5])
if vers == VersionTLS12 && bytes.Equal(data[6:38], tls13HelloRetryRequest) {
m = new(helloRetryRequestMsg)
m.(*helloRetryRequestMsg).isServerHello = true
}
}
if !m.unmarshal(data) { if !m.unmarshal(data) {
return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
} }
@ -1386,10 +1480,6 @@ func (c *Conn) Write(b []byte) (int, error) {
c.out.Lock() c.out.Lock()
defer c.out.Unlock() defer c.out.Unlock()
// Flush any pending handshake data. PackHelloRequestWithFinished may
// have been set and the handshake not followed by Renegotiate.
c.flushHandshake()
if err := c.out.err; err != nil { if err := c.out.err; err != nil {
return 0, err return 0, err
} }
@ -1443,8 +1533,8 @@ func (c *Conn) processTLS13NewSessionTicket(newSessionTicket *newSessionTicketMs
return errors.New("tls: no GREASE ticket extension found") return errors.New("tls: no GREASE ticket extension found")
} }
if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.maxEarlyDataSize == 0 { if c.config.Bugs.ExpectTicketEarlyData && newSessionTicket.maxEarlyDataSize == 0 {
return errors.New("tls: no ticket_early_data_info extension found") return errors.New("tls: no early_data ticket extension found")
} }
if c.config.Bugs.ExpectNoNewSessionTicket { if c.config.Bugs.ExpectNoNewSessionTicket {
@ -1458,6 +1548,7 @@ func (c *Conn) processTLS13NewSessionTicket(newSessionTicket *newSessionTicketMs
session := &ClientSessionState{ session := &ClientSessionState{
sessionTicket: newSessionTicket.ticket, sessionTicket: newSessionTicket.ticket,
vers: c.vers, vers: c.vers,
wireVersion: c.wireVersion,
cipherSuite: cipherSuite.id, cipherSuite: cipherSuite.id,
masterSecret: c.resumptionSecret, masterSecret: c.resumptionSecret,
serverCertificates: c.peerCertificates, serverCertificates: c.peerCertificates,
@ -1470,8 +1561,15 @@ func (c *Conn) processTLS13NewSessionTicket(newSessionTicket *newSessionTicketMs
earlyALPN: c.clientProtocol, earlyALPN: c.clientProtocol,
} }
if isDraft21(c.wireVersion) {
session.masterSecret = deriveSessionPSK(cipherSuite, c.wireVersion, c.resumptionSecret, newSessionTicket.ticketNonce)
}
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config) cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
_, ok := c.config.ClientSessionCache.Get(cacheKey)
if !ok || !c.config.Bugs.UseFirstSessionTicket {
c.config.ClientSessionCache.Put(cacheKey, session) c.config.ClientSessionCache.Put(cacheKey, session)
}
return nil return nil
} }
@ -1507,7 +1605,9 @@ func (c *Conn) handlePostHandshakeMessage() error {
if c.config.Bugs.RejectUnsolicitedKeyUpdate { if c.config.Bugs.RejectUnsolicitedKeyUpdate {
return errors.New("tls: unexpected KeyUpdate message") return errors.New("tls: unexpected KeyUpdate message")
} }
c.in.doKeyUpdate(c, false) if err := c.useInTrafficSecret(c.in.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.wireVersion, c.in.trafficSecret)); err != nil {
return err
}
if keyUpdate.keyUpdateRequest == keyUpdateRequested { if keyUpdate.keyUpdateRequest == keyUpdateRequested {
c.keyUpdateRequested = true c.keyUpdateRequested = true
} }
@ -1539,8 +1639,7 @@ func (c *Conn) ReadKeyUpdateACK() error {
return errors.New("tls: received invalid KeyUpdate message") return errors.New("tls: received invalid KeyUpdate message")
} }
c.in.doKeyUpdate(c, false) return c.useInTrafficSecret(c.in.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.wireVersion, c.in.trafficSecret))
return nil
} }
func (c *Conn) Renegotiate() error { func (c *Conn) Renegotiate() error {
@ -1758,9 +1857,16 @@ func (c *Conn) ExportKeyingMaterial(length int, label, context []byte, useContex
} }
if c.vers >= VersionTLS13 { if c.vers >= VersionTLS13 {
// TODO(davidben): What should we do with useContext? See if isDraft21(c.wireVersion) {
// https://github.com/tlswg/tls13-spec/issues/546 hash := c.cipherSuite.hash()
return hkdfExpandLabel(c.cipherSuite.hash(), c.exporterSecret, label, context, length), nil exporterKeyingLabel := []byte("exporter")
contextHash := hash.New()
contextHash.Write(context)
exporterContext := hash.New().Sum(nil)
derivedSecret := hkdfExpandLabel(c.cipherSuite.hash(), c.wireVersion, c.exporterSecret, label, exporterContext, hash.Size())
return hkdfExpandLabel(c.cipherSuite.hash(), c.wireVersion, derivedSecret, exporterKeyingLabel, contextHash.Sum(nil), length), nil
}
return hkdfExpandLabel(c.cipherSuite.hash(), c.wireVersion, c.exporterSecret, label, context, length), nil
} }
seedLen := len(c.clientRandom) + len(c.serverRandom) seedLen := len(c.clientRandom) + len(c.serverRandom)
@ -1794,7 +1900,7 @@ func (c *Conn) noRenegotiationInfo() bool {
return false return false
} }
func (c *Conn) SendNewSessionTicket() error { func (c *Conn) SendNewSessionTicket(nonce []byte) error {
if c.isClient || c.vers < VersionTLS13 { if c.isClient || c.vers < VersionTLS13 {
return errors.New("tls: cannot send post-handshake NewSessionTicket") return errors.New("tls: cannot send post-handshake NewSessionTicket")
} }
@ -1814,14 +1920,19 @@ func (c *Conn) SendNewSessionTicket() error {
// TODO(davidben): Allow configuring these values. // TODO(davidben): Allow configuring these values.
m := &newSessionTicketMsg{ m := &newSessionTicketMsg{
version: c.vers, vers: c.wireVersion,
isDTLS: c.isDTLS,
ticketLifetime: uint32(24 * time.Hour / time.Second), ticketLifetime: uint32(24 * time.Hour / time.Second),
duplicateEarlyDataInfo: c.config.Bugs.DuplicateTicketEarlyDataInfo, duplicateEarlyDataExtension: c.config.Bugs.DuplicateTicketEarlyData,
customExtension: c.config.Bugs.CustomTicketExtension, customExtension: c.config.Bugs.CustomTicketExtension,
ticketAgeAdd: ticketAgeAdd, ticketAgeAdd: ticketAgeAdd,
maxEarlyDataSize: c.config.MaxEarlyDataSize, maxEarlyDataSize: c.config.MaxEarlyDataSize,
} }
if isDraft21(c.wireVersion) {
m.ticketNonce = nonce
}
if c.config.Bugs.SendTicketLifetime != 0 { if c.config.Bugs.SendTicketLifetime != 0 {
m.ticketLifetime = uint32(c.config.Bugs.SendTicketLifetime / time.Second) m.ticketLifetime = uint32(c.config.Bugs.SendTicketLifetime / time.Second)
} }
@ -1837,6 +1948,10 @@ func (c *Conn) SendNewSessionTicket() error {
earlyALPN: []byte(c.clientProtocol), earlyALPN: []byte(c.clientProtocol),
} }
if isDraft21(c.wireVersion) {
state.masterSecret = deriveSessionPSK(c.cipherSuite, c.wireVersion, c.resumptionSecret, nonce)
}
if !c.config.Bugs.SendEmptySessionTicket { if !c.config.Bugs.SendEmptySessionTicket {
var err error var err error
m.ticket, err = c.encryptTicket(&state) m.ticket, err = c.encryptTicket(&state)
@ -1870,7 +1985,7 @@ func (c *Conn) sendKeyUpdateLocked(keyUpdateRequest byte) error {
if err := c.flushHandshake(); err != nil { if err := c.flushHandshake(); err != nil {
return err return err
} }
c.out.doKeyUpdate(c, true) c.useOutTrafficSecret(c.out.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.wireVersion, c.out.trafficSecret))
return nil return nil
} }
@ -1881,6 +1996,10 @@ func (c *Conn) sendFakeEarlyData(len int) error {
payload[0] = byte(recordTypeApplicationData) payload[0] = byte(recordTypeApplicationData)
payload[1] = 3 payload[1] = 3
payload[2] = 1 payload[2] = 1
if isResumptionRecordVersionVariant(c.config.TLS13Variant) {
payload[1] = 3
payload[2] = 3
}
payload[3] = byte(len >> 8) payload[3] = byte(len >> 8)
payload[4] = byte(len) payload[4] = byte(len)
_, err := c.conn.Write(payload) _, err := c.conn.Write(payload)

View File

@ -23,26 +23,6 @@ import (
"net" "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) { func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) {
recordHeaderLen := dtlsRecordHeaderLen recordHeaderLen := dtlsRecordHeaderLen
@ -149,25 +129,37 @@ func (c *Conn) makeFragment(header, data []byte, fragOffset, fragLen int) []byte
} }
func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) { func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
// Only handshake messages are fragmented.
if typ != recordTypeHandshake { if typ != recordTypeHandshake {
reorder := typ == recordTypeChangeCipherSpec && c.config.Bugs.ReorderChangeCipherSpec reorder := typ == recordTypeChangeCipherSpec && c.config.Bugs.ReorderChangeCipherSpec
// Flush pending handshake messages before writing a new record. // Flush pending handshake messages before encrypting a new record.
if !reorder { if !reorder {
err = c.dtlsFlushHandshake() err = c.dtlsPackHandshake()
if err != nil { if err != nil {
return return
} }
} }
// Only handshake messages are fragmented. if typ == recordTypeApplicationData && len(data) > 1 && c.config.Bugs.SplitAndPackAppData {
n, err = c.dtlsWriteRawRecord(typ, data) _, err = c.dtlsPackRecord(typ, data[:len(data)/2], false)
if err != nil { if err != nil {
return return
} }
_, err = c.dtlsPackRecord(typ, data[len(data)/2:], true)
if err != nil {
return
}
n = len(data)
} else {
n, err = c.dtlsPackRecord(typ, data, false)
if err != nil {
return
}
}
if reorder { if reorder {
err = c.dtlsFlushHandshake() err = c.dtlsPackHandshake()
if err != nil { if err != nil {
return return
} }
@ -178,12 +170,19 @@ func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
if err != nil { if err != nil {
return n, c.sendAlertLocked(alertLevelError, err.(alert)) return n, c.sendAlertLocked(alertLevelError, err.(alert))
} }
} else {
// ChangeCipherSpec is part of the handshake and not
// flushed until dtlsFlushPacket.
err = c.dtlsFlushPacket()
if err != nil {
return
}
} }
return return
} }
if c.out.cipher == nil && c.config.Bugs.StrayChangeCipherSpec { if c.out.cipher == nil && c.config.Bugs.StrayChangeCipherSpec {
_, err = c.dtlsWriteRawRecord(recordTypeChangeCipherSpec, []byte{1}) _, err = c.dtlsPackRecord(recordTypeChangeCipherSpec, []byte{1}, false)
if err != nil { if err != nil {
return return
} }
@ -209,8 +208,8 @@ func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
isFinished := header[0] == typeFinished isFinished := header[0] == typeFinished
if c.config.Bugs.SendEmptyFragments { if c.config.Bugs.SendEmptyFragments {
fragment := c.makeFragment(header, data, 0, 0) c.pendingFragments = append(c.pendingFragments, c.makeFragment(header, data, 0, 0))
c.pendingFragments = append(c.pendingFragments, fragment) c.pendingFragments = append(c.pendingFragments, c.makeFragment(header, data, len(data), 0))
} }
firstRun := true firstRun := true
@ -263,7 +262,9 @@ func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
return return
} }
func (c *Conn) dtlsFlushHandshake() error { // dtlsPackHandshake packs the pending handshake flight into the pending
// record. Callers should follow up with dtlsFlushPacket to write the packets.
func (c *Conn) dtlsPackHandshake() error {
// This is a test-only DTLS implementation, so there is no need to // This is a test-only DTLS implementation, so there is no need to
// retain |c.pendingFragments| for a future retransmit. // retain |c.pendingFragments| for a future retransmit.
var fragments [][]byte var fragments [][]byte
@ -285,7 +286,6 @@ func (c *Conn) dtlsFlushHandshake() error {
} }
maxRecordLen := c.config.Bugs.PackHandshakeFragments maxRecordLen := c.config.Bugs.PackHandshakeFragments
maxPacketLen := c.config.Bugs.PackHandshakeRecords
// Pack handshake fragments into records. // Pack handshake fragments into records.
var records [][]byte var records [][]byte
@ -305,42 +305,39 @@ func (c *Conn) dtlsFlushHandshake() error {
} }
} }
// Format them into packets. // Send the records.
var packets [][]byte
for _, record := range records { for _, record := range records {
b, err := c.dtlsSealRecord(recordTypeHandshake, record) _, err := c.dtlsPackRecord(recordTypeHandshake, record, false)
if err != nil { if err != nil {
return err return err
} }
if i := len(packets) - 1; len(packets) > 0 && len(packets[i])+len(b.data) <= maxPacketLen {
packets[i] = append(packets[i], b.data...)
} else {
// The sealed record will be appended to and reused by
// |c.out|, so copy it.
packets = append(packets, append([]byte{}, b.data...))
}
c.out.freeBlock(b)
} }
// Send all the packets.
for _, packet := range packets {
if _, err := c.conn.Write(packet); err != nil {
return err
}
}
return nil return nil
} }
// dtlsSealRecord seals a record into a block from |c.out|'s pool. func (c *Conn) dtlsFlushHandshake() error {
func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error) { if err := c.dtlsPackHandshake(); err != nil {
return err
}
if err := c.dtlsFlushPacket(); err != nil {
return err
}
return nil
}
// dtlsPackRecord packs a single record to the pending packet, flushing it
// if necessary. The caller should call dtlsFlushPacket to flush the current
// pending packet afterwards.
func (c *Conn) dtlsPackRecord(typ recordType, data []byte, mustPack bool) (n int, err error) {
recordHeaderLen := dtlsRecordHeaderLen recordHeaderLen := dtlsRecordHeaderLen
maxLen := c.config.Bugs.MaxHandshakeRecordLength maxLen := c.config.Bugs.MaxHandshakeRecordLength
if maxLen <= 0 { if maxLen <= 0 {
maxLen = 1024 maxLen = 1024
} }
b = c.out.newBlock() b := c.out.newBlock()
explicitIVLen := 0 explicitIVLen := 0
explicitIVIsSeq := false explicitIVIsSeq := false
@ -392,23 +389,30 @@ func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error)
} }
copy(b.data[recordHeaderLen+explicitIVLen:], data) copy(b.data[recordHeaderLen+explicitIVLen:], data)
c.out.encrypt(b, explicitIVLen, typ) c.out.encrypt(b, explicitIVLen, typ)
// Flush the current pending packet if necessary.
if !mustPack && len(b.data)+len(c.pendingPacket) > c.config.Bugs.PackHandshakeRecords {
err = c.dtlsFlushPacket()
if err != nil {
c.out.freeBlock(b)
return
}
}
// Add the record to the pending packet.
c.pendingPacket = append(c.pendingPacket, b.data...)
c.out.freeBlock(b)
n = len(data)
return return
} }
func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) { func (c *Conn) dtlsFlushPacket() error {
b, err := c.dtlsSealRecord(typ, data) if len(c.pendingPacket) == 0 {
if err != nil { return nil
return
} }
_, err := c.conn.Write(c.pendingPacket)
_, err = c.conn.Write(b.data) c.pendingPacket = nil
if err != nil { return err
return
}
n = len(data)
c.out.freeBlock(b)
return
} }
func (c *Conn) dtlsDoReadHandshake() ([]byte, error) { func (c *Conn) dtlsDoReadHandshake() ([]byte, error) {

View File

@ -35,17 +35,17 @@
"Resume-Server-*Binder*": "Fuzzer mode does not check binders.", "Resume-Server-*Binder*": "Fuzzer mode does not check binders.",
"SkipEarlyData*": "Trial decryption does not work with the NULL cipher.", "SkipEarlyData*": "Trial decryption does not work with the NULL cipher.",
"*-EarlyDataChannelID-OfferBoth-Server": "Trial decryption does not work with the NULL cipher.", "EarlyDataChannelID-OfferBoth-Server-*": "Trial decryption does not work with the NULL cipher.",
"*-EarlyData-NonZeroRTTSession-Server": "Trial decryption does not work with the NULL cipher.", "EarlyData-NonZeroRTTSession-Server-*": "Trial decryption does not work with the NULL cipher.",
"*-EarlyData-SkipEndOfEarlyData": "Trial decryption does not work with the NULL cipher.", "EarlyData-SkipEndOfEarlyData-*": "Trial decryption does not work with the NULL cipher.",
"*-EarlyData-ALPNMismatch-Server": "Trial decryption does not work with the NULL cipher.", "EarlyData-ALPNMismatch-Server-*": "Trial decryption does not work with the NULL cipher.",
"*-EarlyData-ALPNOmitted1-Client": "Trial decryption does not work with the NULL cipher.", "EarlyData-ALPNOmitted1-Client-*": "Trial decryption does not work with the NULL cipher.",
"*-EarlyData-ALPNOmitted2-Client": "Trial decryption does not work with the NULL cipher.", "EarlyData-ALPNOmitted2-Client-*": "Trial decryption does not work with the NULL cipher.",
"*-EarlyData-ALPNOmitted1-Server": "Trial decryption does not work with the NULL cipher.", "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-ALPNOmitted2-Server-*": "Trial decryption does not work with the NULL cipher.",
"*-EarlyData-RejectUnfinishedWrite-Client-*": "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.", "EarlyData-RejectTicket-Client-*": "Trial decryption does not work with the NULL cipher.",
"Renegotiate-Client-BadExt*": "Fuzzer mode does not check renegotiation_info.", "Renegotiate-Client-BadExt*": "Fuzzer mode does not check renegotiation_info.",

View File

@ -211,10 +211,6 @@ NextCipherSuite:
if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 { if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
continue continue
} }
// Don't advertise non-DTLS cipher suites in DTLS.
if c.isDTLS && suite.flags&suiteNoDTLS != 0 {
continue
}
hello.cipherSuites = append(hello.cipherSuites, suiteId) hello.cipherSuites = append(hello.cipherSuites, suiteId)
continue NextCipherSuite continue NextCipherSuite
} }
@ -376,7 +372,14 @@ NextCipherSuite:
c.writeV2Record(helloBytes) c.writeV2Record(helloBytes)
} else { } else {
if len(hello.pskIdentities) > 0 { if len(hello.pskIdentities) > 0 {
generatePSKBinders(hello, pskCipherSuite, session.masterSecret, []byte{}, c.config) version := session.wireVersion
// We may have a pre-1.3 session if SendBothTickets is
// set. Fill in an arbitrary TLS 1.3 version to compute
// the binder.
if session.vers < VersionTLS13 {
version = tls13DraftVersion
}
generatePSKBinders(version, hello, pskCipherSuite, session.masterSecret, []byte{}, []byte{}, c.config)
} }
helloBytes = hello.marshal() helloBytes = hello.marshal()
@ -407,11 +410,23 @@ NextCipherSuite:
// Derive early write keys and set Conn state to allow early writes. // Derive early write keys and set Conn state to allow early writes.
if sendEarlyData { if sendEarlyData {
finishedHash := newFinishedHash(session.vers, pskCipherSuite) finishedHash := newFinishedHash(session.wireVersion, c.isDTLS, pskCipherSuite)
finishedHash.addEntropy(session.masterSecret) finishedHash.addEntropy(session.masterSecret)
finishedHash.Write(helloBytes) finishedHash.Write(helloBytes)
earlyTrafficSecret := finishedHash.deriveSecret(earlyTrafficLabel)
c.out.useTrafficSecret(session.vers, pskCipherSuite, earlyTrafficSecret, clientWrite) earlyLabel := earlyTrafficLabel
if isDraft21(session.wireVersion) {
earlyLabel = earlyTrafficLabelDraft21
}
if !c.config.Bugs.SkipChangeCipherSpec && isDraft22(session.wireVersion) {
c.wireVersion = session.wireVersion
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
c.wireVersion = 0
}
earlyTrafficSecret := finishedHash.deriveSecret(earlyLabel)
c.useOutTrafficSecret(session.wireVersion, pskCipherSuite, earlyTrafficSecret)
for _, earlyData := range c.config.Bugs.SendEarlyData { for _, earlyData := range c.config.Bugs.SendEarlyData {
if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil { if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil {
return err return err
@ -470,9 +485,22 @@ NextCipherSuite:
c.vers = serverVersion c.vers = serverVersion
c.haveVers = true c.haveVers = true
if isDraft22(c.wireVersion) {
// The first server message must be followed by a ChangeCipherSpec.
c.expectTLS13ChangeCipherSpec = true
}
helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg) helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg)
var secondHelloBytes []byte var secondHelloBytes []byte
if haveHelloRetryRequest { if haveHelloRetryRequest {
if isDraft22(c.wireVersion) {
// Explicitly read the ChangeCipherSpec now; it should
// be attached to the first flight, not the second flight.
if err := c.readTLS13ChangeCipherSpec(); err != nil {
return err
}
}
c.out.resetCipher() c.out.resetCipher()
if len(helloRetryRequest.cookie) > 0 { if len(helloRetryRequest.cookie) > 0 {
hello.tls13Cookie = helloRetryRequest.cookie hello.tls13Cookie = helloRetryRequest.cookie
@ -518,7 +546,7 @@ NextCipherSuite:
hello.raw = nil hello.raw = nil
if len(hello.pskIdentities) > 0 { if len(hello.pskIdentities) > 0 {
generatePSKBinders(hello, pskCipherSuite, session.masterSecret, append(helloBytes, helloRetryRequest.marshal()...), c.config) generatePSKBinders(c.wireVersion, hello, pskCipherSuite, session.masterSecret, helloBytes, helloRetryRequest.marshal(), c.config)
} }
secondHelloBytes = hello.marshal() secondHelloBytes = hello.marshal()
@ -588,13 +616,19 @@ NextCipherSuite:
serverHello: serverHello, serverHello: serverHello,
hello: hello, hello: hello,
suite: suite, suite: suite,
finishedHash: newFinishedHash(c.vers, suite), finishedHash: newFinishedHash(c.wireVersion, c.isDTLS, suite),
keyShares: keyShares, keyShares: keyShares,
session: session, session: session,
} }
hs.writeHash(helloBytes, hs.c.sendHandshakeSeq-1) hs.writeHash(helloBytes, hs.c.sendHandshakeSeq-1)
if haveHelloRetryRequest { if haveHelloRetryRequest {
if isDraft21(c.wireVersion) {
err = hs.finishedHash.UpdateForHelloRetryRequest()
if err != nil {
return err
}
}
hs.writeServerHash(helloRetryRequest.marshal()) hs.writeServerHash(helloRetryRequest.marshal())
hs.writeClientHash(secondHelloBytes) hs.writeClientHash(secondHelloBytes)
} }
@ -690,7 +724,13 @@ NextCipherSuite:
func (hs *clientHandshakeState) doTLS13Handshake() error { func (hs *clientHandshakeState) doTLS13Handshake() error {
c := hs.c c := hs.c
if c.wireVersion == tls13ExperimentVersion && !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) { if isResumptionExperiment(c.wireVersion) && !isDraft22(c.wireVersion) {
// Early versions of the middlebox hacks inserted
// ChangeCipherSpec differently on 0-RTT and 2-RTT handshakes.
c.expectTLS13ChangeCipherSpec = true
}
if isResumptionExperiment(c.wireVersion) && !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) {
return errors.New("tls: session IDs did not match.") return errors.New("tls: session IDs did not match.")
} }
@ -739,22 +779,27 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
if err != nil { if err != nil {
return err return err
} }
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(ecdheSecret) hs.finishedHash.addEntropy(ecdheSecret)
} else { } else {
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(zeroSecret) hs.finishedHash.addEntropy(zeroSecret)
} }
if c.wireVersion == tls13ExperimentVersion { clientLabel := clientHandshakeTrafficLabel
if err := c.readRecord(recordTypeChangeCipherSpec); err != nil { serverLabel := serverHandshakeTrafficLabel
return err if isDraft21(c.wireVersion) {
} clientLabel = clientHandshakeTrafficLabelDraft21
serverLabel = serverHandshakeTrafficLabelDraft21
} }
// Derive handshake traffic keys and switch read key to handshake // Derive handshake traffic keys and switch read key to handshake
// traffic key. // traffic key.
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite) if err := c.useInTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret); err != nil {
return err
}
msg, err := c.readHandshake() msg, err := c.readHandshake()
if err != nil { if err != nil {
@ -793,6 +838,10 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
return errors.New("tls: non-empty certificate request context sent in handshake") return errors.New("tls: non-empty certificate request context sent in handshake")
} }
if c.config.Bugs.ExpectNoCertificateAuthoritiesExtension && certReq.hasCAExtension {
return errors.New("tls: expected no certificate_authorities extension")
}
if c.config.Bugs.IgnorePeerSignatureAlgorithmPreferences { if c.config.Bugs.IgnorePeerSignatureAlgorithmPreferences {
certReq.signatureAlgorithms = c.config.signSignatureAlgorithms() certReq.signatureAlgorithms = c.config.signSignatureAlgorithms()
} }
@ -881,17 +930,30 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
// The various secrets do not incorporate the client's final leg, so // The various secrets do not incorporate the client's final leg, so
// derive them now before updating the handshake context. // derive them now before updating the handshake context.
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(zeroSecret) hs.finishedHash.addEntropy(zeroSecret)
clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel)
serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel) clientLabel = clientApplicationTrafficLabel
c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel) serverLabel = serverApplicationTrafficLabel
exportLabel := exporterLabel
if isDraft21(c.wireVersion) {
clientLabel = clientApplicationTrafficLabelDraft21
serverLabel = serverApplicationTrafficLabelDraft21
exportLabel = exporterLabelDraft21
}
clientTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
serverTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
c.exporterSecret = hs.finishedHash.deriveSecret(exportLabel)
// Switch to application data keys on read. In particular, any alerts // Switch to application data keys on read. In particular, any alerts
// from the client certificate are read over these keys. // from the client certificate are read over these keys.
c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite) if err := c.useInTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret); err != nil {
return err
}
// If we're expecting 0.5-RTT messages from the server, read them // If we're expecting 0.5-RTT messages from the server, read them now.
// now. var deferredTickets []*newSessionTicketMsg
if encryptedExtensions.extensions.hasEarlyData { if encryptedExtensions.extensions.hasEarlyData {
// BoringSSL will always send two tickets half-RTT when // BoringSSL will always send two tickets half-RTT when
// negotiating 0-RTT. // negotiating 0-RTT.
@ -904,9 +966,8 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
if !ok { if !ok {
return errors.New("tls: expected half-RTT ticket") return errors.New("tls: expected half-RTT ticket")
} }
if err := c.processTLS13NewSessionTicket(newSessionTicket, hs.suite); err != nil { // Defer processing until the resumption secret is computed.
return err deferredTickets = append(deferredTickets, newSessionTicket)
}
} }
for _, expectedMsg := range c.config.Bugs.ExpectHalfRTTData { for _, expectedMsg := range c.config.Bugs.ExpectHalfRTTData {
if err := c.readRecord(recordTypeApplicationData); err != nil { if err := c.readRecord(recordTypeApplicationData); err != nil {
@ -922,19 +983,30 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
// Send EndOfEarlyData and then switch write key to handshake // Send EndOfEarlyData and then switch write key to handshake
// traffic key. // traffic key.
if c.out.cipher != nil && !c.config.Bugs.SkipEndOfEarlyData { if encryptedExtensions.extensions.hasEarlyData && c.out.cipher != nil && !c.config.Bugs.SkipEndOfEarlyData {
if c.config.Bugs.SendStrayEarlyHandshake { if c.config.Bugs.SendStrayEarlyHandshake {
helloRequest := new(helloRequestMsg) helloRequest := new(helloRequestMsg)
c.writeRecord(recordTypeHandshake, helloRequest.marshal()) c.writeRecord(recordTypeHandshake, helloRequest.marshal())
} }
if isDraft21(c.wireVersion) {
endOfEarlyData := new(endOfEarlyDataMsg)
endOfEarlyData.nonEmpty = c.config.Bugs.NonEmptyEndOfEarlyData
c.writeRecord(recordTypeHandshake, endOfEarlyData.marshal())
hs.writeClientHash(endOfEarlyData.marshal())
} else {
c.sendAlert(alertEndOfEarlyData) c.sendAlert(alertEndOfEarlyData)
} }
}
if c.wireVersion == tls13ExperimentVersion { if !c.config.Bugs.SkipChangeCipherSpec && isResumptionClientCCSExperiment(c.wireVersion) && !hs.hello.hasEarlyData {
c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
} }
c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite) for i := 0; i < c.config.Bugs.SendExtraChangeCipherSpec; i++ {
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
}
c.useOutTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret)
if certReq != nil && !c.config.Bugs.SkipClientCertificate { if certReq != nil && !c.config.Bugs.SkipClientCertificate {
certMsg := &certificateMsg{ certMsg := &certificateMsg{
@ -1020,9 +1092,20 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
c.flushHandshake() c.flushHandshake()
// Switch to application data keys. // Switch to application data keys.
c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite) c.useOutTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret)
resumeLabel := resumptionLabel
if isDraft21(c.wireVersion) {
resumeLabel = resumptionLabelDraft21
}
c.resumptionSecret = hs.finishedHash.deriveSecret(resumeLabel)
for _, ticket := range deferredTickets {
if err := c.processTLS13NewSessionTicket(ticket, hs.suite); err != nil {
return err
}
}
c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel)
return nil return nil
} }
@ -1287,8 +1370,8 @@ func (hs *clientHandshakeState) establishKeys() error {
serverCipher = hs.suite.aead(c.vers, serverKey, serverIV) serverCipher = hs.suite.aead(c.vers, serverKey, serverIV)
} }
c.in.prepareCipherSpec(c.vers, serverCipher, serverHash) c.in.prepareCipherSpec(c.wireVersion, serverCipher, serverHash)
c.out.prepareCipherSpec(c.vers, clientCipher, clientHash) c.out.prepareCipherSpec(c.wireVersion, clientCipher, clientHash)
return nil return nil
} }
@ -1498,6 +1581,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
// session ID or session ticket will be attached. // session ID or session ticket will be attached.
session := &ClientSessionState{ session := &ClientSessionState{
vers: c.vers, vers: c.vers,
wireVersion: c.wireVersion,
cipherSuite: hs.suite.id, cipherSuite: hs.suite.id,
masterSecret: hs.masterSecret, masterSecret: hs.masterSecret,
handshakeHash: hs.finishedHash.Sum(), handshakeHash: hs.finishedHash.Sum(),
@ -1622,7 +1706,9 @@ func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
} }
} }
if !isResume || !c.config.Bugs.PackAppDataWithHandshake {
c.flushHandshake() c.flushHandshake()
}
return nil return nil
} }
@ -1729,7 +1815,7 @@ func writeIntPadded(b []byte, x *big.Int) {
copy(b[len(b)-len(xb):], xb) copy(b[len(b)-len(xb):], xb)
} }
func generatePSKBinders(hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk, transcript []byte, config *Config) { func generatePSKBinders(version uint16, hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk, firstClientHello, helloRetryRequest []byte, config *Config) {
if config.Bugs.SendNoPSKBinder { if config.Bugs.SendNoPSKBinder {
return return
} }
@ -1755,7 +1841,11 @@ func generatePSKBinders(hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk,
helloBytes := hello.marshal() helloBytes := hello.marshal()
binderSize := len(hello.pskBinders)*(binderLen+1) + 2 binderSize := len(hello.pskBinders)*(binderLen+1) + 2
truncatedHello := helloBytes[:len(helloBytes)-binderSize] truncatedHello := helloBytes[:len(helloBytes)-binderSize]
binder := computePSKBinder(psk, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello) binderLabel := resumptionPSKBinderLabel
if isDraft21(version) {
binderLabel = resumptionPSKBinderLabelDraft21
}
binder := computePSKBinder(psk, version, binderLabel, pskCipherSuite, firstClientHello, helloRetryRequest, truncatedHello)
if config.Bugs.SendShortPSKBinder { if config.Bugs.SendShortPSKBinder {
binder = binder[:binderLen] binder = binder[:binderLen]
} }

View File

@ -175,6 +175,7 @@ type clientHelloMsg struct {
pskBinderFirst bool pskBinderFirst bool
omitExtensions bool omitExtensions bool
emptyExtensions bool emptyExtensions bool
pad int
} }
func (m *clientHelloMsg) equal(i interface{}) bool { func (m *clientHelloMsg) equal(i interface{}) bool {
@ -222,7 +223,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.hasGREASEExtension == m1.hasGREASEExtension && m.hasGREASEExtension == m1.hasGREASEExtension &&
m.pskBinderFirst == m1.pskBinderFirst && m.pskBinderFirst == m1.pskBinderFirst &&
m.omitExtensions == m1.omitExtensions && m.omitExtensions == m1.omitExtensions &&
m.emptyExtensions == m1.emptyExtensions m.emptyExtensions == m1.emptyExtensions &&
m.pad == m1.pad
} }
func (m *clientHelloMsg) marshal() []byte { func (m *clientHelloMsg) marshal() []byte {
@ -454,6 +456,16 @@ func (m *clientHelloMsg) marshal() []byte {
} }
} }
if m.pad != 0 && hello.len()%m.pad != 0 {
extensions.addU16(extensionPadding)
padding := extensions.addU16LengthPrefixed()
// Note hello.len() has changed at this point from the length
// prefix.
if l := hello.len() % m.pad; l != 0 {
padding.addBytes(make([]byte, m.pad-l))
}
}
if m.omitExtensions || m.emptyExtensions { if m.omitExtensions || m.emptyExtensions {
// Silently erase any extensions which were sent. // Silently erase any extensions which were sent.
hello.discardChild() hello.discardChild()
@ -463,6 +475,10 @@ func (m *clientHelloMsg) marshal() []byte {
} }
m.raw = handshakeMsg.finish() m.raw = handshakeMsg.finish()
// Sanity-check padding.
if m.pad != 0 && (len(m.raw)-4)%m.pad != 0 {
panic(fmt.Sprintf("%d is not a multiple of %d", len(m.raw)-4, m.pad))
}
return m.raw return m.raw
} }
@ -865,19 +881,19 @@ func (m *serverHelloMsg) marshal() []byte {
} }
if m.versOverride != 0 { if m.versOverride != 0 {
hello.addU16(m.versOverride) hello.addU16(m.versOverride)
} else if m.vers == tls13ExperimentVersion { } else if isResumptionExperiment(m.vers) {
hello.addU16(VersionTLS12) hello.addU16(VersionTLS12)
} else { } else {
hello.addU16(m.vers) hello.addU16(m.vers)
} }
hello.addBytes(m.random) hello.addBytes(m.random)
if vers < VersionTLS13 || m.vers == tls13ExperimentVersion { if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
sessionId := hello.addU8LengthPrefixed() sessionId := hello.addU8LengthPrefixed()
sessionId.addBytes(m.sessionId) sessionId.addBytes(m.sessionId)
} }
hello.addU16(m.cipherSuite) hello.addU16(m.cipherSuite)
if vers < VersionTLS13 || m.vers == tls13ExperimentVersion { if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
hello.addU8(m.compressionMethod) hello.addU8(m.compressionMethod)
} }
@ -896,7 +912,7 @@ func (m *serverHelloMsg) marshal() []byte {
extensions.addU16(2) // Length extensions.addU16(2) // Length
extensions.addU16(m.pskIdentity) extensions.addU16(m.pskIdentity)
} }
if m.vers == tls13ExperimentVersion || m.supportedVersOverride != 0 { if isResumptionExperiment(m.vers) || m.supportedVersOverride != 0 {
extensions.addU16(extensionSupportedVersions) extensions.addU16(extensionSupportedVersions)
extensions.addU16(2) // Length extensions.addU16(2) // Length
if m.supportedVersOverride != 0 { if m.supportedVersOverride != 0 {
@ -950,7 +966,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
} }
m.random = data[6:38] m.random = data[6:38]
data = data[38:] data = data[38:]
if vers < VersionTLS13 || m.vers == tls13ExperimentVersion { if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
sessionIdLen := int(data[0]) sessionIdLen := int(data[0])
if sessionIdLen > 32 || len(data) < 1+sessionIdLen { if sessionIdLen > 32 || len(data) < 1+sessionIdLen {
return false return false
@ -963,7 +979,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
} }
m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]) m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
data = data[2:] data = data[2:]
if vers < VersionTLS13 || m.vers == tls13ExperimentVersion { if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
if len(data) < 1 { if len(data) < 1 {
return false return false
} }
@ -1052,7 +1068,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
m.pskIdentity = uint16(d[0])<<8 | uint16(d[1]) m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
m.hasPSKIdentity = true m.hasPSKIdentity = true
case extensionSupportedVersions: case extensionSupportedVersions:
if m.vers != tls13ExperimentVersion { if !isResumptionExperiment(m.vers) {
return false return false
} }
default: default:
@ -1133,6 +1149,7 @@ type serverExtensions struct {
keyShare keyShareEntry keyShare keyShareEntry
supportedVersion uint16 supportedVersion uint16
supportedPoints []uint8 supportedPoints []uint8
supportedCurves []CurveID
serverNameAck bool serverNameAck bool
} }
@ -1240,6 +1257,15 @@ func (m *serverExtensions) marshal(extensions *byteBuilder) {
supportedPoints := supportedPointsList.addU8LengthPrefixed() supportedPoints := supportedPointsList.addU8LengthPrefixed()
supportedPoints.addBytes(m.supportedPoints) supportedPoints.addBytes(m.supportedPoints)
} }
if len(m.supportedCurves) > 0 {
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.4
extensions.addU16(extensionSupportedCurves)
supportedCurvesList := extensions.addU16LengthPrefixed()
supportedCurves := supportedCurvesList.addU16LengthPrefixed()
for _, curve := range m.supportedCurves {
supportedCurves.addU16(uint16(curve))
}
}
if m.hasEarlyData { if m.hasEarlyData {
extensions.addU16(extensionEarlyData) extensions.addU16(extensionEarlyData)
extensions.addBytes([]byte{0, 0}) extensions.addBytes([]byte{0, 0})
@ -1380,6 +1406,9 @@ func (m *serverExtensions) unmarshal(data []byte, version uint16) bool {
type helloRetryRequestMsg struct { type helloRetryRequestMsg struct {
raw []byte raw []byte
vers uint16 vers uint16
isServerHello bool
sessionId []byte
cipherSuite uint16
hasSelectedGroup bool hasSelectedGroup bool
selectedGroup CurveID selectedGroup CurveID
cookie []byte cookie []byte
@ -1393,9 +1422,26 @@ func (m *helloRetryRequestMsg) marshal() []byte {
} }
retryRequestMsg := newByteBuilder() retryRequestMsg := newByteBuilder()
if isDraft22(m.vers) {
retryRequestMsg.addU8(typeServerHello)
} else {
retryRequestMsg.addU8(typeHelloRetryRequest) retryRequestMsg.addU8(typeHelloRetryRequest)
}
retryRequest := retryRequestMsg.addU24LengthPrefixed() retryRequest := retryRequestMsg.addU24LengthPrefixed()
if isDraft22(m.vers) {
retryRequest.addU16(VersionTLS12)
retryRequest.addBytes(tls13HelloRetryRequest)
sessionId := retryRequest.addU8LengthPrefixed()
sessionId.addBytes(m.sessionId)
retryRequest.addU16(m.cipherSuite)
retryRequest.addU8(0)
} else {
retryRequest.addU16(m.vers) retryRequest.addU16(m.vers)
if isDraft21(m.vers) {
retryRequest.addU16(m.cipherSuite)
}
}
extensions := retryRequest.addU16LengthPrefixed() extensions := retryRequest.addU16LengthPrefixed()
count := 1 count := 1
@ -1404,12 +1450,18 @@ func (m *helloRetryRequestMsg) marshal() []byte {
} }
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
if isDraft22(m.vers) {
extensions.addU16(extensionSupportedVersions)
extensions.addU16(2) // Length
extensions.addU16(m.vers)
}
if m.hasSelectedGroup { if m.hasSelectedGroup {
extensions.addU16(extensionKeyShare) extensions.addU16(extensionKeyShare)
extensions.addU16(2) // length extensions.addU16(2) // length
extensions.addU16(uint16(m.selectedGroup)) extensions.addU16(uint16(m.selectedGroup))
} }
if len(m.cookie) > 0 { // m.cookie may be a non-nil empty slice for empty cookie tests.
if m.cookie != nil {
extensions.addU16(extensionCookie) extensions.addU16(extensionCookie)
body := extensions.addU16LengthPrefixed() body := extensions.addU16LengthPrefixed()
body.addU16LengthPrefixed().addBytes(m.cookie) body.addU16LengthPrefixed().addBytes(m.cookie)
@ -1430,8 +1482,29 @@ func (m *helloRetryRequestMsg) unmarshal(data []byte) bool {
return false return false
} }
m.vers = uint16(data[4])<<8 | uint16(data[5]) m.vers = uint16(data[4])<<8 | uint16(data[5])
extLen := int(data[6])<<8 | int(data[7]) data = data[6:]
data = data[8:] if m.isServerHello {
if len(data) < 33 {
return false
}
data = data[32:] // Random
sessionIdLen := int(data[0])
if sessionIdLen > 32 || len(data) < 1+sessionIdLen+3 {
return false
}
m.sessionId = data[1 : 1+sessionIdLen]
data = data[1+sessionIdLen:]
m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
data = data[1:] // Compression Method
} else {
if isDraft21(m.vers) {
m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
}
}
extLen := int(data[0])<<8 | int(data[1])
data = data[2:]
if len(data) != extLen || len(data) == 0 { if len(data) != extLen || len(data) == 0 {
return false return false
} }
@ -1447,6 +1520,11 @@ func (m *helloRetryRequestMsg) unmarshal(data []byte) bool {
} }
switch extension { switch extension {
case extensionSupportedVersions:
if length != 2 || !m.isServerHello {
return false
}
m.vers = uint16(data[0])<<8 | uint16(data[1])
case extensionKeyShare: case extensionKeyShare:
if length != 2 { if length != 2 {
return false return false
@ -1845,6 +1923,7 @@ func (m *nextProtoMsg) unmarshal(data []byte) bool {
type certificateRequestMsg struct { type certificateRequestMsg struct {
raw []byte raw []byte
vers uint16
// hasSignatureAlgorithm indicates whether this message includes a list // hasSignatureAlgorithm indicates whether this message includes a list
// of signature and hash functions. This change was introduced with TLS // of signature and hash functions. This change was introduced with TLS
// 1.2. // 1.2.
@ -1858,6 +1937,8 @@ type certificateRequestMsg struct {
requestContext []byte requestContext []byte
signatureAlgorithms []signatureAlgorithm signatureAlgorithms []signatureAlgorithm
certificateAuthorities [][]byte certificateAuthorities [][]byte
hasCAExtension bool
customExtension uint16
} }
func (m *certificateRequestMsg) marshal() []byte { func (m *certificateRequestMsg) marshal() []byte {
@ -1873,10 +1954,47 @@ func (m *certificateRequestMsg) marshal() []byte {
if m.hasRequestContext { if m.hasRequestContext {
requestContext := body.addU8LengthPrefixed() requestContext := body.addU8LengthPrefixed()
requestContext.addBytes(m.requestContext) requestContext.addBytes(m.requestContext)
extensions := newByteBuilder()
if isDraft21(m.vers) {
extensions = body.addU16LengthPrefixed()
if m.hasSignatureAlgorithm {
extensions.addU16(extensionSignatureAlgorithms)
signatureAlgorithms := extensions.addU16LengthPrefixed().addU16LengthPrefixed()
for _, sigAlg := range m.signatureAlgorithms {
signatureAlgorithms.addU16(uint16(sigAlg))
}
}
if len(m.certificateAuthorities) > 0 {
extensions.addU16(extensionCertificateAuthorities)
certificateAuthorities := extensions.addU16LengthPrefixed().addU16LengthPrefixed()
for _, ca := range m.certificateAuthorities {
caEntry := certificateAuthorities.addU16LengthPrefixed()
caEntry.addBytes(ca)
}
}
} else {
if m.hasSignatureAlgorithm {
signatureAlgorithms := body.addU16LengthPrefixed()
for _, sigAlg := range m.signatureAlgorithms {
signatureAlgorithms.addU16(uint16(sigAlg))
}
}
certificateAuthorities := body.addU16LengthPrefixed()
for _, ca := range m.certificateAuthorities {
caEntry := certificateAuthorities.addU16LengthPrefixed()
caEntry.addBytes(ca)
}
extensions = body.addU16LengthPrefixed()
}
if m.customExtension > 0 {
extensions.addU16(m.customExtension)
extensions.addU16LengthPrefixed()
}
} else { } else {
certificateTypes := body.addU8LengthPrefixed() certificateTypes := body.addU8LengthPrefixed()
certificateTypes.addBytes(m.certificateTypes) certificateTypes.addBytes(m.certificateTypes)
}
if m.hasSignatureAlgorithm { if m.hasSignatureAlgorithm {
signatureAlgorithms := body.addU16LengthPrefixed() signatureAlgorithms := body.addU16LengthPrefixed()
@ -1890,16 +2008,65 @@ func (m *certificateRequestMsg) marshal() []byte {
caEntry := certificateAuthorities.addU16LengthPrefixed() caEntry := certificateAuthorities.addU16LengthPrefixed()
caEntry.addBytes(ca) caEntry.addBytes(ca)
} }
if m.hasRequestContext {
// Emit no certificate extensions.
body.addU16(0)
} }
m.raw = builder.finish() m.raw = builder.finish()
return m.raw return m.raw
} }
func parseSignatureAlgorithms(data []byte) ([]signatureAlgorithm, []byte, bool) {
if len(data) < 2 {
return nil, nil, false
}
sigAlgsLen := int(data[0])<<8 | int(data[1])
data = data[2:]
if sigAlgsLen&1 != 0 {
return nil, nil, false
}
if len(data) < int(sigAlgsLen) {
return nil, nil, false
}
numSigAlgs := sigAlgsLen / 2
signatureAlgorithms := make([]signatureAlgorithm, numSigAlgs)
for i := range signatureAlgorithms {
signatureAlgorithms[i] = signatureAlgorithm(data[0])<<8 | signatureAlgorithm(data[1])
data = data[2:]
}
return signatureAlgorithms, data, true
}
func parseCAs(data []byte) ([][]byte, []byte, bool) {
if len(data) < 2 {
return nil, nil, false
}
casLength := uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
if len(data) < int(casLength) {
return nil, nil, false
}
cas := data[:casLength]
data = data[casLength:]
var certificateAuthorities [][]byte
for len(cas) > 0 {
if len(cas) < 2 {
return nil, nil, false
}
caLen := uint16(cas[0])<<8 | uint16(cas[1])
cas = cas[2:]
if len(cas) < int(caLen) {
return nil, nil, false
}
certificateAuthorities = append(certificateAuthorities, cas[:caLen])
cas = cas[caLen:]
}
return certificateAuthorities, data, true
}
func (m *certificateRequestMsg) unmarshal(data []byte) bool { func (m *certificateRequestMsg) unmarshal(data []byte) bool {
m.raw = data m.raw = data
@ -1916,65 +2083,60 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool {
m.requestContext = make([]byte, contextLen) m.requestContext = make([]byte, contextLen)
copy(m.requestContext, data[1:]) copy(m.requestContext, data[1:])
data = data[1+contextLen:] data = data[1+contextLen:]
if isDraft21(m.vers) {
if len(data) < 2 {
return false
}
extensionsLen := int(data[0])<<8 | int(data[1])
if len(data) < 2+extensionsLen {
return false
}
extensions := data[2 : 2+extensionsLen]
data = data[2+extensionsLen:]
for len(extensions) != 0 {
if len(extensions) < 4 {
return false
}
extension := uint16(extensions[0])<<8 | uint16(extensions[1])
length := int(extensions[2])<<8 | int(extensions[3])
if len(extensions) < 4+length {
return false
}
contents := extensions[4 : 4+length]
extensions = extensions[4+length:]
switch extension {
case extensionSignatureAlgorithms:
sigAlgs, rest, ok := parseSignatureAlgorithms(contents)
if !ok || len(rest) != 0 {
return false
}
m.signatureAlgorithms = sigAlgs
case extensionCertificateAuthorities:
cas, rest, ok := parseCAs(contents)
if !ok || len(rest) != 0 {
return false
}
m.hasCAExtension = true
m.certificateAuthorities = cas
}
}
} else { } else {
numCertTypes := int(data[0])
if len(data) < 1+numCertTypes {
return false
}
m.certificateTypes = make([]byte, numCertTypes)
copy(m.certificateTypes, data[1:])
data = data[1+numCertTypes:]
}
if m.hasSignatureAlgorithm { if m.hasSignatureAlgorithm {
if len(data) < 2 { sigAlgs, rest, ok := parseSignatureAlgorithms(data)
if !ok {
return false return false
} }
sigAlgsLen := uint16(data[0])<<8 | uint16(data[1]) m.signatureAlgorithms = sigAlgs
data = data[2:] data = rest
if sigAlgsLen&1 != 0 {
return false
}
if len(data) < int(sigAlgsLen) {
return false
}
numSigAlgs := sigAlgsLen / 2
m.signatureAlgorithms = make([]signatureAlgorithm, numSigAlgs)
for i := range m.signatureAlgorithms {
m.signatureAlgorithms[i] = signatureAlgorithm(data[0])<<8 | signatureAlgorithm(data[1])
data = data[2:]
}
} }
if len(data) < 2 { cas, rest, ok := parseCAs(data)
if !ok {
return false return false
} }
casLength := uint16(data[0])<<8 | uint16(data[1]) m.certificateAuthorities = cas
data = data[2:] data = rest
if len(data) < int(casLength) {
return false
}
cas := make([]byte, casLength)
copy(cas, data)
data = data[casLength:]
m.certificateAuthorities = nil
for len(cas) > 0 {
if len(cas) < 2 {
return false
}
caLen := uint16(cas[0])<<8 | uint16(cas[1])
cas = cas[2:]
if len(cas) < int(caLen) {
return false
}
m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
cas = cas[caLen:]
}
if m.hasRequestContext {
// Ignore certificate extensions. // Ignore certificate extensions.
if len(data) < 2 { if len(data) < 2 {
return false return false
@ -1985,6 +2147,31 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool {
} }
data = data[2+extsLength:] data = data[2+extsLength:]
} }
} else {
numCertTypes := int(data[0])
if len(data) < 1+numCertTypes {
return false
}
m.certificateTypes = make([]byte, numCertTypes)
copy(m.certificateTypes, data[1:])
data = data[1+numCertTypes:]
if m.hasSignatureAlgorithm {
sigAlgs, rest, ok := parseSignatureAlgorithms(data)
if !ok {
return false
}
m.signatureAlgorithms = sigAlgs
data = rest
}
cas, rest, ok := parseCAs(data)
if !ok {
return false
}
m.certificateAuthorities = cas
data = rest
}
if len(data) > 0 { if len(data) > 0 {
return false return false
@ -2065,13 +2252,15 @@ func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
type newSessionTicketMsg struct { type newSessionTicketMsg struct {
raw []byte raw []byte
version uint16 vers uint16
isDTLS bool
ticketLifetime uint32 ticketLifetime uint32
ticketAgeAdd uint32 ticketAgeAdd uint32
ticketNonce []byte
ticket []byte ticket []byte
maxEarlyDataSize uint32 maxEarlyDataSize uint32
customExtension string customExtension string
duplicateEarlyDataInfo bool duplicateEarlyDataExtension bool
hasGREASEExtension bool hasGREASEExtension bool
} }
@ -2080,25 +2269,37 @@ func (m *newSessionTicketMsg) marshal() []byte {
return m.raw return m.raw
} }
version, ok := wireToVersion(m.vers, m.isDTLS)
if !ok {
panic("unknown version")
}
// See http://tools.ietf.org/html/rfc5077#section-3.3 // See http://tools.ietf.org/html/rfc5077#section-3.3
ticketMsg := newByteBuilder() ticketMsg := newByteBuilder()
ticketMsg.addU8(typeNewSessionTicket) ticketMsg.addU8(typeNewSessionTicket)
body := ticketMsg.addU24LengthPrefixed() body := ticketMsg.addU24LengthPrefixed()
body.addU32(m.ticketLifetime) body.addU32(m.ticketLifetime)
if m.version >= VersionTLS13 { if version >= VersionTLS13 {
body.addU32(m.ticketAgeAdd) body.addU32(m.ticketAgeAdd)
if isDraft21(m.vers) {
body.addU8LengthPrefixed().addBytes(m.ticketNonce)
}
} }
ticket := body.addU16LengthPrefixed() ticket := body.addU16LengthPrefixed()
ticket.addBytes(m.ticket) ticket.addBytes(m.ticket)
if m.version >= VersionTLS13 { if version >= VersionTLS13 {
extensions := body.addU16LengthPrefixed() extensions := body.addU16LengthPrefixed()
if m.maxEarlyDataSize > 0 { if m.maxEarlyDataSize > 0 {
extensions.addU16(extensionTicketEarlyDataInfo) extID := extensionTicketEarlyDataInfo
if isDraft21(m.vers) {
extID = extensionEarlyData
}
extensions.addU16(extID)
extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize) extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
if m.duplicateEarlyDataInfo { if m.duplicateEarlyDataExtension {
extensions.addU16(extensionTicketEarlyDataInfo) extensions.addU16(extID)
extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize) extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
} }
} }
@ -2115,18 +2316,32 @@ func (m *newSessionTicketMsg) marshal() []byte {
func (m *newSessionTicketMsg) unmarshal(data []byte) bool { func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
m.raw = data m.raw = data
version, ok := wireToVersion(m.vers, m.isDTLS)
if !ok {
panic("unknown version")
}
if len(data) < 8 { if len(data) < 8 {
return false return false
} }
m.ticketLifetime = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) m.ticketLifetime = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
data = data[8:] data = data[8:]
if m.version >= VersionTLS13 { if version >= VersionTLS13 {
if len(data) < 4 { if len(data) < 4 {
return false return false
} }
m.ticketAgeAdd = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) m.ticketAgeAdd = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
data = data[4:] data = data[4:]
if isDraft21(m.vers) {
nonceLen := int(data[0])
data = data[1:]
if len(data) < nonceLen {
return false
}
m.ticketNonce = data[:nonceLen]
data = data[nonceLen:]
}
} }
if len(data) < 2 { if len(data) < 2 {
@ -2138,14 +2353,14 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
return false return false
} }
if m.version >= VersionTLS13 && ticketLen == 0 { if version >= VersionTLS13 && ticketLen == 0 {
return false return false
} }
m.ticket = data[:ticketLen] m.ticket = data[:ticketLen]
data = data[ticketLen:] data = data[ticketLen:]
if m.version >= VersionTLS13 { if version >= VersionTLS13 {
if len(data) < 2 { if len(data) < 2 {
return false return false
} }
@ -2156,6 +2371,11 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
return false return false
} }
extID := extensionTicketEarlyDataInfo
if isDraft21(m.vers) {
extID = extensionEarlyData
}
for len(data) != 0 { for len(data) != 0 {
if len(data) < 4 { if len(data) < 4 {
return false return false
@ -2168,7 +2388,7 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
} }
switch extension { switch extension {
case extensionTicketEarlyDataInfo: case extID:
if length != 4 { if length != 4 {
return false return false
} }
@ -2355,6 +2575,21 @@ func (m *keyUpdateMsg) unmarshal(data []byte) bool {
return m.keyUpdateRequest == keyUpdateNotRequested || m.keyUpdateRequest == keyUpdateRequested return m.keyUpdateRequest == keyUpdateNotRequested || m.keyUpdateRequest == keyUpdateRequested
} }
type endOfEarlyDataMsg struct {
nonEmpty bool
}
func (m *endOfEarlyDataMsg) marshal() []byte {
if m.nonEmpty {
return []byte{typeEndOfEarlyData, 0, 0, 1, 42}
}
return []byte{typeEndOfEarlyData, 0, 0, 0}
}
func (*endOfEarlyDataMsg) unmarshal(data []byte) bool {
return len(data) == 4
}
// ssl3NoCertificateMsg is a dummy message to handle SSL 3.0 using a warning // ssl3NoCertificateMsg is a dummy message to handle SSL 3.0 using a warning
// alert in the handshake. // alert in the handshake.
type ssl3NoCertificateMsg struct{} type ssl3NoCertificateMsg struct{}

View File

@ -80,7 +80,7 @@ func (c *Conn) serverHandshake() error {
return err return err
} }
} }
if err := hs.sendFinished(c.firstFinished[:]); err != nil { if err := hs.sendFinished(c.firstFinished[:], isResume); err != nil {
return err return err
} }
// Most retransmits are triggered by a timeout, but the final // Most retransmits are triggered by a timeout, but the final
@ -120,7 +120,7 @@ func (c *Conn) serverHandshake() error {
if err := hs.sendSessionTicket(); err != nil { if err := hs.sendSessionTicket(); err != nil {
return err return err
} }
if err := hs.sendFinished(nil); err != nil { if err := hs.sendFinished(nil, isResume); err != nil {
return err return err
} }
} }
@ -281,7 +281,7 @@ func (hs *serverHandshakeState) readClientHello() error {
} }
if config.Bugs.ExpectNoTLS12Session { 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") return fmt.Errorf("tls: client offered an unexpected session ID")
} }
if len(hs.clientHello.sessionTicket) > 0 { if len(hs.clientHello.sessionTicket) > 0 {
@ -358,6 +358,12 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
c := hs.c c := hs.c
config := c.config config := c.config
// We've read the ClientHello, so the next record in draft 22 must be
// preceded with ChangeCipherSpec.
if isDraft22(c.wireVersion) {
c.expectTLS13ChangeCipherSpec = true
}
hs.hello = &serverHelloMsg{ hs.hello = &serverHelloMsg{
isDTLS: c.isDTLS, isDTLS: c.isDTLS,
vers: c.wireVersion, vers: c.wireVersion,
@ -412,7 +418,7 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite
} }
hs.finishedHash = newFinishedHash(c.vers, hs.suite) hs.finishedHash = newFinishedHash(c.wireVersion, c.isDTLS, hs.suite)
hs.finishedHash.discardHandshakeBuffer() hs.finishedHash.discardHandshakeBuffer()
hs.writeClientHash(hs.clientHello.marshal()) hs.writeClientHash(hs.clientHello.marshal())
@ -496,7 +502,7 @@ Curves:
// AcceptAnyBinder is set. See https://crbug.com/boringssl/115. // AcceptAnyBinder is set. See https://crbug.com/boringssl/115.
if hs.sessionState != nil && !config.Bugs.AcceptAnySession { if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
binderToVerify := hs.clientHello.pskBinders[pskIndex] binderToVerify := hs.clientHello.pskBinders[pskIndex]
if err := verifyPSKBinder(hs.clientHello, hs.sessionState, binderToVerify, []byte{}); err != nil { if err := verifyPSKBinder(c.wireVersion, hs.clientHello, hs.sessionState, binderToVerify, []byte{}, []byte{}); err != nil {
return err return err
} }
} }
@ -520,8 +526,14 @@ Curves:
ResendHelloRetryRequest: ResendHelloRetryRequest:
var sendHelloRetryRequest bool var sendHelloRetryRequest bool
cipherSuite := hs.suite.id
if config.Bugs.SendHelloRetryRequestCipherSuite != 0 {
cipherSuite = config.Bugs.SendHelloRetryRequestCipherSuite
}
helloRetryRequest := &helloRetryRequestMsg{ helloRetryRequest := &helloRetryRequestMsg{
vers: c.wireVersion, vers: c.wireVersion,
sessionId: hs.clientHello.sessionId,
cipherSuite: cipherSuite,
duplicateExtensions: config.Bugs.DuplicateHelloRetryRequestExtensions, duplicateExtensions: config.Bugs.DuplicateHelloRetryRequestExtensions,
} }
@ -571,15 +583,21 @@ ResendHelloRetryRequest:
} }
if sendHelloRetryRequest { if sendHelloRetryRequest {
if isDraft21(c.wireVersion) {
if err := hs.finishedHash.UpdateForHelloRetryRequest(); err != nil {
return err
}
}
oldClientHelloBytes := hs.clientHello.marshal() oldClientHelloBytes := hs.clientHello.marshal()
hs.writeServerHash(helloRetryRequest.marshal()) hs.writeServerHash(helloRetryRequest.marshal())
if c.vers == tls13RecordTypeExperimentVersion {
c.writeRecord(recordTypePlaintextHandshake, helloRetryRequest.marshal())
} else {
c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal()) c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
}
c.flushHandshake() c.flushHandshake()
if !c.config.Bugs.SkipChangeCipherSpec && isDraft22(c.wireVersion) {
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
}
if hs.clientHello.hasEarlyData { if hs.clientHello.hasEarlyData {
c.skipEarlyData = true c.skipEarlyData = true
} }
@ -596,6 +614,10 @@ ResendHelloRetryRequest:
} }
hs.writeClientHash(newClientHello.marshal()) hs.writeClientHash(newClientHello.marshal())
if config.Bugs.ExpectNoTLS13PSKAfterHRR && len(newClientHello.pskIdentities) > 0 {
return fmt.Errorf("tls: client offered unexpected PSK identities after HelloRetryRequest")
}
if newClientHello.hasEarlyData { if newClientHello.hasEarlyData {
return errors.New("tls: EarlyData sent in new ClientHello") return errors.New("tls: EarlyData sent in new ClientHello")
} }
@ -630,12 +652,16 @@ ResendHelloRetryRequest:
// PSK binders and obfuscated ticket age are both updated in the // PSK binders and obfuscated ticket age are both updated in the
// second ClientHello. // second ClientHello.
if isDraft21(c.wireVersion) && len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
newClientHelloCopy.pskIdentities = oldClientHelloCopy.pskIdentities
} else {
if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) { if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
return errors.New("tls: PSK identity count from old and new ClientHello do not match") return errors.New("tls: PSK identity count from old and new ClientHello do not match")
} }
for i, identity := range oldClientHelloCopy.pskIdentities { for i, identity := range oldClientHelloCopy.pskIdentities {
newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge
} }
}
newClientHelloCopy.pskBinders = oldClientHelloCopy.pskBinders newClientHelloCopy.pskBinders = oldClientHelloCopy.pskBinders
newClientHelloCopy.hasEarlyData = oldClientHelloCopy.hasEarlyData newClientHelloCopy.hasEarlyData = oldClientHelloCopy.hasEarlyData
@ -652,8 +678,7 @@ ResendHelloRetryRequest:
// AcceptAnyBinder is set. See https://crbug.com/115. // AcceptAnyBinder is set. See https://crbug.com/115.
if hs.sessionState != nil && !config.Bugs.AcceptAnySession { if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
binderToVerify := newClientHello.pskBinders[pskIndex] binderToVerify := newClientHello.pskBinders[pskIndex]
err := verifyPSKBinder(newClientHello, hs.sessionState, binderToVerify, append(oldClientHelloBytes, helloRetryRequest.marshal()...)) if err := verifyPSKBinder(c.wireVersion, newClientHello, hs.sessionState, binderToVerify, oldClientHelloBytes, helloRetryRequest.marshal()); err != nil {
if err != nil {
return err return err
} }
} }
@ -667,8 +692,15 @@ ResendHelloRetryRequest:
} }
} }
if encryptedExtensions.extensions.hasEarlyData { if encryptedExtensions.extensions.hasEarlyData {
earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyTrafficLabel) earlyLabel := earlyTrafficLabel
c.in.useTrafficSecret(c.vers, hs.suite, earlyTrafficSecret, clientWrite) if isDraft21(c.wireVersion) {
earlyLabel = earlyTrafficLabelDraft21
}
earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyLabel)
if err := c.useInTrafficSecret(c.wireVersion, hs.suite, earlyTrafficSecret); err != nil {
return err
}
for _, expectedMsg := range config.Bugs.ExpectEarlyData { for _, expectedMsg := range config.Bugs.ExpectEarlyData {
if err := c.readRecord(recordTypeApplicationData); err != nil { if err := c.readRecord(recordTypeApplicationData); err != nil {
@ -719,6 +751,7 @@ ResendHelloRetryRequest:
c.sendAlert(alertHandshakeFailure) c.sendAlert(alertHandshakeFailure)
return err return err
} }
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(ecdheSecret) hs.finishedHash.addEntropy(ecdheSecret)
hs.hello.hasKeyShare = true hs.hello.hasKeyShare = true
@ -743,6 +776,7 @@ ResendHelloRetryRequest:
} }
} }
} else { } else {
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret()) hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret())
} }
@ -754,24 +788,31 @@ ResendHelloRetryRequest:
toWrite = append(toWrite, helloBytes...) toWrite = append(toWrite, helloBytes...)
toWrite = append(toWrite, typeEncryptedExtensions) toWrite = append(toWrite, typeEncryptedExtensions)
c.writeRecord(recordTypeHandshake, toWrite) c.writeRecord(recordTypeHandshake, toWrite)
} else {
if c.vers == tls13RecordTypeExperimentVersion {
c.writeRecord(recordTypePlaintextHandshake, hs.hello.marshal())
} else { } else {
c.writeRecord(recordTypeHandshake, hs.hello.marshal()) c.writeRecord(recordTypeHandshake, hs.hello.marshal())
} }
}
c.flushHandshake() c.flushHandshake()
if c.wireVersion == tls13ExperimentVersion { if !c.config.Bugs.SkipChangeCipherSpec && isResumptionExperiment(c.wireVersion) && !sendHelloRetryRequest {
c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
} }
for i := 0; i < c.config.Bugs.SendExtraChangeCipherSpec; i++ {
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
}
clientLabel := clientHandshakeTrafficLabel
serverLabel := serverHandshakeTrafficLabel
if isDraft21(c.wireVersion) {
clientLabel = clientHandshakeTrafficLabelDraft21
serverLabel = serverHandshakeTrafficLabelDraft21
}
// Switch to handshake traffic keys. // Switch to handshake traffic keys.
serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite) c.useOutTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret)
// Derive handshake traffic read key, but don't switch yet. // Derive handshake traffic read key, but don't switch yet.
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
// Send EncryptedExtensions. // Send EncryptedExtensions.
hs.writeServerHash(encryptedExtensions.marshal()) hs.writeServerHash(encryptedExtensions.marshal())
@ -786,9 +827,11 @@ ResendHelloRetryRequest:
if config.ClientAuth >= RequestClientCert { if config.ClientAuth >= RequestClientCert {
// Request a client certificate // Request a client certificate
certReq := &certificateRequestMsg{ certReq := &certificateRequestMsg{
hasSignatureAlgorithm: true, vers: c.wireVersion,
hasSignatureAlgorithm: !config.Bugs.OmitCertificateRequestAlgorithms,
hasRequestContext: true, hasRequestContext: true,
requestContext: config.Bugs.SendRequestContext, requestContext: config.Bugs.SendRequestContext,
customExtension: config.Bugs.SendCustomCertificateRequest,
} }
if !config.Bugs.NoSignatureAlgorithms { if !config.Bugs.NoSignatureAlgorithms {
certReq.signatureAlgorithms = config.verifySignatureAlgorithms() certReq.signatureAlgorithms = config.verifySignatureAlgorithms()
@ -903,14 +946,25 @@ ResendHelloRetryRequest:
// The various secrets do not incorporate the client's final leg, so // The various secrets do not incorporate the client's final leg, so
// derive them now before updating the handshake context. // derive them now before updating the handshake context.
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret()) hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret())
clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel)
serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel) clientLabel = clientApplicationTrafficLabel
c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel) serverLabel = serverApplicationTrafficLabel
exportLabel := exporterLabel
if isDraft21(c.wireVersion) {
clientLabel = clientApplicationTrafficLabelDraft21
serverLabel = serverApplicationTrafficLabelDraft21
exportLabel = exporterLabelDraft21
}
clientTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
serverTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
c.exporterSecret = hs.finishedHash.deriveSecret(exportLabel)
// Switch to application data keys on write. In particular, any alerts // Switch to application data keys on write. In particular, any alerts
// from the client certificate are sent over these keys. // from the client certificate are sent over these keys.
c.out.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite) c.useOutTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret)
// Send 0.5-RTT messages. // Send 0.5-RTT messages.
for _, halfRTTMsg := range config.Bugs.SendHalfRTTData { for _, halfRTTMsg := range config.Bugs.SendHalfRTTData {
@ -919,8 +973,21 @@ ResendHelloRetryRequest:
} }
} }
// Read end_of_early_data alert. // Read end_of_early_data.
if encryptedExtensions.extensions.hasEarlyData { if encryptedExtensions.extensions.hasEarlyData {
if isDraft21(c.wireVersion) {
msg, err := c.readHandshake()
if err != nil {
return err
}
endOfEarlyData, ok := msg.(*endOfEarlyDataMsg)
if !ok {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(endOfEarlyData, msg)
}
hs.writeClientHash(endOfEarlyData.marshal())
} else {
if err := c.readRecord(recordTypeAlert); err != errEndOfEarlyDataAlert { if err := c.readRecord(recordTypeAlert); err != errEndOfEarlyDataAlert {
if err == nil { if err == nil {
panic("readRecord(recordTypeAlert) returned nil") panic("readRecord(recordTypeAlert) returned nil")
@ -928,15 +995,17 @@ ResendHelloRetryRequest:
return err return err
} }
} }
if c.wireVersion == tls13ExperimentVersion && !c.skipEarlyData {
if err := c.readRecord(recordTypeChangeCipherSpec); err != nil {
return err
} }
if isResumptionClientCCSExperiment(c.wireVersion) && !isDraft22(c.wireVersion) && !hs.clientHello.hasEarlyData {
// Early versions of the middlebox hacks inserted
// ChangeCipherSpec differently on 0-RTT and 2-RTT handshakes.
c.expectTLS13ChangeCipherSpec = true
} }
// Switch input stream to handshake traffic keys. // Switch input stream to handshake traffic keys.
c.in.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite) if err := c.useInTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret); err != nil {
return err
}
// If we requested a client certificate, then the client must send a // If we requested a client certificate, then the client must send a
// certificate message, even if it's empty. // certificate message, even if it's empty.
@ -1040,17 +1109,25 @@ ResendHelloRetryRequest:
hs.writeClientHash(clientFinished.marshal()) hs.writeClientHash(clientFinished.marshal())
// Switch to application data keys on read. // Switch to application data keys on read.
c.in.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite) if err := c.useInTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret); err != nil {
return err
}
c.cipherSuite = hs.suite c.cipherSuite = hs.suite
c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel)
resumeLabel := resumptionLabel
if isDraft21(c.wireVersion) {
resumeLabel = resumptionLabelDraft21
}
c.resumptionSecret = hs.finishedHash.deriveSecret(resumeLabel)
// TODO(davidben): Allow configuring the number of tickets sent for // TODO(davidben): Allow configuring the number of tickets sent for
// testing. // testing.
if !c.config.SessionTicketsDisabled && foundKEMode { if !c.config.SessionTicketsDisabled && foundKEMode {
ticketCount := 2 ticketCount := 2
for i := 0; i < ticketCount; i++ { for i := 0; i < ticketCount; i++ {
c.SendNewSessionTicket() c.SendNewSessionTicket([]byte{byte(i)})
} }
} }
return nil return nil
@ -1089,9 +1166,6 @@ func (hs *serverHandshakeState) processClientHello() (isResume bool, err error)
copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12) copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12)
} }
if len(hs.clientHello.sessionId) > 0 && c.config.Bugs.ExpectEmptyClientHelloSessionID {
return false, errors.New("tls: expected empty session ID from client")
}
if len(hs.clientHello.sessionId) == 0 && c.config.Bugs.ExpectClientHelloSessionID { if len(hs.clientHello.sessionId) == 0 && c.config.Bugs.ExpectClientHelloSessionID {
return false, errors.New("tls: expected non-empty session ID from client") return false, errors.New("tls: expected non-empty session ID from client")
} }
@ -1308,6 +1382,10 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server
serverExtensions.supportedPoints = c.config.Bugs.SendSupportedPointFormats serverExtensions.supportedPoints = c.config.Bugs.SendSupportedPointFormats
} }
if c.config.Bugs.SendServerSupportedCurves {
serverExtensions.supportedCurves = c.config.curvePreferences()
}
if !hs.clientHello.hasGREASEExtension && config.Bugs.ExpectGREASE { if !hs.clientHello.hasGREASEExtension && config.Bugs.ExpectGREASE {
return errors.New("tls: no GREASE extension found") return errors.New("tls: no GREASE extension found")
} }
@ -1410,7 +1488,7 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
hs.hello.extensions.ocspStapling = true hs.hello.extensions.ocspStapling = true
} }
hs.finishedHash = newFinishedHash(c.vers, hs.suite) hs.finishedHash = newFinishedHash(c.wireVersion, c.isDTLS, hs.suite)
hs.finishedHash.discardHandshakeBuffer() hs.finishedHash.discardHandshakeBuffer()
hs.writeClientHash(hs.clientHello.marshal()) hs.writeClientHash(hs.clientHello.marshal())
hs.writeServerHash(hs.hello.marshal()) hs.writeServerHash(hs.hello.marshal())
@ -1462,7 +1540,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
} }
} }
hs.finishedHash = newFinishedHash(c.vers, hs.suite) hs.finishedHash = newFinishedHash(c.wireVersion, c.isDTLS, hs.suite)
hs.writeClientHash(hs.clientHello.marshal()) hs.writeClientHash(hs.clientHello.marshal())
hs.writeServerHash(hs.hello.marshal()) hs.writeServerHash(hs.hello.marshal())
@ -1516,6 +1594,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if config.ClientAuth >= RequestClientCert { if config.ClientAuth >= RequestClientCert {
// Request a client certificate // Request a client certificate
certReq := &certificateRequestMsg{ certReq := &certificateRequestMsg{
vers: c.wireVersion,
certificateTypes: config.ClientCertificateTypes, certificateTypes: config.ClientCertificateTypes,
} }
if certReq.certificateTypes == nil { if certReq.certificateTypes == nil {
@ -1697,8 +1776,8 @@ func (hs *serverHandshakeState) establishKeys() error {
serverCipher = hs.suite.aead(c.vers, serverKey, serverIV) serverCipher = hs.suite.aead(c.vers, serverKey, serverIV)
} }
c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) c.in.prepareCipherSpec(c.wireVersion, clientCipher, clientHash)
c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) c.out.prepareCipherSpec(c.wireVersion, serverCipher, serverHash)
return nil return nil
} }
@ -1789,6 +1868,8 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
} }
m := new(newSessionTicketMsg) m := new(newSessionTicketMsg)
m.vers = c.wireVersion
m.isDTLS = c.isDTLS
if c.config.Bugs.SendTicketLifetime != 0 { if c.config.Bugs.SendTicketLifetime != 0 {
m.ticketLifetime = uint32(c.config.Bugs.SendTicketLifetime / time.Second) m.ticketLifetime = uint32(c.config.Bugs.SendTicketLifetime / time.Second)
} }
@ -1807,7 +1888,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
return nil return nil
} }
func (hs *serverHandshakeState) sendFinished(out []byte) error { func (hs *serverHandshakeState) sendFinished(out []byte, isResume bool) error {
c := hs.c c := hs.c
finished := new(finishedMsg) finished := new(finishedMsg)
@ -1852,8 +1933,8 @@ func (hs *serverHandshakeState) sendFinished(out []byte) error {
} }
} }
if !c.config.Bugs.PackHelloRequestWithFinished { if isResume || (!c.config.Bugs.PackHelloRequestWithFinished && !c.config.Bugs.PackAppDataWithHandshake) {
// Defer flushing until renegotiation. // Defer flushing until Renegotiate() or Write().
c.flushHandshake() c.flushHandshake()
} }
@ -1935,7 +2016,7 @@ func verifyChannelIDMessage(channelIDMsg *channelIDMsg, channelIDHash []byte) (*
if !elliptic.P256().IsOnCurve(x, y) { if !elliptic.P256().IsOnCurve(x, y) {
return nil, errors.New("tls: invalid channel ID public key") return nil, errors.New("tls: invalid channel ID public key")
} }
channelID := &ecdsa.PublicKey{elliptic.P256(), x, y} channelID := &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}
if !ecdsa.Verify(channelID, channelIDHash, r, s) { if !ecdsa.Verify(channelID, channelIDHash, r, s) {
return nil, errors.New("tls: invalid channel ID signature") return nil, errors.New("tls: invalid channel ID signature")
} }
@ -2002,9 +2083,6 @@ func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version
if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 { if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
continue continue
} }
if c.isDTLS && candidate.flags&suiteNoDTLS != 0 {
continue
}
return candidate return candidate
} }
} }
@ -2027,7 +2105,7 @@ func isGREASEValue(val uint16) bool {
return val&0x0f0f == 0x0a0a && val&0xff == val>>8 return val&0x0f0f == 0x0a0a && val&0xff == val>>8
} }
func verifyPSKBinder(clientHello *clientHelloMsg, sessionState *sessionState, binderToVerify, transcript []byte) error { func verifyPSKBinder(version uint16, clientHello *clientHelloMsg, sessionState *sessionState, binderToVerify, firstClientHello, helloRetryRequest []byte) error {
binderLen := 2 binderLen := 2
for _, binder := range clientHello.pskBinders { for _, binder := range clientHello.pskBinders {
binderLen += 1 + len(binder) binderLen += 1 + len(binder)
@ -2040,7 +2118,11 @@ func verifyPSKBinder(clientHello *clientHelloMsg, sessionState *sessionState, bi
return errors.New("tls: Unknown cipher suite for PSK in session") return errors.New("tls: Unknown cipher suite for PSK in session")
} }
binder := computePSKBinder(sessionState.masterSecret, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello) binderLabel := resumptionPSKBinderLabel
if isDraft21(version) {
binderLabel = resumptionPSKBinderLabelDraft21
}
binder := computePSKBinder(sessionState.masterSecret, version, binderLabel, pskCipherSuite, firstClientHello, helloRetryRequest, truncatedHello)
if !bytes.Equal(binder, binderToVerify) { if !bytes.Equal(binder, binderToVerify) {
return errors.New("tls: PSK binder does not verify") return errors.New("tls: PSK binder does not verify")
} }

View File

@ -136,12 +136,47 @@ func (ka *rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello
return errors.New("tls: unexpected ServerKeyExchange") return errors.New("tls: unexpected ServerKeyExchange")
} }
func rsaSize(pub *rsa.PublicKey) int {
return (pub.N.BitLen() + 7) / 8
}
func rsaRawEncrypt(pub *rsa.PublicKey, msg []byte) ([]byte, error) {
k := rsaSize(pub)
if len(msg) != k {
return nil, errors.New("tls: bad padded RSA input")
}
m := new(big.Int).SetBytes(msg)
e := big.NewInt(int64(pub.E))
m.Exp(m, e, pub.N)
unpadded := m.Bytes()
ret := make([]byte, k)
copy(ret[len(ret)-len(unpadded):], unpadded)
return ret, nil
}
// nonZeroRandomBytes fills the given slice with non-zero random octets.
func nonZeroRandomBytes(s []byte, rand io.Reader) {
if _, err := io.ReadFull(rand, s); err != nil {
panic(err)
}
for i := range s {
for s[i] == 0 {
if _, err := io.ReadFull(rand, s[i:i+1]); err != nil {
panic(err)
}
}
}
}
func (ka *rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { func (ka *rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
bad := config.Bugs.BadRSAClientKeyExchange bad := config.Bugs.BadRSAClientKeyExchange
preMasterSecret := make([]byte, 48) preMasterSecret := make([]byte, 48)
vers := clientHello.vers vers := clientHello.vers
if bad == RSABadValueWrongVersion { if bad == RSABadValueWrongVersion1 {
vers ^= 1 vers ^= 1
} else if bad == RSABadValueWrongVersion2 {
vers ^= 0x100
} }
preMasterSecret[0] = byte(vers >> 8) preMasterSecret[0] = byte(vers >> 8)
preMasterSecret[1] = byte(vers) preMasterSecret[1] = byte(vers)
@ -152,13 +187,31 @@ func (ka *rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello
sentPreMasterSecret := preMasterSecret sentPreMasterSecret := preMasterSecret
if bad == RSABadValueTooLong { if bad == RSABadValueTooLong {
sentPreMasterSecret = make([]byte, len(sentPreMasterSecret)+1) sentPreMasterSecret = make([]byte, 1, len(sentPreMasterSecret)+1)
copy(sentPreMasterSecret, preMasterSecret) sentPreMasterSecret = append(sentPreMasterSecret, preMasterSecret...)
} else if bad == RSABadValueTooShort { } else if bad == RSABadValueTooShort {
sentPreMasterSecret = sentPreMasterSecret[:len(sentPreMasterSecret)-1] sentPreMasterSecret = sentPreMasterSecret[:len(sentPreMasterSecret)-1]
} }
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), sentPreMasterSecret) // Pad for PKCS#1 v1.5.
padded := make([]byte, rsaSize(cert.PublicKey.(*rsa.PublicKey)))
padded[1] = 2
nonZeroRandomBytes(padded[2:len(padded)-len(sentPreMasterSecret)-1], config.rand())
copy(padded[len(padded)-len(sentPreMasterSecret):], sentPreMasterSecret)
if bad == RSABadValueWrongBlockType {
padded[1] = 3
} else if bad == RSABadValueWrongLeadingByte {
padded[0] = 1
} else if bad == RSABadValueNoZero {
for i := 2; i < len(padded); i++ {
if padded[i] == 0 {
padded[i]++
}
}
}
encrypted, err := rsaRawEncrypt(cert.PublicKey.(*rsa.PublicKey), padded)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View File

@ -180,9 +180,14 @@ func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clie
return return
} }
func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash { func newFinishedHash(wireVersion uint16, isDTLS bool, cipherSuite *cipherSuite) finishedHash {
var ret finishedHash var ret finishedHash
version, ok := wireToVersion(wireVersion, isDTLS)
if !ok {
panic("unknown version")
}
if version >= VersionTLS12 { if version >= VersionTLS12 {
ret.hash = cipherSuite.hash() ret.hash = cipherSuite.hash()
@ -207,6 +212,7 @@ func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
ret.buffer = []byte{} ret.buffer = []byte{}
ret.version = version ret.version = version
ret.wireVersion = wireVersion
return ret return ret
} }
@ -227,12 +233,27 @@ type finishedHash struct {
buffer []byte buffer []byte
version uint16 version uint16
wireVersion uint16
prf func(result, secret, label, seed []byte) prf func(result, secret, label, seed []byte)
// secret, in TLS 1.3, is the running input secret. // secret, in TLS 1.3, is the running input secret.
secret []byte secret []byte
} }
func (h *finishedHash) UpdateForHelloRetryRequest() (err error) {
data := newByteBuilder()
data.addU8(typeMessageHash)
data.addU24(h.hash.Size())
data.addBytes(h.Sum())
h.client = h.hash.New()
h.server = h.hash.New()
if h.buffer != nil {
h.buffer = []byte{}
}
h.Write(data.finish())
return nil
}
func (h *finishedHash) Write(msg []byte) (n int, err error) { func (h *finishedHash) Write(msg []byte) (n int, err error) {
h.client.Write(msg) h.client.Write(msg)
h.server.Write(msg) h.server.Write(msg)
@ -307,7 +328,7 @@ func (h finishedHash) clientSum(baseKey []byte) []byte {
return out return out
} }
clientFinishedKey := hkdfExpandLabel(h.hash, baseKey, finishedLabel, nil, h.hash.Size()) clientFinishedKey := hkdfExpandLabel(h.hash, h.wireVersion, baseKey, finishedLabel, nil, h.hash.Size())
finishedHMAC := hmac.New(h.hash.New, clientFinishedKey) finishedHMAC := hmac.New(h.hash.New, clientFinishedKey)
finishedHMAC.Write(h.appendContextHashes(nil)) finishedHMAC.Write(h.appendContextHashes(nil))
return finishedHMAC.Sum(nil) return finishedHMAC.Sum(nil)
@ -326,7 +347,7 @@ func (h finishedHash) serverSum(baseKey []byte) []byte {
return out return out
} }
serverFinishedKey := hkdfExpandLabel(h.hash, baseKey, finishedLabel, nil, h.hash.Size()) serverFinishedKey := hkdfExpandLabel(h.hash, h.wireVersion, baseKey, finishedLabel, nil, h.hash.Size())
finishedHMAC := hmac.New(h.hash.New, serverFinishedKey) finishedHMAC := hmac.New(h.hash.New, serverFinishedKey)
finishedHMAC.Write(h.appendContextHashes(nil)) finishedHMAC.Write(h.appendContextHashes(nil))
return finishedHMAC.Sum(nil) return finishedHMAC.Sum(nil)
@ -374,20 +395,33 @@ func (h *finishedHash) addEntropy(ikm []byte) {
h.secret = hkdfExtract(h.hash.New, h.secret, ikm) h.secret = hkdfExtract(h.hash.New, h.secret, ikm)
} }
func (h *finishedHash) nextSecret() {
if isDraft21(h.wireVersion) {
derivedLabel := []byte("derived")
h.secret = hkdfExpandLabel(h.hash, h.wireVersion, h.secret, derivedLabel, h.hash.New().Sum(nil), h.hash.Size())
}
}
// hkdfExpandLabel implements TLS 1.3's HKDF-Expand-Label function, as defined // hkdfExpandLabel implements TLS 1.3's HKDF-Expand-Label function, as defined
// in section 7.1 of draft-ietf-tls-tls13-16. // in section 7.1 of draft-ietf-tls-tls13-16.
func hkdfExpandLabel(hash crypto.Hash, secret, label, hashValue []byte, length int) []byte { func hkdfExpandLabel(hash crypto.Hash, version uint16, secret, label, hashValue []byte, length int) []byte {
if len(label) > 255 || len(hashValue) > 255 { if len(label) > 255 || len(hashValue) > 255 {
panic("hkdfExpandLabel: label or hashValue too long") panic("hkdfExpandLabel: label or hashValue too long")
} }
hkdfLabel := make([]byte, 3+9+len(label)+1+len(hashValue))
versionLabel := []byte("TLS 1.3, ")
if isDraft21(version) {
versionLabel = []byte("tls13 ")
}
hkdfLabel := make([]byte, 3+len(versionLabel)+len(label)+1+len(hashValue))
x := hkdfLabel x := hkdfLabel
x[0] = byte(length >> 8) x[0] = byte(length >> 8)
x[1] = byte(length) x[1] = byte(length)
x[2] = byte(9 + len(label)) x[2] = byte(len(versionLabel) + len(label))
x = x[3:] x = x[3:]
copy(x, []byte("TLS 1.3, ")) copy(x, versionLabel)
x = x[9:] x = x[len(versionLabel):]
copy(x, label) copy(x, label)
x = x[len(label):] x = x[len(label):]
x[0] = byte(len(hashValue)) x[0] = byte(len(hashValue))
@ -414,12 +448,25 @@ var (
applicationTrafficLabel = []byte("application traffic secret") applicationTrafficLabel = []byte("application traffic secret")
exporterLabel = []byte("exporter master secret") exporterLabel = []byte("exporter master secret")
resumptionLabel = []byte("resumption master secret") resumptionLabel = []byte("resumption master secret")
externalPSKBinderLabelDraft21 = []byte("ext binder")
resumptionPSKBinderLabelDraft21 = []byte("res binder")
earlyTrafficLabelDraft21 = []byte("c e traffic")
clientHandshakeTrafficLabelDraft21 = []byte("c hs traffic")
serverHandshakeTrafficLabelDraft21 = []byte("s hs traffic")
clientApplicationTrafficLabelDraft21 = []byte("c ap traffic")
serverApplicationTrafficLabelDraft21 = []byte("s ap traffic")
applicationTrafficLabelDraft21 = []byte("traffic upd")
exporterLabelDraft21 = []byte("exp master")
resumptionLabelDraft21 = []byte("res master")
resumptionPSKLabel = []byte("resumption")
) )
// deriveSecret implements TLS 1.3's Derive-Secret function, as defined in // deriveSecret implements TLS 1.3's Derive-Secret function, as defined in
// section 7.1 of draft ietf-tls-tls13-16. // section 7.1 of draft ietf-tls-tls13-16.
func (h *finishedHash) deriveSecret(label []byte) []byte { func (h *finishedHash) deriveSecret(label []byte) []byte {
return hkdfExpandLabel(h.hash, h.secret, label, h.appendContextHashes(nil), h.hash.Size()) return hkdfExpandLabel(h.hash, h.wireVersion, h.secret, label, h.appendContextHashes(nil), h.hash.Size())
} }
// The following are context strings for CertificateVerify in TLS 1.3. // The following are context strings for CertificateVerify in TLS 1.3.
@ -458,21 +505,34 @@ var (
// deriveTrafficAEAD derives traffic keys and constructs an AEAD given a traffic // deriveTrafficAEAD derives traffic keys and constructs an AEAD given a traffic
// secret. // secret.
func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) interface{} { func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) interface{} {
key := hkdfExpandLabel(suite.hash(), secret, keyTLS13, nil, suite.keyLen) key := hkdfExpandLabel(suite.hash(), version, secret, keyTLS13, nil, suite.keyLen)
iv := hkdfExpandLabel(suite.hash(), secret, ivTLS13, nil, suite.ivLen(version)) iv := hkdfExpandLabel(suite.hash(), version, secret, ivTLS13, nil, suite.ivLen(version))
return suite.aead(version, key, iv) return suite.aead(version, key, iv)
} }
func updateTrafficSecret(hash crypto.Hash, secret []byte) []byte { func updateTrafficSecret(hash crypto.Hash, version uint16, secret []byte) []byte {
return hkdfExpandLabel(hash, secret, applicationTrafficLabel, nil, hash.Size()) trafficLabel := applicationTrafficLabel
if isDraft21(version) {
trafficLabel = applicationTrafficLabelDraft21
}
return hkdfExpandLabel(hash, version, secret, trafficLabel, nil, hash.Size())
} }
func computePSKBinder(psk, label []byte, cipherSuite *cipherSuite, transcript, truncatedHello []byte) []byte { func computePSKBinder(psk []byte, version uint16, label []byte, cipherSuite *cipherSuite, clientHello, helloRetryRequest, truncatedHello []byte) []byte {
finishedHash := newFinishedHash(VersionTLS13, cipherSuite) finishedHash := newFinishedHash(version, false, cipherSuite)
finishedHash.addEntropy(psk) finishedHash.addEntropy(psk)
binderKey := finishedHash.deriveSecret(label) binderKey := finishedHash.deriveSecret(label)
finishedHash.Write(transcript) finishedHash.Write(clientHello)
if isDraft21(version) && len(helloRetryRequest) != 0 {
finishedHash.UpdateForHelloRetryRequest()
}
finishedHash.Write(helloRetryRequest)
finishedHash.Write(truncatedHello) finishedHash.Write(truncatedHello)
return finishedHash.clientSum(binderKey) return finishedHash.clientSum(binderKey)
} }
func deriveSessionPSK(suite *cipherSuite, version uint16, masterSecret []byte, nonce []byte) []byte {
hash := suite.hash()
return hkdfExpandLabel(hash, version, masterSecret, resumptionPSKLabel, nonce, hash.Size())
}

View File

@ -112,6 +112,10 @@ func (r *recordingConn) Transcript() []byte {
if flow.flowType != writeFlow { if flow.flowType != writeFlow {
continue continue
} }
if r.isDatagram {
// Prepend a length prefix to preserve packet boundaries.
ret = append(ret, byte(len(flow.data)>>16), byte(len(flow.data)>>8), byte(len(flow.data)))
}
ret = append(ret, flow.data...) ret = append(ret, flow.data...)
} }
return ret return ret

File diff suppressed because it is too large Load Diff

View File

@ -81,7 +81,8 @@ const Flag<bool> kBoolFlags[] = {
{ "-tls-unique", &TestConfig::tls_unique }, { "-tls-unique", &TestConfig::tls_unique },
{ "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal }, { "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal },
{ "-expect-no-session", &TestConfig::expect_no_session }, { "-expect-no-session", &TestConfig::expect_no_session },
{ "-expect-early-data-info", &TestConfig::expect_early_data_info }, { "-expect-ticket-supports-early-data",
&TestConfig::expect_ticket_supports_early_data },
{ "-use-ticket-callback", &TestConfig::use_ticket_callback }, { "-use-ticket-callback", &TestConfig::use_ticket_callback },
{ "-renew-ticket", &TestConfig::renew_ticket }, { "-renew-ticket", &TestConfig::renew_ticket },
{ "-enable-early-data", &TestConfig::enable_early_data }, { "-enable-early-data", &TestConfig::enable_early_data },
@ -121,6 +122,7 @@ const Flag<bool> kBoolFlags[] = {
{ "-expect-no-session-id", &TestConfig::expect_no_session_id }, { "-expect-no-session-id", &TestConfig::expect_no_session_id },
{ "-expect-accept-early-data", &TestConfig::expect_accept_early_data }, { "-expect-accept-early-data", &TestConfig::expect_accept_early_data },
{ "-expect-reject-early-data", &TestConfig::expect_reject_early_data }, { "-expect-reject-early-data", &TestConfig::expect_reject_early_data },
{ "-expect-no-offer-early-data", &TestConfig::expect_no_offer_early_data },
{ "-no-op-extra-handshake", &TestConfig::no_op_extra_handshake }, { "-no-op-extra-handshake", &TestConfig::no_op_extra_handshake },
{ "-handshake-twice", &TestConfig::handshake_twice }, { "-handshake-twice", &TestConfig::handshake_twice },
{ "-allow-unknown-alpn-protos", &TestConfig::allow_unknown_alpn_protos }, { "-allow-unknown-alpn-protos", &TestConfig::allow_unknown_alpn_protos },
@ -130,7 +132,6 @@ const Flag<bool> kBoolFlags[] = {
const Flag<std::string> kStringFlags[] = { const Flag<std::string> kStringFlags[] = {
{ "-write-settings", &TestConfig::write_settings }, { "-write-settings", &TestConfig::write_settings },
{ "-digest-prefs", &TestConfig::digest_prefs },
{ "-key-file", &TestConfig::key_file }, { "-key-file", &TestConfig::key_file },
{ "-cert-file", &TestConfig::cert_file }, { "-cert-file", &TestConfig::cert_file },
{ "-expect-server-name", &TestConfig::expected_server_name }, { "-expect-server-name", &TestConfig::expected_server_name },

View File

@ -26,7 +26,6 @@ struct TestConfig {
int resume_count = 0; int resume_count = 0;
std::string write_settings; std::string write_settings;
bool fallback_scsv = false; bool fallback_scsv = false;
std::string digest_prefs;
std::vector<int> signing_prefs; std::vector<int> signing_prefs;
std::vector<int> verify_prefs; std::vector<int> verify_prefs;
std::string key_file; std::string key_file;
@ -87,9 +86,10 @@ struct TestConfig {
bool tls_unique = false; bool tls_unique = false;
bool expect_ticket_renewal = false; bool expect_ticket_renewal = false;
bool expect_no_session = false; bool expect_no_session = false;
bool expect_early_data_info = false; bool expect_ticket_supports_early_data = false;
bool expect_accept_early_data = false; bool expect_accept_early_data = false;
bool expect_reject_early_data = false; bool expect_reject_early_data = false;
bool expect_no_offer_early_data = false;
bool use_ticket_callback = false; bool use_ticket_callback = false;
bool renew_ticket = false; bool renew_ticket = false;
bool enable_early_data = false; bool enable_early_data = false;

2
vendor/manifest vendored
View File

@ -5,7 +5,7 @@
"importpath": "github.com/google/boringssl/ssl/test", "importpath": "github.com/google/boringssl/ssl/test",
"repository": "https://github.com/google/boringssl", "repository": "https://github.com/google/boringssl",
"vcs": "git", "vcs": "git",
"revision": "74795b32c60104939f4c410a47e22b3027e98d06", "revision": "855d5046c7899f19e2fad6ac83504a40cd92c6cc",
"branch": "master", "branch": "master",
"path": "/ssl/test", "path": "/ssl/test",
"notests": true, "notests": true,