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
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
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
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# 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/x509.h>
#include <functional>
#include <memory>
#include <string>
#include <vector>
@ -63,7 +64,7 @@ OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
#include "../../crypto/internal.h"
#include "../internal.h"
#include "async_bio.h"
#include "fuzzer.h"
#include "fuzzer_tags.h"
#include "packeted_bio.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 = {
nullptr /* type */,
nullptr /* max_signature_len */,
AsyncPrivateKeySign,
nullptr /* sign_digest */,
AsyncPrivateKeyDecrypt,
AsyncPrivateKeyComplete,
};
@ -452,27 +450,6 @@ static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
bssl::UniquePtr<EVP_PKEY> *out_pkey) {
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()) {
std::vector<uint16_t> u16s(config->signing_prefs.begin(),
config->signing_prefs.end());
@ -854,7 +831,7 @@ static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) {
*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) {
TestState *async_state = GetTestState(ssl);
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
// error.
static int Connect(uint16_t port) {
time_t start_time = time(nullptr);
for (int af : { AF_INET6, AF_INET }) {
int sock = socket(af, SOCK_STREAM, 0);
if (sock == -1) {
@ -1147,11 +1123,6 @@ static int Connect(uint16_t port) {
}
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;
}
@ -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 == "<NULL>") {
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 {
bssl::UniquePtr<STACK_OF(X509_NAME)> names =
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
// the result value of the final |SSL_read| call.
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.
AsyncBioEnforceWriteQuota(test_state->async_bio, false);
}
ret = config->peek_then_read ? SSL_peek(ssl, out, max_out)
: SSL_read(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);
});
if (config->async) {
AsyncBioEnforceWriteQuota(test_state->async_bio, true);
}
@ -2163,13 +2165,21 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, SSL *ssl,
int ret;
if (!config->implicit_handshake) {
do {
ret = SSL_do_handshake(ssl);
ret = CheckIdempotentError("SSL_do_handshake", ssl, [&]() -> int {
return SSL_do_handshake(ssl);
});
} while (config->async && RetryAsync(ssl, ret));
if (ret != 1 ||
!CheckHandshakeProperties(ssl, is_resume, config)) {
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) {
do {
ret = SSL_do_handshake(ssl);
@ -2365,14 +2375,13 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, SSL *ssl,
}
if (expect_new_session) {
bool got_early_data_info =
bool got_early_data =
GetTestState(ssl)->new_session->ticket_max_early_data != 0;
if (config->expect_early_data_info != got_early_data_info) {
fprintf(
stderr,
"new session did%s include ticket_early_data_info, but we expected "
"the opposite\n",
got_early_data_info ? "" : " not");
if (config->expect_ticket_supports_early_data != got_early_data) {
fprintf(stderr,
"new session did%s support early data, but we expected the "
"opposite\n",
got_early_data ? "" : " not");
return false;
}
}
@ -2407,6 +2416,11 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, SSL *ssl,
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
// values should remain unchanged even if the server sent different SCT
// lists.

View File

@ -15,104 +15,46 @@
#ifndef 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/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include "./fuzzer_tags.h"
// SSL fuzzer utilities.
//
// The TLS client and server fuzzers coordinate with bssl_shim on a common
// format to encode configuration parameters in a fuzzer file. To add a new
// configuration, define a tag, update |SetupTest| below to parse it, and
// update |WriteSettings| in bssl_shim to serialize it. Finally, record
// transcripts from a test run, and use the BORINGSSL_FUZZER_DEBUG environment
// variable to confirm the transcripts are compatible.
namespace {
// kDataTag denotes that the remainder of the input should be passed to the TLS
// stack.
static const uint16_t kDataTag = 0;
const uint8_t kP256KeyPKCS8[] = {
0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
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
// resume.
static const uint16_t kSessionTag = 1;
const uint8_t kOCSPResponse[] = {0x01, 0x02, 0x03, 0x04};
// kRequestClientCert denotes that the server should request client
// certificates.
static const uint16_t kRequestClientCert = 2;
const uint8_t kSCT[] = {0x00, 0x06, 0x00, 0x04, 0x05, 0x06, 0x07, 0x08};
// kTLS13Variant is followed by a u8 denoting the TLS 1.3 variant to configure.
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[] = {
const uint8_t kCertificateDER[] = {
0x30, 0x82, 0x02, 0xff, 0x30, 0x82, 0x01, 0xe7, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x11, 0x00, 0xb1, 0x84, 0xee, 0x34, 0x99, 0x98, 0x76, 0xfb,
0x6f, 0xb2, 0x15, 0xc8, 0x47, 0x79, 0x05, 0x9b, 0x30, 0x0d, 0x06, 0x09,
@ -180,7 +122,7 @@ static const uint8_t kCertificateDER[] = {
0x76, 0x8a, 0xbb,
};
static const uint8_t kRSAPrivateKeyDER[] = {
const uint8_t kRSAPrivateKeyDER[] = {
0x30, 0x82, 0x04, 0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xce, 0x47, 0xcb, 0x11, 0xbb, 0xd2, 0x9d, 0x8e, 0x9e, 0xd2, 0x1e, 0x14,
0xaf, 0xc7, 0xea, 0xb6, 0xc9, 0x38, 0x2a, 0x6f, 0xb3, 0x7e, 0xfb, 0xbc,
@ -283,5 +225,294 @@ static const uint8_t kRSAPrivateKeyDER[] = {
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

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/hmac"
"crypto/md5"
"crypto/rc4"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
@ -48,8 +47,6 @@ const (
// client indicates that it supports ECC with a curve and point format
// that we're happy with.
suiteECDHE = 1 << iota
// suiteDHE indicates that the cipher suite involves Diffie-Hellman.
suiteDHE
// suiteECDSA indicates that the cipher suite involves an ECDSA
// signature and therefore may only be selected when the server's
// 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
// handshake hash.
suiteSHA384
// suiteNoDTLS indicates that the cipher suite cannot be used
// in DTLS.
suiteNoDTLS
// suitePSK indicates that the cipher suite authenticates with
// a pre-shared key rather than a server private key.
suitePSK
@ -101,8 +95,6 @@ func (cs cipherSuite) hash() crypto.Hash {
}
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_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},
@ -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_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_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_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},
@ -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_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_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_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},
@ -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_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_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_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 {
@ -170,11 +157,6 @@ func cipherNull(key, iv []byte, isRead bool) interface{} {
return nullCipher{}
}
func cipherRC4(key, iv []byte, isRead bool) interface{} {
cipher, _ := rc4.NewCipher(key)
return cipher
}
func cipher3DES(key, iv []byte, isRead bool) interface{} {
block, _ := des.NewTripleDESCipher(key)
if isRead {
@ -450,22 +432,17 @@ func cipherSuiteFromID(id uint16) *cipherSuite {
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
const (
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_AES_128_CBC_SHA uint16 = 0x002f
TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
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_256_CBC_SHA uint16 = 0x008d
TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
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_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_AES_128_CBC_SHA uint16 = 0xc013
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014

View File

@ -33,22 +33,30 @@ const (
// A draft version of TLS 1.3 that is sent over the wire for the current draft.
const (
tls13DraftVersion = 0x7f12
tls13ExperimentVersion = 0x7e01
tls13RecordTypeExperimentVersion = 0x7a12
tls13DraftVersion = 0x7f12
tls13Draft21Version = 0x7f15
tls13ExperimentVersion = 0x7e01
tls13Experiment2Version = 0x7e02
tls13Experiment3Version = 0x7e03
tls13Draft22Version = 0x7e04
)
const (
TLS13Default = 0
TLS13Experiment = 1
TLS13RecordTypeExperiment = 2
TLS13NoSessionIDExperiment = 3
TLS13Default = 0
TLS13Experiment = 1
TLS13Experiment2 = 2
TLS13Experiment3 = 3
TLS13Draft21 = 4
TLS13Draft22 = 5
)
var allTLSWireVersions = []uint16{
tls13DraftVersion,
tls13Draft22Version,
tls13Draft21Version,
tls13Experiment3Version,
tls13Experiment2Version,
tls13ExperimentVersion,
tls13RecordTypeExperimentVersion,
VersionTLS12,
VersionTLS11,
VersionTLS10,
@ -89,6 +97,7 @@ const (
typeServerHello uint8 = 2
typeHelloVerifyRequest uint8 = 3
typeNewSessionTicket uint8 = 4
typeEndOfEarlyData uint8 = 5 // draft-ietf-tls-tls13-21
typeHelloRetryRequest uint8 = 6 // draft-ietf-tls-tls13-16
typeEncryptedExtensions uint8 = 8 // draft-ietf-tls-tls13-16
typeCertificate uint8 = 11
@ -102,6 +111,7 @@ const (
typeKeyUpdate uint8 = 24 // draft-ietf-tls-tls13-16
typeNextProtocol uint8 = 67 // Not IANA assigned
typeChannelID uint8 = 203 // Not IANA assigned
typeMessageHash uint8 = 254 // draft-ietf-tls-tls13-21
)
// TLS compression types.
@ -119,6 +129,7 @@ const (
extensionUseSRTP uint16 = 14
extensionALPN uint16 = 16
extensionSignedCertificateTimestamp uint16 = 18
extensionPadding uint16 = 21
extensionExtendedMasterSecret uint16 = 23
extensionSessionTicket uint16 = 35
extensionKeyShare uint16 = 40 // draft-ietf-tls-tls13-16
@ -128,6 +139,7 @@ const (
extensionCookie uint16 = 44 // draft-ietf-tls-tls13-16
extensionPSKKeyExchangeModes uint16 = 45 // 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
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
@ -139,6 +151,12 @@ const (
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
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
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.
sessionTicket []uint8 // Encrypted ticket used for session resumption with server
vers uint16 // SSL/TLS version negotiated for the session
wireVersion uint16 // Wire SSL/TLS version negotiated for the session
cipherSuite uint16 // Ciphersuite negotiated for the session
masterSecret []byte // MasterSecret generated by client on a full handshake
handshakeHash []byte // Handshake hash for Channel ID purposes.
@ -452,8 +471,7 @@ type Config struct {
// MaxEarlyDataSize controls the maximum number of bytes that the
// server will accept in early data and advertise in a
// NewSessionTicketMsg. If 0, no early data will be accepted and
// the TicketEarlyDataInfo extension in the NewSessionTicketMsg
// will be omitted.
// the early_data extension in the NewSessionTicketMsg will be omitted.
MaxEarlyDataSize uint32
// SRTPProtectionProfiles, if not nil, is the list of SRTP
@ -493,7 +511,11 @@ const (
RSABadValueCorrupt
RSABadValueTooLong
RSABadValueTooShort
RSABadValueWrongVersion
RSABadValueWrongVersion1
RSABadValueWrongVersion2
RSABadValueWrongBlockType
RSABadValueWrongLeadingByte
RSABadValueNoZero
NumRSABadValues
)
@ -556,6 +578,10 @@ type ProtocolBugs struct {
// NewSessionTicket message despite promising to in ServerHello.
SkipNewSessionTicket bool
// UseFirstSessionTicket causes the client to cache only the first session
// ticket received.
UseFirstSessionTicket bool
// SkipClientCertificate causes the client to skip the Certificate
// message.
SkipClientCertificate bool
@ -569,18 +595,22 @@ type ProtocolBugs struct {
// message.
SkipFinished bool
// SkipEndOfEarlyData causes the implementation to skip the
// end_of_early_data alert.
// SkipEndOfEarlyData causes the implementation to skip
// end_of_early_data.
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
// CertificateVerify message after the Certificate message.
SkipCertificateVerify bool
// EarlyChangeCipherSpec causes the client to send an early
// ChangeCipherSpec message before the ClientKeyExchange. A value of
// zero disables this behavior. One and two configure variants for 0.9.8
// and 1.0.1 modes, respectively.
// zero disables this behavior. One and two configure variants for
// 1.0.1 and 0.9.8 modes, respectively.
EarlyChangeCipherSpec int
// StrayChangeCipherSpec causes every pre-ChangeCipherSpec handshake
@ -598,6 +628,14 @@ type ProtocolBugs struct {
// messages.
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
// send unencrypted before ChangeCipherSpec rather than after it.
SendUnencryptedFinished bool
@ -735,10 +773,6 @@ type ProtocolBugs struct {
// connection if there is not a SessionID in the ClientHello.
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
// connection if either a session ID or TLS 1.2 ticket is offered.
ExpectNoTLS12Session bool
@ -747,6 +781,10 @@ type ProtocolBugs struct {
// if a TLS 1.3 PSK is offered.
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
// the extended master secret option.
RequireExtendedMasterSecret bool
@ -948,10 +986,22 @@ type ProtocolBugs struct {
// record size.
PackHandshakeFragments int
// PackHandshakeRecords, if true, causes handshake records in DTLS to be
// packed into individual packets, up to the specified packet size.
// PackHandshakeRecords, if non-zero, causes handshake and
// ChangeCipherSpec records in DTLS to be packed into individual
// packets, up to the specified packet size.
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
// be packed into records, up to the largest size record available.
PackHandshakeFlight bool
@ -1034,13 +1084,13 @@ type ProtocolBugs struct {
// receipt of a NewSessionTicket message.
ExpectNoNewSessionTicket bool
// DuplicateTicketEarlyDataInfo causes an extra empty extension of
// ticket_early_data_info to be sent in NewSessionTicket.
DuplicateTicketEarlyDataInfo bool
// DuplicateTicketEarlyData causes an extra empty extension of early_data to
// be sent in NewSessionTicket.
DuplicateTicketEarlyData bool
// ExpectTicketEarlyDataInfo, if true, means that the client will fail upon
// absence of the ticket_early_data_info extension.
ExpectTicketEarlyDataInfo bool
// ExpectTicketEarlyData, if true, means that the client will fail upon
// absence of the early_data extension.
ExpectTicketEarlyData bool
// ExpectTicketAge, if non-zero, is the expected age of the ticket that the
// server receives from the client.
@ -1288,6 +1338,10 @@ type ProtocolBugs struct {
// the specified curve in a HelloRetryRequest.
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
// sent by the server in HelloRetryRequest.
SendHelloRetryRequestCookie []byte
@ -1325,6 +1379,14 @@ type ProtocolBugs struct {
// a TLS 1.3 CertificateRequest.
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
// unrecognized_name alert before the ServerHello.
SendSNIWarningAlert bool
@ -1386,6 +1448,12 @@ type ProtocolBugs struct {
// empty slice, no extension will be sent.
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
// length accepted from the peer.
MaxReceivePlaintext int
@ -1406,6 +1474,10 @@ type ProtocolBugs struct {
// renegotiation handshakes.
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
// to use when signing in TLS 1.1 and earlier where algorithms are not
// negotiated.
@ -1434,6 +1506,10 @@ type ProtocolBugs struct {
// ExpectRecordSplitting, if true, causes application records to only be
// accepted if they follow a 1/n-1 record split.
ExpectRecordSplitting bool
// PadClientHello, if non-zero, pads the ClientHello to a multiple of
// that many bytes.
PadClientHello int
}
func (c *Config) serverInit() {
@ -1534,12 +1610,59 @@ func (c *Config) defaultCurves() map[CurveID]bool {
return defaultCurves
}
func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) {
if isDTLS {
switch vers {
case VersionDTLS12:
return VersionTLS12, true
case VersionDTLS10:
return VersionTLS10, true
}
} else {
switch vers {
case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
return vers, true
case tls13DraftVersion, 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,
// it returns true and the corresponding protocol version. Otherwise, it returns
// false.
func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) {
if (c.TLS13Variant != TLS13Experiment && c.TLS13Variant != TLS13NoSessionIDExperiment && wireVers == tls13ExperimentVersion) ||
(c.TLS13Variant != TLS13RecordTypeExperiment && wireVers == tls13RecordTypeExperimentVersion) ||
if (c.TLS13Variant != TLS13Experiment && wireVers == tls13ExperimentVersion) ||
(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) {
return 0, false
}

View File

@ -96,10 +96,13 @@ type Conn struct {
handMsg []byte // pending assembled handshake message
handMsgLen int // handshake message length, not including the header
pendingFragments [][]byte // pending outgoing handshake fragments.
pendingPacket []byte // pending outgoing packet.
keyUpdateRequested bool
seenOneByteRecord bool
expectTLS13ChangeCipherSpec bool
tmp [16]byte
}
@ -151,14 +154,15 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
type halfConn struct {
sync.Mutex
err error // first permanent error
version uint16 // protocol version
isDTLS bool
cipher interface{} // cipher algorithm
mac macFunction
seq [8]byte // 64-bit sequence number
outSeq [8]byte // Mapped sequence number
bfree *block // list of free blocks
err error // first permanent error
version uint16 // protocol version
wireVersion uint16 // wire version
isDTLS bool
cipher interface{} // cipher algorithm
mac macFunction
seq [8]byte // 64-bit sequence number
outSeq [8]byte // Mapped sequence number
bfree *block // list of free blocks
nextCipher interface{} // next encryption state
nextMac macFunction // next MAC algorithm
@ -188,7 +192,12 @@ func (hc *halfConn) error() error {
// prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use.
func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
hc.version = version
hc.wireVersion = version
protocolVersion, ok := wireToVersion(version, hc.isDTLS)
if !ok {
panic("TLS: unknown version")
}
hc.version = protocolVersion
hc.nextCipher = cipher
hc.nextMac = mac
}
@ -215,7 +224,12 @@ func (hc *halfConn) changeCipherSpec(config *Config) error {
// useTrafficSecret sets the current cipher state for TLS 1.3.
func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) {
hc.version = version
hc.wireVersion = version
protocolVersion, ok := wireToVersion(version, hc.isDTLS)
if !ok {
panic("TLS: unknown version")
}
hc.version = protocolVersion
hc.cipher = deriveTrafficAEAD(version, suite, secret, side)
if hc.config.Bugs.NullAllCiphers {
hc.cipher = nullCipher{}
@ -232,14 +246,6 @@ func (hc *halfConn) resetCipher() {
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.
func (hc *halfConn) incSeq(isOutgoing bool) {
limit := 0
@ -725,6 +731,26 @@ func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
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) {
RestartReadRecord:
if c.isDTLS {
@ -763,11 +789,6 @@ RestartReadRecord:
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])
n := int(b.data[3])<<8 | int(b.data[4])
@ -781,6 +802,9 @@ RestartReadRecord:
if c.vers >= VersionTLS13 {
expect = VersionTLS10
}
if isResumptionRecordVersionExperiment(c.wireVersion) {
expect = VersionTLS12
}
} else {
expect = c.config.Bugs.ExpectInitialRecordVersion
}
@ -855,6 +879,47 @@ RestartReadRecord:
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
// and updates the record layer state.
// c.in.Mutex <= L; c.input == nil.
@ -875,6 +940,12 @@ func (c *Conn) readRecord(want recordType) error {
break
}
if c.expectTLS13ChangeCipherSpec {
if err := c.readTLS13ChangeCipherSpec(); err != nil {
return err
}
}
Again:
typ, b, err := c.doReadRecord(want)
if err != nil {
@ -929,11 +1000,12 @@ Again:
c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
break
}
if c.wireVersion != tls13ExperimentVersion {
err := c.in.changeCipherSpec(c.config)
if err != nil {
c.in.setErrorLocked(c.sendAlert(err.(alert)))
}
if c.hand.Len() != 0 {
c.in.setErrorLocked(errors.New("tls: buffered handshake messages on cipher change"))
break
}
if err := c.in.changeCipherSpec(c.config); err != nil {
c.in.setErrorLocked(c.sendAlert(err.(alert)))
}
case recordTypeApplicationData:
@ -1063,6 +1135,12 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
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)
}
@ -1125,6 +1203,10 @@ func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) {
// layer to {3, 1}.
vers = VersionTLS10
}
if isResumptionRecordVersionExperiment(c.wireVersion) || isResumptionRecordVersionExperiment(c.out.wireVersion) {
vers = VersionTLS12
}
if c.config.Bugs.SendRecordVersion != 0 {
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)
if typ == recordTypeChangeCipherSpec && c.wireVersion != tls13ExperimentVersion {
if typ == recordTypeChangeCipherSpec && !isResumptionExperiment(c.wireVersion) {
err = c.out.changeCipherSpec(c.config)
if err != nil {
return n, c.sendAlertLocked(alertLevelError, err.(alert))
@ -1244,7 +1326,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(helloRetryRequestMsg)
case typeNewSessionTicket:
m = &newSessionTicketMsg{
version: c.vers,
vers: c.wireVersion,
isDTLS: c.isDTLS,
}
case typeEncryptedExtensions:
m = new(encryptedExtensionsMsg)
@ -1254,6 +1337,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
}
case typeCertificateRequest:
m = &certificateRequestMsg{
vers: c.wireVersion,
hasSignatureAlgorithm: c.vers >= VersionTLS12,
hasRequestContext: c.vers >= VersionTLS13,
}
@ -1279,6 +1363,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
m = new(channelIDMsg)
case typeKeyUpdate:
m = new(keyUpdateMsg)
case typeEndOfEarlyData:
m = new(endOfEarlyDataMsg)
default:
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.
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) {
return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
@ -1386,10 +1480,6 @@ func (c *Conn) Write(b []byte) (int, error) {
c.out.Lock()
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 {
return 0, err
}
@ -1443,8 +1533,8 @@ func (c *Conn) processTLS13NewSessionTicket(newSessionTicket *newSessionTicketMs
return errors.New("tls: no GREASE ticket extension found")
}
if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.maxEarlyDataSize == 0 {
return errors.New("tls: no ticket_early_data_info extension found")
if c.config.Bugs.ExpectTicketEarlyData && newSessionTicket.maxEarlyDataSize == 0 {
return errors.New("tls: no early_data ticket extension found")
}
if c.config.Bugs.ExpectNoNewSessionTicket {
@ -1458,6 +1548,7 @@ func (c *Conn) processTLS13NewSessionTicket(newSessionTicket *newSessionTicketMs
session := &ClientSessionState{
sessionTicket: newSessionTicket.ticket,
vers: c.vers,
wireVersion: c.wireVersion,
cipherSuite: cipherSuite.id,
masterSecret: c.resumptionSecret,
serverCertificates: c.peerCertificates,
@ -1470,8 +1561,15 @@ func (c *Conn) processTLS13NewSessionTicket(newSessionTicket *newSessionTicketMs
earlyALPN: c.clientProtocol,
}
if isDraft21(c.wireVersion) {
session.masterSecret = deriveSessionPSK(cipherSuite, c.wireVersion, c.resumptionSecret, newSessionTicket.ticketNonce)
}
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
c.config.ClientSessionCache.Put(cacheKey, session)
_, ok := c.config.ClientSessionCache.Get(cacheKey)
if !ok || !c.config.Bugs.UseFirstSessionTicket {
c.config.ClientSessionCache.Put(cacheKey, session)
}
return nil
}
@ -1507,7 +1605,9 @@ func (c *Conn) handlePostHandshakeMessage() error {
if c.config.Bugs.RejectUnsolicitedKeyUpdate {
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 {
c.keyUpdateRequested = true
}
@ -1539,8 +1639,7 @@ func (c *Conn) ReadKeyUpdateACK() error {
return errors.New("tls: received invalid KeyUpdate message")
}
c.in.doKeyUpdate(c, false)
return nil
return c.useInTrafficSecret(c.in.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.wireVersion, c.in.trafficSecret))
}
func (c *Conn) Renegotiate() error {
@ -1758,9 +1857,16 @@ func (c *Conn) ExportKeyingMaterial(length int, label, context []byte, useContex
}
if c.vers >= VersionTLS13 {
// TODO(davidben): What should we do with useContext? See
// https://github.com/tlswg/tls13-spec/issues/546
return hkdfExpandLabel(c.cipherSuite.hash(), c.exporterSecret, label, context, length), nil
if isDraft21(c.wireVersion) {
hash := c.cipherSuite.hash()
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)
@ -1794,7 +1900,7 @@ func (c *Conn) noRenegotiationInfo() bool {
return false
}
func (c *Conn) SendNewSessionTicket() error {
func (c *Conn) SendNewSessionTicket(nonce []byte) error {
if c.isClient || c.vers < VersionTLS13 {
return errors.New("tls: cannot send post-handshake NewSessionTicket")
}
@ -1814,12 +1920,17 @@ func (c *Conn) SendNewSessionTicket() error {
// TODO(davidben): Allow configuring these values.
m := &newSessionTicketMsg{
version: c.vers,
ticketLifetime: uint32(24 * time.Hour / time.Second),
duplicateEarlyDataInfo: c.config.Bugs.DuplicateTicketEarlyDataInfo,
customExtension: c.config.Bugs.CustomTicketExtension,
ticketAgeAdd: ticketAgeAdd,
maxEarlyDataSize: c.config.MaxEarlyDataSize,
vers: c.wireVersion,
isDTLS: c.isDTLS,
ticketLifetime: uint32(24 * time.Hour / time.Second),
duplicateEarlyDataExtension: c.config.Bugs.DuplicateTicketEarlyData,
customExtension: c.config.Bugs.CustomTicketExtension,
ticketAgeAdd: ticketAgeAdd,
maxEarlyDataSize: c.config.MaxEarlyDataSize,
}
if isDraft21(c.wireVersion) {
m.ticketNonce = nonce
}
if c.config.Bugs.SendTicketLifetime != 0 {
@ -1837,6 +1948,10 @@ func (c *Conn) SendNewSessionTicket() error {
earlyALPN: []byte(c.clientProtocol),
}
if isDraft21(c.wireVersion) {
state.masterSecret = deriveSessionPSK(c.cipherSuite, c.wireVersion, c.resumptionSecret, nonce)
}
if !c.config.Bugs.SendEmptySessionTicket {
var err error
m.ticket, err = c.encryptTicket(&state)
@ -1870,7 +1985,7 @@ func (c *Conn) sendKeyUpdateLocked(keyUpdateRequest byte) error {
if err := c.flushHandshake(); err != nil {
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
}
@ -1881,6 +1996,10 @@ func (c *Conn) sendFakeEarlyData(len int) error {
payload[0] = byte(recordTypeApplicationData)
payload[1] = 3
payload[2] = 1
if isResumptionRecordVersionVariant(c.config.TLS13Variant) {
payload[1] = 3
payload[2] = 3
}
payload[3] = byte(len >> 8)
payload[4] = byte(len)
_, err := c.conn.Write(payload)

View File

@ -23,26 +23,6 @@ import (
"net"
)
func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) {
if isDTLS {
switch vers {
case VersionDTLS12:
return VersionTLS12, true
case VersionDTLS10:
return VersionTLS10, true
}
} else {
switch vers {
case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
return vers, true
case tls13DraftVersion, tls13ExperimentVersion, tls13RecordTypeExperimentVersion:
return VersionTLS13, true
}
}
return 0, false
}
func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) {
recordHeaderLen := dtlsRecordHeaderLen
@ -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) {
// Only handshake messages are fragmented.
if typ != recordTypeHandshake {
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 {
err = c.dtlsFlushHandshake()
err = c.dtlsPackHandshake()
if err != nil {
return
}
}
// Only handshake messages are fragmented.
n, err = c.dtlsWriteRawRecord(typ, data)
if err != nil {
return
if typ == recordTypeApplicationData && len(data) > 1 && c.config.Bugs.SplitAndPackAppData {
_, err = c.dtlsPackRecord(typ, data[:len(data)/2], false)
if err != nil {
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 {
err = c.dtlsFlushHandshake()
err = c.dtlsPackHandshake()
if err != nil {
return
}
@ -178,12 +170,19 @@ func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
if err != nil {
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
}
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 {
return
}
@ -209,8 +208,8 @@ func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
isFinished := header[0] == typeFinished
if c.config.Bugs.SendEmptyFragments {
fragment := c.makeFragment(header, data, 0, 0)
c.pendingFragments = append(c.pendingFragments, fragment)
c.pendingFragments = append(c.pendingFragments, c.makeFragment(header, data, 0, 0))
c.pendingFragments = append(c.pendingFragments, c.makeFragment(header, data, len(data), 0))
}
firstRun := true
@ -263,7 +262,9 @@ func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
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
// retain |c.pendingFragments| for a future retransmit.
var fragments [][]byte
@ -285,7 +286,6 @@ func (c *Conn) dtlsFlushHandshake() error {
}
maxRecordLen := c.config.Bugs.PackHandshakeFragments
maxPacketLen := c.config.Bugs.PackHandshakeRecords
// Pack handshake fragments into records.
var records [][]byte
@ -305,42 +305,39 @@ func (c *Conn) dtlsFlushHandshake() error {
}
}
// Format them into packets.
var packets [][]byte
// Send the records.
for _, record := range records {
b, err := c.dtlsSealRecord(recordTypeHandshake, record)
_, err := c.dtlsPackRecord(recordTypeHandshake, record, false)
if err != nil {
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
}
// dtlsSealRecord seals a record into a block from |c.out|'s pool.
func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error) {
func (c *Conn) dtlsFlushHandshake() 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
maxLen := c.config.Bugs.MaxHandshakeRecordLength
if maxLen <= 0 {
maxLen = 1024
}
b = c.out.newBlock()
b := c.out.newBlock()
explicitIVLen := 0
explicitIVIsSeq := false
@ -392,23 +389,30 @@ func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error)
}
copy(b.data[recordHeaderLen+explicitIVLen:], data)
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
}
func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) {
b, err := c.dtlsSealRecord(typ, data)
if err != nil {
return
func (c *Conn) dtlsFlushPacket() error {
if len(c.pendingPacket) == 0 {
return nil
}
_, err = c.conn.Write(b.data)
if err != nil {
return
}
n = len(data)
c.out.freeBlock(b)
return
_, err := c.conn.Write(c.pendingPacket)
c.pendingPacket = nil
return err
}
func (c *Conn) dtlsDoReadHandshake() ([]byte, error) {

View File

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

View File

@ -211,10 +211,6 @@ NextCipherSuite:
if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
continue
}
// Don't advertise non-DTLS cipher suites in DTLS.
if c.isDTLS && suite.flags&suiteNoDTLS != 0 {
continue
}
hello.cipherSuites = append(hello.cipherSuites, suiteId)
continue NextCipherSuite
}
@ -376,7 +372,14 @@ NextCipherSuite:
c.writeV2Record(helloBytes)
} else {
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()
@ -407,11 +410,23 @@ NextCipherSuite:
// Derive early write keys and set Conn state to allow early writes.
if sendEarlyData {
finishedHash := newFinishedHash(session.vers, pskCipherSuite)
finishedHash := newFinishedHash(session.wireVersion, c.isDTLS, pskCipherSuite)
finishedHash.addEntropy(session.masterSecret)
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 {
if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil {
return err
@ -470,9 +485,22 @@ NextCipherSuite:
c.vers = serverVersion
c.haveVers = true
if isDraft22(c.wireVersion) {
// The first server message must be followed by a ChangeCipherSpec.
c.expectTLS13ChangeCipherSpec = true
}
helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg)
var secondHelloBytes []byte
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()
if len(helloRetryRequest.cookie) > 0 {
hello.tls13Cookie = helloRetryRequest.cookie
@ -518,7 +546,7 @@ NextCipherSuite:
hello.raw = nil
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()
@ -588,13 +616,19 @@ NextCipherSuite:
serverHello: serverHello,
hello: hello,
suite: suite,
finishedHash: newFinishedHash(c.vers, suite),
finishedHash: newFinishedHash(c.wireVersion, c.isDTLS, suite),
keyShares: keyShares,
session: session,
}
hs.writeHash(helloBytes, hs.c.sendHandshakeSeq-1)
if haveHelloRetryRequest {
if isDraft21(c.wireVersion) {
err = hs.finishedHash.UpdateForHelloRetryRequest()
if err != nil {
return err
}
}
hs.writeServerHash(helloRetryRequest.marshal())
hs.writeClientHash(secondHelloBytes)
}
@ -690,7 +724,13 @@ NextCipherSuite:
func (hs *clientHandshakeState) doTLS13Handshake() error {
c := hs.c
if c.wireVersion == tls13ExperimentVersion && !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) {
if isResumptionExperiment(c.wireVersion) && !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.")
}
@ -739,22 +779,27 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
if err != nil {
return err
}
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(ecdheSecret)
} else {
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(zeroSecret)
}
if c.wireVersion == tls13ExperimentVersion {
if err := c.readRecord(recordTypeChangeCipherSpec); err != nil {
return err
}
clientLabel := clientHandshakeTrafficLabel
serverLabel := serverHandshakeTrafficLabel
if isDraft21(c.wireVersion) {
clientLabel = clientHandshakeTrafficLabelDraft21
serverLabel = serverHandshakeTrafficLabelDraft21
}
// Derive handshake traffic keys and switch read key to handshake
// traffic key.
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel)
c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite)
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
if err := c.useInTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret); err != nil {
return err
}
msg, err := c.readHandshake()
if err != nil {
@ -793,6 +838,10 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
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 {
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
// derive them now before updating the handshake context.
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(zeroSecret)
clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel)
serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel)
c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel)
clientLabel = clientApplicationTrafficLabel
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
// 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
// now.
// If we're expecting 0.5-RTT messages from the server, read them now.
var deferredTickets []*newSessionTicketMsg
if encryptedExtensions.extensions.hasEarlyData {
// BoringSSL will always send two tickets half-RTT when
// negotiating 0-RTT.
@ -904,9 +966,8 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
if !ok {
return errors.New("tls: expected half-RTT ticket")
}
if err := c.processTLS13NewSessionTicket(newSessionTicket, hs.suite); err != nil {
return err
}
// Defer processing until the resumption secret is computed.
deferredTickets = append(deferredTickets, newSessionTicket)
}
for _, expectedMsg := range c.config.Bugs.ExpectHalfRTTData {
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
// 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 {
helloRequest := new(helloRequestMsg)
c.writeRecord(recordTypeHandshake, helloRequest.marshal())
}
c.sendAlert(alertEndOfEarlyData)
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)
}
}
if c.wireVersion == tls13ExperimentVersion {
if !c.config.Bugs.SkipChangeCipherSpec && isResumptionClientCCSExperiment(c.wireVersion) && !hs.hello.hasEarlyData {
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 {
certMsg := &certificateMsg{
@ -1020,9 +1092,20 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
c.flushHandshake()
// 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
}
@ -1287,8 +1370,8 @@ func (hs *clientHandshakeState) establishKeys() error {
serverCipher = hs.suite.aead(c.vers, serverKey, serverIV)
}
c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
c.in.prepareCipherSpec(c.wireVersion, serverCipher, serverHash)
c.out.prepareCipherSpec(c.wireVersion, clientCipher, clientHash)
return nil
}
@ -1498,6 +1581,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
// session ID or session ticket will be attached.
session := &ClientSessionState{
vers: c.vers,
wireVersion: c.wireVersion,
cipherSuite: hs.suite.id,
masterSecret: hs.masterSecret,
handshakeHash: hs.finishedHash.Sum(),
@ -1622,7 +1706,9 @@ func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
}
}
c.flushHandshake()
if !isResume || !c.config.Bugs.PackAppDataWithHandshake {
c.flushHandshake()
}
return nil
}
@ -1729,7 +1815,7 @@ func writeIntPadded(b []byte, x *big.Int) {
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 {
return
}
@ -1755,7 +1841,11 @@ func generatePSKBinders(hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk,
helloBytes := hello.marshal()
binderSize := len(hello.pskBinders)*(binderLen+1) + 2
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 {
binder = binder[:binderLen]
}

View File

@ -175,6 +175,7 @@ type clientHelloMsg struct {
pskBinderFirst bool
omitExtensions bool
emptyExtensions bool
pad int
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@ -222,7 +223,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.hasGREASEExtension == m1.hasGREASEExtension &&
m.pskBinderFirst == m1.pskBinderFirst &&
m.omitExtensions == m1.omitExtensions &&
m.emptyExtensions == m1.emptyExtensions
m.emptyExtensions == m1.emptyExtensions &&
m.pad == m1.pad
}
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 {
// Silently erase any extensions which were sent.
hello.discardChild()
@ -463,6 +475,10 @@ func (m *clientHelloMsg) marshal() []byte {
}
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
}
@ -865,19 +881,19 @@ func (m *serverHelloMsg) marshal() []byte {
}
if m.versOverride != 0 {
hello.addU16(m.versOverride)
} else if m.vers == tls13ExperimentVersion {
} else if isResumptionExperiment(m.vers) {
hello.addU16(VersionTLS12)
} else {
hello.addU16(m.vers)
}
hello.addBytes(m.random)
if vers < VersionTLS13 || m.vers == tls13ExperimentVersion {
if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
sessionId := hello.addU8LengthPrefixed()
sessionId.addBytes(m.sessionId)
}
hello.addU16(m.cipherSuite)
if vers < VersionTLS13 || m.vers == tls13ExperimentVersion {
if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
hello.addU8(m.compressionMethod)
}
@ -896,7 +912,7 @@ func (m *serverHelloMsg) marshal() []byte {
extensions.addU16(2) // Length
extensions.addU16(m.pskIdentity)
}
if m.vers == tls13ExperimentVersion || m.supportedVersOverride != 0 {
if isResumptionExperiment(m.vers) || m.supportedVersOverride != 0 {
extensions.addU16(extensionSupportedVersions)
extensions.addU16(2) // Length
if m.supportedVersOverride != 0 {
@ -950,7 +966,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
m.random = data[6:38]
data = data[38:]
if vers < VersionTLS13 || m.vers == tls13ExperimentVersion {
if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
sessionIdLen := int(data[0])
if sessionIdLen > 32 || len(data) < 1+sessionIdLen {
return false
@ -963,7 +979,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
m.cipherSuite = uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
if vers < VersionTLS13 || m.vers == tls13ExperimentVersion {
if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
if len(data) < 1 {
return false
}
@ -1052,7 +1068,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
m.hasPSKIdentity = true
case extensionSupportedVersions:
if m.vers != tls13ExperimentVersion {
if !isResumptionExperiment(m.vers) {
return false
}
default:
@ -1133,6 +1149,7 @@ type serverExtensions struct {
keyShare keyShareEntry
supportedVersion uint16
supportedPoints []uint8
supportedCurves []CurveID
serverNameAck bool
}
@ -1240,6 +1257,15 @@ func (m *serverExtensions) marshal(extensions *byteBuilder) {
supportedPoints := supportedPointsList.addU8LengthPrefixed()
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 {
extensions.addU16(extensionEarlyData)
extensions.addBytes([]byte{0, 0})
@ -1380,6 +1406,9 @@ func (m *serverExtensions) unmarshal(data []byte, version uint16) bool {
type helloRetryRequestMsg struct {
raw []byte
vers uint16
isServerHello bool
sessionId []byte
cipherSuite uint16
hasSelectedGroup bool
selectedGroup CurveID
cookie []byte
@ -1393,9 +1422,26 @@ func (m *helloRetryRequestMsg) marshal() []byte {
}
retryRequestMsg := newByteBuilder()
retryRequestMsg.addU8(typeHelloRetryRequest)
if isDraft22(m.vers) {
retryRequestMsg.addU8(typeServerHello)
} else {
retryRequestMsg.addU8(typeHelloRetryRequest)
}
retryRequest := retryRequestMsg.addU24LengthPrefixed()
retryRequest.addU16(m.vers)
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)
if isDraft21(m.vers) {
retryRequest.addU16(m.cipherSuite)
}
}
extensions := retryRequest.addU16LengthPrefixed()
count := 1
@ -1404,12 +1450,18 @@ func (m *helloRetryRequestMsg) marshal() []byte {
}
for i := 0; i < count; i++ {
if isDraft22(m.vers) {
extensions.addU16(extensionSupportedVersions)
extensions.addU16(2) // Length
extensions.addU16(m.vers)
}
if m.hasSelectedGroup {
extensions.addU16(extensionKeyShare)
extensions.addU16(2) // length
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)
body := extensions.addU16LengthPrefixed()
body.addU16LengthPrefixed().addBytes(m.cookie)
@ -1430,8 +1482,29 @@ func (m *helloRetryRequestMsg) unmarshal(data []byte) bool {
return false
}
m.vers = uint16(data[4])<<8 | uint16(data[5])
extLen := int(data[6])<<8 | int(data[7])
data = data[8:]
data = data[6:]
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 {
return false
}
@ -1447,6 +1520,11 @@ func (m *helloRetryRequestMsg) unmarshal(data []byte) bool {
}
switch extension {
case extensionSupportedVersions:
if length != 2 || !m.isServerHello {
return false
}
m.vers = uint16(data[0])<<8 | uint16(data[1])
case extensionKeyShare:
if length != 2 {
return false
@ -1844,7 +1922,8 @@ func (m *nextProtoMsg) unmarshal(data []byte) bool {
}
type certificateRequestMsg struct {
raw []byte
raw []byte
vers uint16
// hasSignatureAlgorithm indicates whether this message includes a list
// of signature and hash functions. This change was introduced with TLS
// 1.2.
@ -1858,6 +1937,8 @@ type certificateRequestMsg struct {
requestContext []byte
signatureAlgorithms []signatureAlgorithm
certificateAuthorities [][]byte
hasCAExtension bool
customExtension uint16
}
func (m *certificateRequestMsg) marshal() []byte {
@ -1873,33 +1954,119 @@ func (m *certificateRequestMsg) marshal() []byte {
if m.hasRequestContext {
requestContext := body.addU8LengthPrefixed()
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 {
certificateTypes := body.addU8LengthPrefixed()
certificateTypes.addBytes(m.certificateTypes)
}
if m.hasSignatureAlgorithm {
signatureAlgorithms := body.addU16LengthPrefixed()
for _, sigAlg := range m.signatureAlgorithms {
signatureAlgorithms.addU16(uint16(sigAlg))
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)
}
if m.hasRequestContext {
// Emit no certificate extensions.
body.addU16(0)
certificateAuthorities := body.addU16LengthPrefixed()
for _, ca := range m.certificateAuthorities {
caEntry := certificateAuthorities.addU16LengthPrefixed()
caEntry.addBytes(ca)
}
}
m.raw = builder.finish()
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 {
m.raw = data
@ -1916,6 +2083,70 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool {
m.requestContext = make([]byte, contextLen)
copy(m.requestContext, data[1:])
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 {
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
// Ignore certificate extensions.
if len(data) < 2 {
return false
}
extsLength := int(data[0])<<8 | int(data[1])
if len(data) < 2+extsLength {
return false
}
data = data[2+extsLength:]
}
} else {
numCertTypes := int(data[0])
if len(data) < 1+numCertTypes {
@ -1924,66 +2155,22 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool {
m.certificateTypes = make([]byte, numCertTypes)
copy(m.certificateTypes, data[1:])
data = data[1+numCertTypes:]
}
if m.hasSignatureAlgorithm {
if len(data) < 2 {
return false
}
sigAlgsLen := uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
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 {
return false
}
casLength := uint16(data[0])<<8 | uint16(data[1])
data = data[2:]
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
if m.hasSignatureAlgorithm {
sigAlgs, rest, ok := parseSignatureAlgorithms(data)
if !ok {
return false
}
m.signatureAlgorithms = sigAlgs
data = rest
}
m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
cas = cas[caLen:]
}
if m.hasRequestContext {
// Ignore certificate extensions.
if len(data) < 2 {
cas, rest, ok := parseCAs(data)
if !ok {
return false
}
extsLength := int(data[0])<<8 | int(data[1])
if len(data) < 2+extsLength {
return false
}
data = data[2+extsLength:]
m.certificateAuthorities = cas
data = rest
}
if len(data) > 0 {
@ -2064,15 +2251,17 @@ func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
}
type newSessionTicketMsg struct {
raw []byte
version uint16
ticketLifetime uint32
ticketAgeAdd uint32
ticket []byte
maxEarlyDataSize uint32
customExtension string
duplicateEarlyDataInfo bool
hasGREASEExtension bool
raw []byte
vers uint16
isDTLS bool
ticketLifetime uint32
ticketAgeAdd uint32
ticketNonce []byte
ticket []byte
maxEarlyDataSize uint32
customExtension string
duplicateEarlyDataExtension bool
hasGREASEExtension bool
}
func (m *newSessionTicketMsg) marshal() []byte {
@ -2080,25 +2269,37 @@ func (m *newSessionTicketMsg) marshal() []byte {
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
ticketMsg := newByteBuilder()
ticketMsg.addU8(typeNewSessionTicket)
body := ticketMsg.addU24LengthPrefixed()
body.addU32(m.ticketLifetime)
if m.version >= VersionTLS13 {
if version >= VersionTLS13 {
body.addU32(m.ticketAgeAdd)
if isDraft21(m.vers) {
body.addU8LengthPrefixed().addBytes(m.ticketNonce)
}
}
ticket := body.addU16LengthPrefixed()
ticket.addBytes(m.ticket)
if m.version >= VersionTLS13 {
if version >= VersionTLS13 {
extensions := body.addU16LengthPrefixed()
if m.maxEarlyDataSize > 0 {
extensions.addU16(extensionTicketEarlyDataInfo)
extID := extensionTicketEarlyDataInfo
if isDraft21(m.vers) {
extID = extensionEarlyData
}
extensions.addU16(extID)
extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
if m.duplicateEarlyDataInfo {
extensions.addU16(extensionTicketEarlyDataInfo)
if m.duplicateEarlyDataExtension {
extensions.addU16(extID)
extensions.addU16LengthPrefixed().addU32(m.maxEarlyDataSize)
}
}
@ -2115,18 +2316,32 @@ func (m *newSessionTicketMsg) marshal() []byte {
func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
m.raw = data
version, ok := wireToVersion(m.vers, m.isDTLS)
if !ok {
panic("unknown version")
}
if len(data) < 8 {
return false
}
m.ticketLifetime = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
data = data[8:]
if m.version >= VersionTLS13 {
if version >= VersionTLS13 {
if len(data) < 4 {
return false
}
m.ticketAgeAdd = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
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 {
@ -2138,14 +2353,14 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
return false
}
if m.version >= VersionTLS13 && ticketLen == 0 {
if version >= VersionTLS13 && ticketLen == 0 {
return false
}
m.ticket = data[:ticketLen]
data = data[ticketLen:]
if m.version >= VersionTLS13 {
if version >= VersionTLS13 {
if len(data) < 2 {
return false
}
@ -2156,6 +2371,11 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
return false
}
extID := extensionTicketEarlyDataInfo
if isDraft21(m.vers) {
extID = extensionEarlyData
}
for len(data) != 0 {
if len(data) < 4 {
return false
@ -2168,7 +2388,7 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
}
switch extension {
case extensionTicketEarlyDataInfo:
case extID:
if length != 4 {
return false
}
@ -2355,6 +2575,21 @@ func (m *keyUpdateMsg) unmarshal(data []byte) bool {
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
// alert in the handshake.
type ssl3NoCertificateMsg struct{}

View File

@ -80,7 +80,7 @@ func (c *Conn) serverHandshake() error {
return err
}
}
if err := hs.sendFinished(c.firstFinished[:]); err != nil {
if err := hs.sendFinished(c.firstFinished[:], isResume); err != nil {
return err
}
// 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 {
return err
}
if err := hs.sendFinished(nil); err != nil {
if err := hs.sendFinished(nil, isResume); err != nil {
return err
}
}
@ -281,7 +281,7 @@ func (hs *serverHandshakeState) readClientHello() error {
}
if config.Bugs.ExpectNoTLS12Session {
if len(hs.clientHello.sessionId) > 0 && c.wireVersion != tls13ExperimentVersion {
if len(hs.clientHello.sessionId) > 0 && !isResumptionExperiment(c.wireVersion) {
return fmt.Errorf("tls: client offered an unexpected session ID")
}
if len(hs.clientHello.sessionTicket) > 0 {
@ -358,6 +358,12 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
c := hs.c
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{
isDTLS: c.isDTLS,
vers: c.wireVersion,
@ -412,7 +418,7 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
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.writeClientHash(hs.clientHello.marshal())
@ -496,7 +502,7 @@ Curves:
// AcceptAnyBinder is set. See https://crbug.com/boringssl/115.
if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
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
}
}
@ -520,8 +526,14 @@ Curves:
ResendHelloRetryRequest:
var sendHelloRetryRequest bool
cipherSuite := hs.suite.id
if config.Bugs.SendHelloRetryRequestCipherSuite != 0 {
cipherSuite = config.Bugs.SendHelloRetryRequestCipherSuite
}
helloRetryRequest := &helloRetryRequestMsg{
vers: c.wireVersion,
sessionId: hs.clientHello.sessionId,
cipherSuite: cipherSuite,
duplicateExtensions: config.Bugs.DuplicateHelloRetryRequestExtensions,
}
@ -571,15 +583,21 @@ ResendHelloRetryRequest:
}
if sendHelloRetryRequest {
if isDraft21(c.wireVersion) {
if err := hs.finishedHash.UpdateForHelloRetryRequest(); err != nil {
return err
}
}
oldClientHelloBytes := hs.clientHello.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()
if !c.config.Bugs.SkipChangeCipherSpec && isDraft22(c.wireVersion) {
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
}
if hs.clientHello.hasEarlyData {
c.skipEarlyData = true
}
@ -596,6 +614,10 @@ ResendHelloRetryRequest:
}
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 {
return errors.New("tls: EarlyData sent in new ClientHello")
}
@ -630,11 +652,15 @@ ResendHelloRetryRequest:
// PSK binders and obfuscated ticket age are both updated in the
// second ClientHello.
if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
return errors.New("tls: PSK identity count from old and new ClientHello do not match")
}
for i, identity := range oldClientHelloCopy.pskIdentities {
newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge
if isDraft21(c.wireVersion) && len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
newClientHelloCopy.pskIdentities = oldClientHelloCopy.pskIdentities
} else {
if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
return errors.New("tls: PSK identity count from old and new ClientHello do not match")
}
for i, identity := range oldClientHelloCopy.pskIdentities {
newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge
}
}
newClientHelloCopy.pskBinders = oldClientHelloCopy.pskBinders
newClientHelloCopy.hasEarlyData = oldClientHelloCopy.hasEarlyData
@ -652,8 +678,7 @@ ResendHelloRetryRequest:
// AcceptAnyBinder is set. See https://crbug.com/115.
if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
binderToVerify := newClientHello.pskBinders[pskIndex]
err := verifyPSKBinder(newClientHello, hs.sessionState, binderToVerify, append(oldClientHelloBytes, helloRetryRequest.marshal()...))
if err != nil {
if err := verifyPSKBinder(c.wireVersion, newClientHello, hs.sessionState, binderToVerify, oldClientHelloBytes, helloRetryRequest.marshal()); err != nil {
return err
}
}
@ -667,8 +692,15 @@ ResendHelloRetryRequest:
}
}
if encryptedExtensions.extensions.hasEarlyData {
earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyTrafficLabel)
c.in.useTrafficSecret(c.vers, hs.suite, earlyTrafficSecret, clientWrite)
earlyLabel := earlyTrafficLabel
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 {
if err := c.readRecord(recordTypeApplicationData); err != nil {
@ -719,6 +751,7 @@ ResendHelloRetryRequest:
c.sendAlert(alertHandshakeFailure)
return err
}
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(ecdheSecret)
hs.hello.hasKeyShare = true
@ -743,6 +776,7 @@ ResendHelloRetryRequest:
}
}
} else {
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret())
}
@ -755,23 +789,30 @@ ResendHelloRetryRequest:
toWrite = append(toWrite, typeEncryptedExtensions)
c.writeRecord(recordTypeHandshake, toWrite)
} else {
if c.vers == tls13RecordTypeExperimentVersion {
c.writeRecord(recordTypePlaintextHandshake, hs.hello.marshal())
} else {
c.writeRecord(recordTypeHandshake, hs.hello.marshal())
}
c.writeRecord(recordTypeHandshake, hs.hello.marshal())
}
c.flushHandshake()
if c.wireVersion == tls13ExperimentVersion {
if !c.config.Bugs.SkipChangeCipherSpec && isResumptionExperiment(c.wireVersion) && !sendHelloRetryRequest {
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.
serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel)
c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite)
serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverLabel)
c.useOutTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret)
// Derive handshake traffic read key, but don't switch yet.
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel)
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
// Send EncryptedExtensions.
hs.writeServerHash(encryptedExtensions.marshal())
@ -786,9 +827,11 @@ ResendHelloRetryRequest:
if config.ClientAuth >= RequestClientCert {
// Request a client certificate
certReq := &certificateRequestMsg{
hasSignatureAlgorithm: true,
vers: c.wireVersion,
hasSignatureAlgorithm: !config.Bugs.OmitCertificateRequestAlgorithms,
hasRequestContext: true,
requestContext: config.Bugs.SendRequestContext,
customExtension: config.Bugs.SendCustomCertificateRequest,
}
if !config.Bugs.NoSignatureAlgorithms {
certReq.signatureAlgorithms = config.verifySignatureAlgorithms()
@ -903,14 +946,25 @@ ResendHelloRetryRequest:
// The various secrets do not incorporate the client's final leg, so
// derive them now before updating the handshake context.
hs.finishedHash.nextSecret()
hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret())
clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel)
serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel)
c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel)
clientLabel = clientApplicationTrafficLabel
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
// 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.
for _, halfRTTMsg := range config.Bugs.SendHalfRTTData {
@ -919,24 +973,39 @@ ResendHelloRetryRequest:
}
}
// Read end_of_early_data alert.
// Read end_of_early_data.
if encryptedExtensions.extensions.hasEarlyData {
if err := c.readRecord(recordTypeAlert); err != errEndOfEarlyDataAlert {
if err == nil {
panic("readRecord(recordTypeAlert) returned nil")
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 == nil {
panic("readRecord(recordTypeAlert) returned nil")
}
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.
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
// certificate message, even if it's empty.
@ -1040,17 +1109,25 @@ ResendHelloRetryRequest:
hs.writeClientHash(clientFinished.marshal())
// 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.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
// testing.
if !c.config.SessionTicketsDisabled && foundKEMode {
ticketCount := 2
for i := 0; i < ticketCount; i++ {
c.SendNewSessionTicket()
c.SendNewSessionTicket([]byte{byte(i)})
}
}
return nil
@ -1089,9 +1166,6 @@ func (hs *serverHandshakeState) processClientHello() (isResume bool, err error)
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 {
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
}
if c.config.Bugs.SendServerSupportedCurves {
serverExtensions.supportedCurves = c.config.curvePreferences()
}
if !hs.clientHello.hasGREASEExtension && config.Bugs.ExpectGREASE {
return errors.New("tls: no GREASE extension found")
}
@ -1410,7 +1488,7 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
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.writeClientHash(hs.clientHello.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.writeServerHash(hs.hello.marshal())
@ -1516,6 +1594,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if config.ClientAuth >= RequestClientCert {
// Request a client certificate
certReq := &certificateRequestMsg{
vers: c.wireVersion,
certificateTypes: config.ClientCertificateTypes,
}
if certReq.certificateTypes == nil {
@ -1697,8 +1776,8 @@ func (hs *serverHandshakeState) establishKeys() error {
serverCipher = hs.suite.aead(c.vers, serverKey, serverIV)
}
c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
c.in.prepareCipherSpec(c.wireVersion, clientCipher, clientHash)
c.out.prepareCipherSpec(c.wireVersion, serverCipher, serverHash)
return nil
}
@ -1789,6 +1868,8 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
}
m := new(newSessionTicketMsg)
m.vers = c.wireVersion
m.isDTLS = c.isDTLS
if c.config.Bugs.SendTicketLifetime != 0 {
m.ticketLifetime = uint32(c.config.Bugs.SendTicketLifetime / time.Second)
}
@ -1807,7 +1888,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
return nil
}
func (hs *serverHandshakeState) sendFinished(out []byte) error {
func (hs *serverHandshakeState) sendFinished(out []byte, isResume bool) error {
c := hs.c
finished := new(finishedMsg)
@ -1852,8 +1933,8 @@ func (hs *serverHandshakeState) sendFinished(out []byte) error {
}
}
if !c.config.Bugs.PackHelloRequestWithFinished {
// Defer flushing until renegotiation.
if isResume || (!c.config.Bugs.PackHelloRequestWithFinished && !c.config.Bugs.PackAppDataWithHandshake) {
// Defer flushing until Renegotiate() or Write().
c.flushHandshake()
}
@ -1935,7 +2016,7 @@ func verifyChannelIDMessage(channelIDMsg *channelIDMsg, channelIDHash []byte) (*
if !elliptic.P256().IsOnCurve(x, y) {
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) {
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 {
continue
}
if c.isDTLS && candidate.flags&suiteNoDTLS != 0 {
continue
}
return candidate
}
}
@ -2027,7 +2105,7 @@ func isGREASEValue(val uint16) bool {
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
for _, binder := range clientHello.pskBinders {
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")
}
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) {
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")
}
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) {
bad := config.Bugs.BadRSAClientKeyExchange
preMasterSecret := make([]byte, 48)
vers := clientHello.vers
if bad == RSABadValueWrongVersion {
if bad == RSABadValueWrongVersion1 {
vers ^= 1
} else if bad == RSABadValueWrongVersion2 {
vers ^= 0x100
}
preMasterSecret[0] = byte(vers >> 8)
preMasterSecret[1] = byte(vers)
@ -152,13 +187,31 @@ func (ka *rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello
sentPreMasterSecret := preMasterSecret
if bad == RSABadValueTooLong {
sentPreMasterSecret = make([]byte, len(sentPreMasterSecret)+1)
copy(sentPreMasterSecret, preMasterSecret)
sentPreMasterSecret = make([]byte, 1, len(sentPreMasterSecret)+1)
sentPreMasterSecret = append(sentPreMasterSecret, preMasterSecret...)
} else if bad == RSABadValueTooShort {
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 {
return nil, nil, err
}

View File

@ -180,9 +180,14 @@ func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clie
return
}
func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
func newFinishedHash(wireVersion uint16, isDTLS bool, cipherSuite *cipherSuite) finishedHash {
var ret finishedHash
version, ok := wireToVersion(wireVersion, isDTLS)
if !ok {
panic("unknown version")
}
if version >= VersionTLS12 {
ret.hash = cipherSuite.hash()
@ -207,6 +212,7 @@ func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
ret.buffer = []byte{}
ret.version = version
ret.wireVersion = wireVersion
return ret
}
@ -226,13 +232,28 @@ type finishedHash struct {
// full buffer is required.
buffer []byte
version uint16
prf func(result, secret, label, seed []byte)
version uint16
wireVersion uint16
prf func(result, secret, label, seed []byte)
// secret, in TLS 1.3, is the running input secret.
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) {
h.client.Write(msg)
h.server.Write(msg)
@ -307,7 +328,7 @@ func (h finishedHash) clientSum(baseKey []byte) []byte {
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.Write(h.appendContextHashes(nil))
return finishedHMAC.Sum(nil)
@ -326,7 +347,7 @@ func (h finishedHash) serverSum(baseKey []byte) []byte {
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.Write(h.appendContextHashes(nil))
return finishedHMAC.Sum(nil)
@ -374,20 +395,33 @@ func (h *finishedHash) addEntropy(ikm []byte) {
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
// 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 {
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[0] = byte(length >> 8)
x[1] = byte(length)
x[2] = byte(9 + len(label))
x[2] = byte(len(versionLabel) + len(label))
x = x[3:]
copy(x, []byte("TLS 1.3, "))
x = x[9:]
copy(x, versionLabel)
x = x[len(versionLabel):]
copy(x, label)
x = x[len(label):]
x[0] = byte(len(hashValue))
@ -414,12 +448,25 @@ var (
applicationTrafficLabel = []byte("application traffic secret")
exporterLabel = []byte("exporter 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
// section 7.1 of draft ietf-tls-tls13-16.
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.
@ -458,21 +505,34 @@ var (
// deriveTrafficAEAD derives traffic keys and constructs an AEAD given a traffic
// secret.
func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) interface{} {
key := hkdfExpandLabel(suite.hash(), secret, keyTLS13, nil, suite.keyLen)
iv := hkdfExpandLabel(suite.hash(), secret, ivTLS13, nil, suite.ivLen(version))
key := hkdfExpandLabel(suite.hash(), version, secret, keyTLS13, nil, suite.keyLen)
iv := hkdfExpandLabel(suite.hash(), version, secret, ivTLS13, nil, suite.ivLen(version))
return suite.aead(version, key, iv)
}
func updateTrafficSecret(hash crypto.Hash, secret []byte) []byte {
return hkdfExpandLabel(hash, secret, applicationTrafficLabel, nil, hash.Size())
func updateTrafficSecret(hash crypto.Hash, version uint16, secret []byte) []byte {
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 {
finishedHash := newFinishedHash(VersionTLS13, cipherSuite)
func computePSKBinder(psk []byte, version uint16, label []byte, cipherSuite *cipherSuite, clientHello, helloRetryRequest, truncatedHello []byte) []byte {
finishedHash := newFinishedHash(version, false, cipherSuite)
finishedHash.addEntropy(psk)
binderKey := finishedHash.deriveSecret(label)
finishedHash.Write(transcript)
finishedHash.Write(clientHello)
if isDraft21(version) && len(helloRetryRequest) != 0 {
finishedHash.UpdateForHelloRetryRequest()
}
finishedHash.Write(helloRetryRequest)
finishedHash.Write(truncatedHello)
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 {
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...)
}
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 },
{ "-expect-ticket-renewal", &TestConfig::expect_ticket_renewal },
{ "-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 },
{ "-renew-ticket", &TestConfig::renew_ticket },
{ "-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-accept-early-data", &TestConfig::expect_accept_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 },
{ "-handshake-twice", &TestConfig::handshake_twice },
{ "-allow-unknown-alpn-protos", &TestConfig::allow_unknown_alpn_protos },
@ -130,7 +132,6 @@ const Flag<bool> kBoolFlags[] = {
const Flag<std::string> kStringFlags[] = {
{ "-write-settings", &TestConfig::write_settings },
{ "-digest-prefs", &TestConfig::digest_prefs },
{ "-key-file", &TestConfig::key_file },
{ "-cert-file", &TestConfig::cert_file },
{ "-expect-server-name", &TestConfig::expected_server_name },

View File

@ -26,7 +26,6 @@ struct TestConfig {
int resume_count = 0;
std::string write_settings;
bool fallback_scsv = false;
std::string digest_prefs;
std::vector<int> signing_prefs;
std::vector<int> verify_prefs;
std::string key_file;
@ -87,9 +86,10 @@ struct TestConfig {
bool tls_unique = false;
bool expect_ticket_renewal = 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_reject_early_data = false;
bool expect_no_offer_early_data = false;
bool use_ticket_callback = false;
bool renew_ticket = false;
bool enable_early_data = false;

2
vendor/manifest vendored
View File

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