Enabling 0-RTT on new Session Tickets.
This adds support for setting 0-RTT mode on tickets minted by BoringSSL, allowing for testing of the initial handshake knowledge. BUG=76 Change-Id: Ic199842c03b5401ef122a537fdb7ed9e9a5c635a Reviewed-on: https://boringssl-review.googlesource.com/12740 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
parent
c0c7019282
commit
08b65f4e31
@ -2913,6 +2913,11 @@ OPENSSL_EXPORT int SSL_renegotiate_pending(SSL *ssl);
|
||||
* peformed by |ssl|. This includes the pending renegotiation, if any. */
|
||||
OPENSSL_EXPORT int SSL_total_renegotiations(const SSL *ssl);
|
||||
|
||||
/* SSL_CTX_set_early_data_enabled sets whether early data is allowed to be used
|
||||
* with resumptions using |ctx|. WARNING: This is experimental and may cause
|
||||
* interop failures until fully implemented. */
|
||||
OPENSSL_EXPORT void SSL_CTX_set_early_data_enabled(SSL_CTX *ctx, int enabled);
|
||||
|
||||
/* SSL_MAX_CERT_LIST_DEFAULT is the default maximum length, in bytes, of a peer
|
||||
* certificate chain. */
|
||||
#define SSL_MAX_CERT_LIST_DEFAULT (1024 * 100)
|
||||
@ -3758,6 +3763,10 @@ struct ssl_session_st {
|
||||
|
||||
uint32_t ticket_age_add;
|
||||
|
||||
/* ticket_max_early_data is the maximum amount of data allowed to be sent as
|
||||
* early data. If zero, 0-RTT is disallowed. */
|
||||
uint32_t ticket_max_early_data;
|
||||
|
||||
/* extended_master_secret is true if the master secret in this session was
|
||||
* generated using EMS and thus isn't vulnerable to the Triple Handshake
|
||||
* attack. */
|
||||
@ -4033,6 +4042,10 @@ struct ssl_ctx_st {
|
||||
* shutdown. */
|
||||
unsigned quiet_shutdown:1;
|
||||
|
||||
/* If enable_early_data is non-zero, early data can be sent and accepted over
|
||||
* new connections. */
|
||||
unsigned enable_early_data:1;
|
||||
|
||||
/* ocsp_stapling_enabled is only used by client connections and indicates
|
||||
* whether OCSP stapling will be requested. */
|
||||
unsigned ocsp_stapling_enabled:1;
|
||||
|
@ -213,6 +213,7 @@ extern "C" {
|
||||
#define TLSEXT_TYPE_supported_versions 43
|
||||
#define TLSEXT_TYPE_cookie 44
|
||||
#define TLSEXT_TYPE_psk_key_exchange_modes 45
|
||||
#define TLSEXT_TYPE_ticket_early_data_info 46
|
||||
|
||||
/* ExtensionType value from RFC5746 */
|
||||
#define TLSEXT_TYPE_renegotiate 0xff01
|
||||
|
@ -1148,10 +1148,10 @@ typedef struct {
|
||||
* it. It writes the parsed extensions to pointers denoted by |ext_types|. On
|
||||
* success, it fills in the |out_present| and |out_data| fields and returns one.
|
||||
* Otherwise, it sets |*out_alert| to an alert to send and returns zero. Unknown
|
||||
* extensions are rejected. */
|
||||
* extensions are rejected unless |ignore_unknown| is 1. */
|
||||
int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
|
||||
const SSL_EXTENSION_TYPE *ext_types,
|
||||
size_t num_ext_types);
|
||||
size_t num_ext_types, int ignore_unknown);
|
||||
|
||||
|
||||
/* SSLKEYLOGFILE functions. */
|
||||
|
@ -780,7 +780,7 @@ int ssl_verify_alarm_type(long type) {
|
||||
|
||||
int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
|
||||
const SSL_EXTENSION_TYPE *ext_types,
|
||||
size_t num_ext_types) {
|
||||
size_t num_ext_types, int ignore_unknown) {
|
||||
/* Reset everything. */
|
||||
for (size_t i = 0; i < num_ext_types; i++) {
|
||||
*ext_types[i].out_present = 0;
|
||||
@ -807,6 +807,9 @@ int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
|
||||
}
|
||||
|
||||
if (ext_type == NULL) {
|
||||
if (ignore_unknown) {
|
||||
continue;
|
||||
}
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
|
||||
*out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
|
||||
return 0;
|
||||
|
@ -128,6 +128,7 @@
|
||||
* ticketAgeAdd [21] OCTET STRING OPTIONAL,
|
||||
* isServer [22] BOOLEAN DEFAULT TRUE,
|
||||
* peerSignatureAlgorithm [23] INTEGER OPTIONAL,
|
||||
* ticketMaxEarlyData [24] INTEGER OPTIONAL,
|
||||
* }
|
||||
*
|
||||
* Note: historically this serialization has included other optional
|
||||
@ -180,6 +181,8 @@ static const int kIsServerTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 22;
|
||||
static const int kPeerSignatureAlgorithmTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 23;
|
||||
static const int kTicketMaxEarlyDataTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 24;
|
||||
|
||||
static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
|
||||
size_t *out_len, int for_ticket) {
|
||||
@ -392,6 +395,13 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (in->ticket_max_early_data != 0 &&
|
||||
(!CBB_add_asn1(&session, &child, kTicketMaxEarlyDataTag) ||
|
||||
!CBB_add_asn1_uint64(&child, in->ticket_max_early_data))) {
|
||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!CBB_finish(&cbb, out_data, out_len)) {
|
||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
@ -775,6 +785,8 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
|
||||
|
||||
if (!SSL_SESSION_parse_u16(&session, &ret->peer_signature_algorithm,
|
||||
kPeerSignatureAlgorithmTag, 0) ||
|
||||
!SSL_SESSION_parse_u32(&session, &ret->ticket_max_early_data,
|
||||
kTicketMaxEarlyDataTag, 0) ||
|
||||
CBS_len(&session) != 0) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
|
||||
goto err;
|
||||
|
@ -874,6 +874,10 @@ int SSL_send_fatal_alert(SSL *ssl, uint8_t alert) {
|
||||
return ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
||||
}
|
||||
|
||||
void SSL_CTX_set_early_data_enabled(SSL_CTX *ctx, int enabled) {
|
||||
ctx->enable_early_data = !!enabled;
|
||||
}
|
||||
|
||||
static int bio_retry_reason_to_error(int reason) {
|
||||
switch (reason) {
|
||||
case BIO_RR_CONNECT:
|
||||
|
@ -276,6 +276,7 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
|
||||
session->original_handshake_hash_len;
|
||||
new_session->tlsext_tick_lifetime_hint = session->tlsext_tick_lifetime_hint;
|
||||
new_session->ticket_age_add = session->ticket_age_add;
|
||||
new_session->ticket_max_early_data = session->ticket_max_early_data;
|
||||
new_session->extended_master_secret = session->extended_master_secret;
|
||||
}
|
||||
|
||||
|
@ -1045,6 +1045,10 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(const TestConfig *config) {
|
||||
SSL_CTX_set_short_header_enabled(ssl_ctx.get(), 1);
|
||||
}
|
||||
|
||||
if (config->enable_early_data) {
|
||||
SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1);
|
||||
}
|
||||
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
@ -1844,6 +1848,19 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
|
||||
GetTestState(ssl.get())->got_new_session ? "" : " not");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expect_new_session) {
|
||||
bool got_early_data_info =
|
||||
GetTestState(ssl.get())->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");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (out_session) {
|
||||
|
@ -95,6 +95,7 @@ const (
|
||||
extensionSupportedVersions uint16 = 43 // draft-ietf-tls-tls13-16
|
||||
extensionCookie uint16 = 44 // draft-ietf-tls-tls13-16
|
||||
extensionPSKKeyExchangeModes uint16 = 45 // draft-ietf-tls-tls13-18
|
||||
extensionTicketEarlyDataInfo uint16 = 46 // draft-ietf-tls-tls13-18
|
||||
extensionCustom uint16 = 1234 // not IANA assigned
|
||||
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
|
||||
extensionRenegotiationInfo uint16 = 0xff01
|
||||
@ -102,11 +103,6 @@ const (
|
||||
extensionShortHeader uint16 = 27463 // not IANA assigned
|
||||
)
|
||||
|
||||
// TLS ticket extension numbers
|
||||
const (
|
||||
ticketExtensionCustom uint16 = 1234 // not IANA assigned
|
||||
)
|
||||
|
||||
// TLS signaling cipher suite values
|
||||
const (
|
||||
scsvRenegotiation uint16 = 0x00ff
|
||||
@ -959,6 +955,15 @@ type ProtocolBugs struct {
|
||||
// receipt of a NewSessionTicket message.
|
||||
ExpectNoNewSessionTicket bool
|
||||
|
||||
// SendTicketEarlyDataInfo, if non-zero, is the maximum amount of data that we
|
||||
// will accept as early data, and gets sent in the ticket_early_data_info
|
||||
// extension of the NewSessionTicket message.
|
||||
SendTicketEarlyDataInfo uint32
|
||||
|
||||
// ExpectTicketEarlyDataInfo, if true, means that the client will fail upon
|
||||
// absence of the ticket_early_data_info extension.
|
||||
ExpectTicketEarlyDataInfo bool
|
||||
|
||||
// ExpectTicketAge, if non-zero, is the expected age of the ticket that the
|
||||
// server receives from the client.
|
||||
ExpectTicketAge time.Duration
|
||||
|
@ -1451,6 +1451,10 @@ func (c *Conn) handlePostHandshakeMessage() error {
|
||||
return errors.New("tls: no GREASE ticket extension found")
|
||||
}
|
||||
|
||||
if c.config.Bugs.ExpectTicketEarlyDataInfo && newSessionTicket.earlyDataInfo == 0 {
|
||||
return errors.New("tls: no ticket_early_data_info extension found")
|
||||
}
|
||||
|
||||
if c.config.Bugs.ExpectNoNewSessionTicket {
|
||||
return errors.New("tls: received unexpected NewSessionTicket")
|
||||
}
|
||||
@ -1765,6 +1769,7 @@ func (c *Conn) SendNewSessionTicket() error {
|
||||
m := &newSessionTicketMsg{
|
||||
version: c.vers,
|
||||
ticketLifetime: uint32(24 * time.Hour / time.Second),
|
||||
earlyDataInfo: c.config.Bugs.SendTicketEarlyDataInfo,
|
||||
customExtension: c.config.Bugs.CustomTicketExtension,
|
||||
ticketAgeAdd: ticketAgeAdd,
|
||||
}
|
||||
|
@ -2008,6 +2008,7 @@ type newSessionTicketMsg struct {
|
||||
ticketLifetime uint32
|
||||
ticketAgeAdd uint32
|
||||
ticket []byte
|
||||
earlyDataInfo uint32
|
||||
customExtension string
|
||||
hasGREASEExtension bool
|
||||
}
|
||||
@ -2031,8 +2032,12 @@ func (m *newSessionTicketMsg) marshal() []byte {
|
||||
|
||||
if m.version >= VersionTLS13 {
|
||||
extensions := body.addU16LengthPrefixed()
|
||||
if m.earlyDataInfo > 0 {
|
||||
extensions.addU16(extensionTicketEarlyDataInfo)
|
||||
extensions.addU16LengthPrefixed().addU32(m.earlyDataInfo)
|
||||
}
|
||||
if len(m.customExtension) > 0 {
|
||||
extensions.addU16(ticketExtensionCustom)
|
||||
extensions.addU16(extensionCustom)
|
||||
extensions.addU16LengthPrefixed().addBytes([]byte(m.customExtension))
|
||||
}
|
||||
}
|
||||
@ -2078,28 +2083,37 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
|
||||
if len(data) < 2 {
|
||||
return false
|
||||
}
|
||||
extsLength := int(data[0])<<8 + int(data[1])
|
||||
|
||||
extensionsLength := int(data[0])<<8 | int(data[1])
|
||||
data = data[2:]
|
||||
if len(data) < extsLength {
|
||||
if extensionsLength != len(data) {
|
||||
return false
|
||||
}
|
||||
extensions := data[:extsLength]
|
||||
data = data[extsLength:]
|
||||
|
||||
for len(extensions) > 0 {
|
||||
if len(extensions) < 4 {
|
||||
for len(data) != 0 {
|
||||
if len(data) < 4 {
|
||||
return false
|
||||
}
|
||||
extValue := uint16(extensions[0])<<8 | uint16(extensions[1])
|
||||
extLength := int(extensions[2])<<8 | int(extensions[3])
|
||||
if len(extensions) < 4+extLength {
|
||||
extension := uint16(data[0])<<8 | uint16(data[1])
|
||||
length := int(data[2])<<8 | int(data[3])
|
||||
data = data[4:]
|
||||
if len(data) < length {
|
||||
return false
|
||||
}
|
||||
extensions = extensions[4+extLength:]
|
||||
|
||||
if isGREASEValue(extValue) {
|
||||
m.hasGREASEExtension = true
|
||||
switch extension {
|
||||
case extensionTicketEarlyDataInfo:
|
||||
if length != 4 {
|
||||
return false
|
||||
}
|
||||
m.earlyDataInfo = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
|
||||
default:
|
||||
if isGREASEValue(extension) {
|
||||
m.hasGREASEExtension = true
|
||||
}
|
||||
}
|
||||
|
||||
data = data[length:]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8379,6 +8379,33 @@ func addSessionTicketTests() {
|
||||
expectedLocalError: "tls: invalid ticket age",
|
||||
})
|
||||
|
||||
testCases = append(testCases, testCase{
|
||||
testType: clientTest,
|
||||
name: "TLS13-SendTicketEarlyDataInfo",
|
||||
config: Config{
|
||||
MaxVersion: VersionTLS13,
|
||||
Bugs: ProtocolBugs{
|
||||
SendTicketEarlyDataInfo: 16384,
|
||||
},
|
||||
},
|
||||
flags: []string{
|
||||
"-expect-early-data-info",
|
||||
},
|
||||
})
|
||||
|
||||
testCases = append(testCases, testCase{
|
||||
testType: serverTest,
|
||||
name: "TLS13-ExpectTicketEarlyDataInfo",
|
||||
config: Config{
|
||||
MaxVersion: VersionTLS13,
|
||||
Bugs: ProtocolBugs{
|
||||
ExpectTicketEarlyDataInfo: true,
|
||||
},
|
||||
},
|
||||
flags: []string{
|
||||
"-enable-early-data",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func addChangeCipherSpecTests() {
|
||||
|
@ -81,8 +81,10 @@ 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 },
|
||||
{ "-use-ticket-callback", &TestConfig::use_ticket_callback },
|
||||
{ "-renew-ticket", &TestConfig::renew_ticket },
|
||||
{ "-enable-early-data", &TestConfig::enable_early_data },
|
||||
{ "-enable-client-custom-extension",
|
||||
&TestConfig::enable_client_custom_extension },
|
||||
{ "-enable-server-custom-extension",
|
||||
|
@ -83,8 +83,10 @@ struct TestConfig {
|
||||
bool tls_unique = false;
|
||||
bool expect_ticket_renewal = false;
|
||||
bool expect_no_session = false;
|
||||
bool expect_early_data_info = false;
|
||||
bool use_ticket_callback = false;
|
||||
bool renew_ticket = false;
|
||||
bool enable_early_data = false;
|
||||
bool enable_client_custom_extension = false;
|
||||
bool enable_server_custom_extension = false;
|
||||
bool custom_extension_skip = false;
|
||||
|
@ -243,7 +243,8 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) {
|
||||
|
||||
uint8_t alert;
|
||||
if (!ssl_parse_extensions(&extensions, &alert, ext_types,
|
||||
OPENSSL_ARRAY_SIZE(ext_types))) {
|
||||
OPENSSL_ARRAY_SIZE(ext_types),
|
||||
0 /* reject unknown */)) {
|
||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
||||
goto err;
|
||||
}
|
||||
|
@ -78,7 +78,8 @@ static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) {
|
||||
|
||||
uint8_t alert;
|
||||
if (!ssl_parse_extensions(&extensions, &alert, ext_types,
|
||||
OPENSSL_ARRAY_SIZE(ext_types))) {
|
||||
OPENSSL_ARRAY_SIZE(ext_types),
|
||||
0 /* reject unknown */)) {
|
||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
||||
return ssl_hs_error;
|
||||
}
|
||||
@ -211,7 +212,8 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) {
|
||||
|
||||
uint8_t alert;
|
||||
if (!ssl_parse_extensions(&extensions, &alert, ext_types,
|
||||
OPENSSL_ARRAY_SIZE(ext_types))) {
|
||||
OPENSSL_ARRAY_SIZE(ext_types),
|
||||
0 /* reject unknown */)) {
|
||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
||||
return ssl_hs_error;
|
||||
}
|
||||
@ -659,6 +661,30 @@ int tls13_process_new_session_ticket(SSL *ssl) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse out the extensions. */
|
||||
int have_early_data_info = 0;
|
||||
CBS early_data_info;
|
||||
const SSL_EXTENSION_TYPE ext_types[] = {
|
||||
{TLSEXT_TYPE_ticket_early_data_info, &have_early_data_info,
|
||||
&early_data_info},
|
||||
};
|
||||
|
||||
uint8_t alert;
|
||||
if (!ssl_parse_extensions(&extensions, &alert, ext_types,
|
||||
OPENSSL_ARRAY_SIZE(ext_types),
|
||||
1 /* ignore unknown */)) {
|
||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
||||
return ssl_hs_error;
|
||||
}
|
||||
|
||||
if (have_early_data_info) {
|
||||
if (!CBS_get_u32(&early_data_info, &session->ticket_max_early_data) ||
|
||||
CBS_len(&early_data_info) != 0) {
|
||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
||||
return ssl_hs_error;
|
||||
}
|
||||
}
|
||||
|
||||
session->ticket_age_add_valid = 1;
|
||||
session->not_resumable = 0;
|
||||
|
||||
|
@ -29,6 +29,11 @@
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
/* kMaxEarlyDataAccepted is the advertised number of plaintext bytes of early
|
||||
* data that will be accepted. This value should be slightly below
|
||||
* kMaxEarlyDataSkipped in tls_record.c, which is measured in ciphertext. */
|
||||
static const size_t kMaxEarlyDataAccepted = 14336;
|
||||
|
||||
enum server_hs_state_t {
|
||||
state_process_client_hello = 0,
|
||||
state_select_parameters,
|
||||
@ -657,9 +662,6 @@ static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* TODO(svaldez): Add support for sending 0RTT through TicketEarlyDataInfo
|
||||
* extension. */
|
||||
|
||||
CBB cbb, body, ticket, extensions;
|
||||
if (!ssl->method->init_message(ssl, &cbb, &body,
|
||||
SSL3_MT_NEW_SESSION_TICKET) ||
|
||||
@ -671,6 +673,18 @@ static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ssl->ctx->enable_early_data) {
|
||||
session->ticket_max_early_data = kMaxEarlyDataAccepted;
|
||||
|
||||
CBB early_data_info;
|
||||
if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) ||
|
||||
!CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
|
||||
!CBB_add_u32(&early_data_info, session->ticket_max_early_data) ||
|
||||
!CBB_flush(&extensions)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a fake extension. See draft-davidben-tls-grease-01. */
|
||||
if (!CBB_add_u16(&extensions,
|
||||
ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
|
||||
|
@ -125,10 +125,11 @@
|
||||
* forever. */
|
||||
static const uint8_t kMaxEmptyRecords = 32;
|
||||
|
||||
/* kMaxEarlyDataSkipped is the maximum amount of data processed when skipping
|
||||
* over early data. Without this limit an attacker could send records at a
|
||||
* faster rate than we can process and cause trial decryption to loop
|
||||
* forever. */
|
||||
/* kMaxEarlyDataSkipped is the maximum number of rejected early data bytes that
|
||||
* will be skipped. Without this limit an attacker could send records at a
|
||||
* faster rate than we can process and cause trial decryption to loop forever.
|
||||
* This value should be slightly above kMaxEarlyDataAccepted in tls13_server.c,
|
||||
* which is measured in plaintext. */
|
||||
static const size_t kMaxEarlyDataSkipped = 16384;
|
||||
|
||||
/* kMaxWarningAlerts is the number of consecutive warning alerts that will be
|
||||
|
Loading…
Reference in New Issue
Block a user