Bläddra i källkod

Hand back ECDHE split handshakes after the first server message.

This changes the contract for split handshakes such that on the
receiving side, the connection is to be driven until it returns
|SSL_ERROR_HANDBACK|, rather than until SSL_do_handshake() returns
success.

Change-Id: Idd1ebfbd943d88474d7c934f4c0ae757ff3c0f37
Reviewed-on: https://boringssl-review.googlesource.com/26864
Commit-Queue: Matt Braithwaite <mab@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
kris/onging/CECPQ3_patch15
Matthew Braithwaite 6 år sedan
committed by CQ bot account: commit-bot@chromium.org
förälder
incheckning
56986f905f
10 ändrade filer med 418 tillägg och 222 borttagningar
  1. +7
    -5
      include/openssl/ssl.h
  2. +107
    -39
      ssl/handoff.cc
  3. +5
    -0
      ssl/handshake.cc
  4. +87
    -103
      ssl/handshake_server.cc
  5. +42
    -0
      ssl/internal.h
  6. +54
    -0
      ssl/ssl_key_share.cc
  7. +3
    -0
      ssl/ssl_lib.cc
  8. +7
    -2
      ssl/ssl_test.cc
  9. +0
    -4
      ssl/ssl_transcript.cc
  10. +106
    -69
      ssl/test/bssl_shim.cc

+ 7
- 5
include/openssl/ssl.h Visa fil

@@ -535,6 +535,7 @@ OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code);
#define SSL_ERROR_WANT_CERTIFICATE_VERIFY 16

#define SSL_ERROR_HANDOFF 17
#define SSL_ERROR_HANDBACK 18

// SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success
// and zero on failure.
@@ -3926,6 +3927,7 @@ OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb(
#define SSL_EARLY_DATA_REJECTED 11
#define SSL_CERTIFICATE_VERIFY 12
#define SSL_HANDOFF 13
#define SSL_HANDBACK 14

// SSL_want returns one of the above values to determine what the most recent
// operation on |ssl| was blocked on. Use |SSL_get_error| instead.
@@ -4478,10 +4480,10 @@ OPENSSL_EXPORT bool SealRecord(SSL *ssl, Span<uint8_t> out_prefix,
// state of the connection.
//
// Elsewhere, a fresh |SSL| can be used with |SSL_apply_handoff| to continue
// the connection. The connection from the client is fed into this |SSL| until
// the handshake completes normally. At this point (and only at this point),
// |SSL_serialize_handback| can be called to serialize the result of the
// handshake.
// the connection. The connection from the client is fed into this |SSL|, and
// the handshake resumed. When the handshake stops again and |SSL_get_error|
// indicates |SSL_ERROR_HANDBACK|, |SSL_serialize_handback| should be called to
// serialize the state of the handshake again.
//
// Back at the first location, a fresh |SSL| can be used with
// |SSL_apply_handback|. Then the client's connection can be processed mostly
@@ -4489,7 +4491,7 @@ OPENSSL_EXPORT bool SealRecord(SSL *ssl, Span<uint8_t> out_prefix,
//
// Lastly, when a connection is in the handoff state, whether or not
// |SSL_serialize_handoff| is called, |SSL_decline_handoff| will move it back
// into a normal state where the connection can procede without impact.
// into a normal state where the connection can proceed without impact.
//
// WARNING: Currently only works with TLS 1.0–1.2.
// WARNING: The serialisation formats are not yet stable: version skew may be


+ 107
- 39
ssl/handoff.cc Visa fil

@@ -93,17 +93,17 @@ bool SSL_apply_handoff(SSL *ssl, Span<const uint8_t> handoff) {
if (CBS_len(&transcript) != 0) {
s3->hs->transcript.Update(transcript);
s3->is_v2_hello = true;
ssl_do_msg_callback(ssl, 0 /* read */, 0 /* V2ClientHello */, transcript);
}
ssl->handback = true;

return true;
}

bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
if (!ssl->server ||
!ssl->s3->initial_handshake_complete ||
ssl->method->is_dtls ||
ssl->version < TLS1_VERSION) {
(ssl->s3->hs->state != state12_finish_server_handshake &&
ssl->s3->hs->state != state12_read_client_certificate) ||
ssl->method->is_dtls || ssl->version < TLS1_VERSION) {
return false;
}

@@ -115,14 +115,22 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) {

size_t iv_len = 0;
const uint8_t *read_iv = nullptr, *write_iv = nullptr;
if (ssl->version == TLS1_VERSION &&
SSL_CIPHER_is_block_cipher(s3->aead_read_ctx->cipher()) &&
(!s3->aead_read_ctx->GetIV(&read_iv, &iv_len) ||
!s3->aead_write_ctx->GetIV(&write_iv, &iv_len))) {
return false;
Span<const uint8_t> transcript;
if (ssl->s3->hs->state == state12_finish_server_handshake) {
if (ssl->version == TLS1_VERSION &&
SSL_CIPHER_is_block_cipher(s3->aead_read_ctx->cipher()) &&
(!s3->aead_read_ctx->GetIV(&read_iv, &iv_len) ||
!s3->aead_write_ctx->GetIV(&write_iv, &iv_len))) {
return false;
}
} else {
transcript = s3->hs->transcript.buffer();
}

CBB seq;
// TODO(mab): make sure everything is serialized.
CBB seq, key_share;
SSL_SESSION *session =
s3->session_reused ? ssl->session : s3->hs->new_session.get();
if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&seq, kHandbackVersion) ||
!CBB_add_asn1_uint64(&seq, ssl->version) ||
@@ -142,7 +150,7 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
!CBB_add_asn1_bool(&seq, s3->session_reused) ||
!CBB_add_asn1_bool(&seq, s3->send_connection_binding) ||
!CBB_add_asn1_bool(&seq, s3->tlsext_channel_id_valid) ||
!ssl_session_serialize(s3->established_session.get(), &seq) ||
!ssl_session_serialize(session, &seq) ||
!CBB_add_asn1_octet_string(&seq, s3->next_proto_negotiated.data(),
s3->next_proto_negotiated.size()) ||
!CBB_add_asn1_octet_string(&seq, s3->alpn_selected.data(),
@@ -158,11 +166,22 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
!CBB_add_asn1_bool(&seq, ssl->quiet_shutdown) ||
!CBB_add_asn1_bool(&seq, ssl->tlsext_channel_id_enabled) ||
!CBB_add_asn1_bool(&seq, ssl->retain_only_sha256_of_client_certs) ||
!CBB_flush(out)) {
!CBB_add_asn1_bool(&seq, ssl->token_binding_negotiated) ||
!CBB_add_asn1_uint64(&seq, ssl->negotiated_token_binding_param) ||
!CBB_add_asn1_bool(&seq, s3->hs->next_proto_neg_seen) ||
!CBB_add_asn1_bool(&seq, s3->hs->cert_request) ||
!CBB_add_asn1_bool(&seq, s3->hs->extended_master_secret) ||
!CBB_add_asn1_bool(&seq, s3->hs->ticket_expected) ||
!CBB_add_asn1_uint64(&seq, SSL_CIPHER_get_id(s3->hs->new_cipher)) ||
!CBB_add_asn1_octet_string(&seq, transcript.data(), transcript.size()) ||
!CBB_add_asn1(&seq, &key_share, CBS_ASN1_SEQUENCE)) {
return false;
}

return true;
if (ssl->s3->hs->state == state12_read_client_certificate &&
!s3->hs->key_share->Serialize(&key_share)) {
return false;
}
return CBB_flush(out);
}

bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
@@ -173,11 +192,16 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {

SSL3_STATE *const s3 = ssl->s3;
uint64_t handback_version, version, conf_max_version, conf_min_version,
max_send_fragment, options, mode, max_cert_list;
max_send_fragment, options, mode, max_cert_list,
negotiated_token_binding_param, cipher;

CBS seq, read_seq, write_seq, server_rand, client_rand, read_iv, write_iv,
next_proto, alpn, hostname, channel_id;
int session_reused, send_connection_binding, channel_id_valid,
quiet_shutdown, channel_id_enabled, retain_only_sha256;
next_proto, alpn, hostname, channel_id, transcript, key_share;
int session_reused, send_connection_binding, channel_id_valid, quiet_shutdown,
channel_id_enabled, retain_only_sha256, cert_request,
extended_master_secret, ticket_expected, token_binding_negotiated,
next_proto_neg_seen;
SSL_SESSION *session = nullptr;

CBS handback_cbs(handback);
if (!CBS_get_asn1(&handback_cbs, &seq, CBS_ASN1_SEQUENCE) ||
@@ -210,11 +234,19 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
return false;
}

s3->established_session =
SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
s3->hs = ssl_handshake_new(ssl);
if (session_reused) {
ssl->session =
SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool)
.release();
session = ssl->session;
} else {
s3->hs->new_session =
SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
session = s3->hs->new_session.get();
}

if (!s3->established_session ||
!CBS_get_asn1(&seq, &next_proto, CBS_ASN1_OCTETSTRING) ||
if (!session || !CBS_get_asn1(&seq, &next_proto, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &alpn, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &hostname, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &channel_id, CBS_ASN1_OCTETSTRING) ||
@@ -226,7 +258,22 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
!CBS_get_asn1_uint64(&seq, &max_cert_list) ||
!CBS_get_asn1_bool(&seq, &quiet_shutdown) ||
!CBS_get_asn1_bool(&seq, &channel_id_enabled) ||
!CBS_get_asn1_bool(&seq, &retain_only_sha256)) {
!CBS_get_asn1_bool(&seq, &retain_only_sha256) ||
!CBS_get_asn1_bool(&seq, &token_binding_negotiated) ||
!CBS_get_asn1_uint64(&seq, &negotiated_token_binding_param) ||
!CBS_get_asn1_bool(&seq, &next_proto_neg_seen) ||
!CBS_get_asn1_bool(&seq, &cert_request) ||
!CBS_get_asn1_bool(&seq, &extended_master_secret) ||
!CBS_get_asn1_bool(&seq, &ticket_expected) ||
!CBS_get_asn1_uint64(&seq, &cipher)) {
return false;
}
if ((s3->hs->new_cipher =
SSL_get_cipher_by_value(static_cast<uint16_t>(cipher))) == nullptr) {
return false;
}
if (!CBS_get_asn1(&seq, &transcript, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &key_share, CBS_ASN1_SEQUENCE)) {
return false;
}

@@ -240,9 +287,9 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
ssl->mode = mode;
ssl->max_cert_list = max_cert_list;

s3->hs.reset();
s3->have_version = true;
s3->initial_handshake_complete = true;
s3->hs->state = CBS_len(&transcript) == 0 ? state12_finish_server_handshake
: state12_read_client_certificate;
s3->session_reused = session_reused;
s3->send_connection_binding = send_connection_binding;
s3->tlsext_channel_id_valid = channel_id_valid;
@@ -263,23 +310,44 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
ssl->quiet_shutdown = quiet_shutdown;
ssl->tlsext_channel_id_enabled = channel_id_enabled;
ssl->retain_only_sha256_of_client_certs = retain_only_sha256;
ssl->token_binding_negotiated = token_binding_negotiated;
ssl->negotiated_token_binding_param =
static_cast<uint8_t>(negotiated_token_binding_param);
s3->hs->next_proto_neg_seen = next_proto_neg_seen;
s3->hs->wait = ssl_hs_flush;
s3->hs->extended_master_secret = extended_master_secret;
s3->hs->ticket_expected = ticket_expected;
s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version);
s3->hs->cert_request = cert_request;

if (s3->hs->state == state12_finish_server_handshake) {
Array<uint8_t> key_block;
if (!tls1_configure_aead(ssl, evp_aead_open, &key_block, session->cipher,
read_iv) ||
!tls1_configure_aead(ssl, evp_aead_seal, &key_block, session->cipher,
write_iv)) {
return false;
}

Array<uint8_t> key_block;
if (!tls1_configure_aead(ssl, evp_aead_open, &key_block,
s3->established_session->cipher, read_iv) ||
!tls1_configure_aead(ssl, evp_aead_seal, &key_block,
s3->established_session->cipher, write_iv)) {
return false;
}

if (!CBS_copy_bytes(&read_seq, s3->read_sequence,
sizeof(s3->read_sequence)) ||
!CBS_copy_bytes(&write_seq, s3->write_sequence,
sizeof(s3->write_sequence))) {
return false;
if (!CBS_copy_bytes(&read_seq, s3->read_sequence,
sizeof(s3->read_sequence)) ||
!CBS_copy_bytes(&write_seq, s3->write_sequence,
sizeof(s3->write_sequence))) {
return false;
}
} else {
if (!s3->hs->transcript.Init() ||
!s3->hs->transcript.InitHash(ssl_protocol_version(ssl),
s3->hs->new_cipher) ||
!s3->hs->transcript.Update(transcript)) {
return false;
}
if ((s3->hs->key_share = SSLKeyShare::Create(&key_share)) == nullptr) {
return false;
}
}

return true;
return CBS_len(&seq) == 0;
}

} // namespace bssl

+ 5
- 0
ssl/handshake.cc Visa fil

@@ -565,6 +565,11 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) {
hs->wait = ssl_hs_ok;
return -1;

case ssl_hs_handback:
ssl->s3->rwstate = SSL_HANDBACK;
hs->wait = ssl_hs_handback;
return -1;

case ssl_hs_x509_lookup:
ssl->s3->rwstate = SSL_X509_LOOKUP;
hs->wait = ssl_hs_ok;


+ 87
- 103
ssl/handshake_server.cc Visa fil

@@ -172,30 +172,6 @@

namespace bssl {

enum ssl_server_hs_state_t {
state_start_accept = 0,
state_read_client_hello,
state_select_certificate,
state_tls13,
state_select_parameters,
state_send_server_hello,
state_send_server_certificate,
state_send_server_key_exchange,
state_send_server_hello_done,
state_read_client_certificate,
state_verify_client_certificate,
state_read_client_key_exchange,
state_read_client_certificate_verify,
state_read_change_cipher_spec,
state_process_change_cipher_spec,
state_read_next_proto,
state_read_channel_id,
state_read_client_finished,
state_send_server_finished,
state_finish_server_handshake,
state_done,
};

int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello,
uint16_t id) {
CBS cipher_suites;
@@ -425,7 +401,7 @@ static const SSL_CIPHER *ssl3_choose_cipher(

static enum ssl_hs_wait_t do_start_accept(SSL_HANDSHAKE *hs) {
ssl_do_info_callback(hs->ssl, SSL_CB_HANDSHAKE_START, 1);
hs->state = state_read_client_hello;
hs->state = state12_read_client_hello;
return ssl_hs_ok;
}

@@ -505,7 +481,7 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}

hs->state = state_select_certificate;
hs->state = state12_select_certificate;
return ssl_hs_ok;
}

@@ -536,7 +512,7 @@ static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {

if (ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
// Jump to the TLS 1.3 state machine.
hs->state = state_tls13;
hs->state = state12_tls13;
return ssl_hs_ok;
}

@@ -555,14 +531,14 @@ static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}

hs->state = state_select_parameters;
hs->state = state12_select_parameters;
return ssl_hs_ok;
}

static enum ssl_hs_wait_t do_tls13(SSL_HANDSHAKE *hs) {
enum ssl_hs_wait_t wait = tls13_server_handshake(hs);
if (wait == ssl_hs_ok) {
hs->state = state_finish_server_handshake;
hs->state = state12_finish_server_handshake;
return ssl_hs_ok;
}

@@ -672,14 +648,15 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}

// Release the handshake buffer if client authentication isn't required.
if (!hs->cert_request) {
// Handback includes the whole handshake transcript, so we cannot free the
// transcript buffer in the handback case.
if (!hs->cert_request && !hs->ssl->handback) {
hs->transcript.FreeBuffer();
}

ssl->method->next_message(ssl);

hs->state = state_send_server_hello;
hs->state = state12_send_server_hello;
return ssl_hs_ok;
}

@@ -744,9 +721,9 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
}

if (ssl->session != NULL) {
hs->state = state_send_server_finished;
hs->state = state12_send_server_finished;
} else {
hs->state = state_send_server_certificate;
hs->state = state12_send_server_certificate;
}
return ssl_hs_ok;
}
@@ -835,7 +812,7 @@ static enum ssl_hs_wait_t do_send_server_certificate(SSL_HANDSHAKE *hs) {
}
}

hs->state = state_send_server_key_exchange;
hs->state = state12_send_server_key_exchange;
return ssl_hs_ok;
}

@@ -843,7 +820,7 @@ static enum ssl_hs_wait_t do_send_server_key_exchange(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;

if (hs->server_params.size() == 0) {
hs->state = state_send_server_hello_done;
hs->state = state12_send_server_hello_done;
return ssl_hs_ok;
}

@@ -907,7 +884,7 @@ static enum ssl_hs_wait_t do_send_server_key_exchange(SSL_HANDSHAKE *hs) {

hs->server_params.Reset();

hs->state = state_send_server_hello_done;
hs->state = state12_send_server_hello_done;
return ssl_hs_ok;
}

@@ -942,15 +919,18 @@ static enum ssl_hs_wait_t do_send_server_hello_done(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}

hs->state = state_read_client_certificate;
hs->state = state12_read_client_certificate;
return ssl_hs_flush;
}

static enum ssl_hs_wait_t do_read_client_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;

if (ssl->handback && hs->new_cipher->algorithm_mkey == SSL_kECDHE) {
return ssl_hs_handback;
}
if (!hs->cert_request) {
hs->state = state_verify_client_certificate;
hs->state = state12_verify_client_certificate;
return ssl_hs_ok;
}

@@ -973,7 +953,7 @@ static enum ssl_hs_wait_t do_read_client_certificate(SSL_HANDSHAKE *hs) {
// OpenSSL returns X509_V_OK when no certificates are received. This is
// classed by them as a bug, but it's assumed by at least NGINX.
hs->new_session->verify_result = X509_V_OK;
hs->state = state_verify_client_certificate;
hs->state = state12_verify_client_certificate;
return ssl_hs_ok;
}

@@ -1035,7 +1015,7 @@ static enum ssl_hs_wait_t do_read_client_certificate(SSL_HANDSHAKE *hs) {
}

ssl->method->next_message(ssl);
hs->state = state_verify_client_certificate;
hs->state = state12_verify_client_certificate;
return ssl_hs_ok;
}

@@ -1051,7 +1031,7 @@ static enum ssl_hs_wait_t do_verify_client_certificate(SSL_HANDSHAKE *hs) {
}
}

hs->state = state_read_client_key_exchange;
hs->state = state12_read_client_key_exchange;
return ssl_hs_ok;
}

@@ -1262,7 +1242,7 @@ static enum ssl_hs_wait_t do_read_client_key_exchange(SSL_HANDSHAKE *hs) {
hs->new_session->extended_master_secret = hs->extended_master_secret;

ssl->method->next_message(ssl);
hs->state = state_read_client_certificate_verify;
hs->state = state12_read_client_certificate_verify;
return ssl_hs_ok;
}

@@ -1273,7 +1253,7 @@ static enum ssl_hs_wait_t do_read_client_certificate_verify(SSL_HANDSHAKE *hs) {
// CertificateVerify is required if and only if there's a client certificate.
if (!hs->peer_pubkey) {
hs->transcript.FreeBuffer();
hs->state = state_read_change_cipher_spec;
hs->state = state12_read_change_cipher_spec;
return ssl_hs_ok;
}

@@ -1358,12 +1338,12 @@ static enum ssl_hs_wait_t do_read_client_certificate_verify(SSL_HANDSHAKE *hs) {
}

ssl->method->next_message(ssl);
hs->state = state_read_change_cipher_spec;
hs->state = state12_read_change_cipher_spec;
return ssl_hs_ok;
}

static enum ssl_hs_wait_t do_read_change_cipher_spec(SSL_HANDSHAKE *hs) {
hs->state = state_process_change_cipher_spec;
hs->state = state12_process_change_cipher_spec;
return ssl_hs_read_change_cipher_spec;
}

@@ -1372,7 +1352,7 @@ static enum ssl_hs_wait_t do_process_change_cipher_spec(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}

hs->state = state_read_next_proto;
hs->state = state12_read_next_proto;
return ssl_hs_ok;
}

@@ -1380,7 +1360,7 @@ static enum ssl_hs_wait_t do_read_next_proto(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;

if (!hs->next_proto_neg_seen) {
hs->state = state_read_channel_id;
hs->state = state12_read_channel_id;
return ssl_hs_ok;
}

@@ -1408,7 +1388,7 @@ static enum ssl_hs_wait_t do_read_next_proto(SSL_HANDSHAKE *hs) {
}

ssl->method->next_message(ssl);
hs->state = state_read_channel_id;
hs->state = state12_read_channel_id;
return ssl_hs_ok;
}

@@ -1416,7 +1396,7 @@ static enum ssl_hs_wait_t do_read_channel_id(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;

if (!ssl->s3->tlsext_channel_id_valid) {
hs->state = state_read_client_finished;
hs->state = state12_read_client_finished;
return ssl_hs_ok;
}

@@ -1432,7 +1412,7 @@ static enum ssl_hs_wait_t do_read_channel_id(SSL_HANDSHAKE *hs) {
}

ssl->method->next_message(ssl);
hs->state = state_read_client_finished;
hs->state = state12_read_client_finished;
return ssl_hs_ok;
}

@@ -1444,9 +1424,9 @@ static enum ssl_hs_wait_t do_read_client_finished(SSL_HANDSHAKE *hs) {
}

if (ssl->session != NULL) {
hs->state = state_finish_server_handshake;
hs->state = state12_finish_server_handshake;
} else {
hs->state = state_send_server_finished;
hs->state = state12_send_server_finished;
}

// If this is a full handshake with ChannelID then record the handshake
@@ -1501,9 +1481,9 @@ static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) {
}

if (ssl->session != NULL) {
hs->state = state_read_change_cipher_spec;
hs->state = state12_read_change_cipher_spec;
} else {
hs->state = state_finish_server_handshake;
hs->state = state12_finish_server_handshake;
}
return ssl_hs_flush;
}
@@ -1511,6 +1491,10 @@ static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_finish_server_handshake(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;

if (ssl->handback) {
return ssl_hs_handback;
}

ssl->method->on_handshake_complete(ssl);

// If we aren't retaining peer certificates then we can discard it now.
@@ -1532,77 +1516,77 @@ static enum ssl_hs_wait_t do_finish_server_handshake(SSL_HANDSHAKE *hs) {
ssl->s3->initial_handshake_complete = true;
ssl_update_cache(hs, SSL_SESS_CACHE_SERVER);

hs->state = state_done;
hs->state = state12_done;
return ssl_hs_ok;
}

enum ssl_hs_wait_t ssl_server_handshake(SSL_HANDSHAKE *hs) {
while (hs->state != state_done) {
while (hs->state != state12_done) {
enum ssl_hs_wait_t ret = ssl_hs_error;
enum ssl_server_hs_state_t state =
static_cast<enum ssl_server_hs_state_t>(hs->state);
enum tls12_server_hs_state_t state =
static_cast<enum tls12_server_hs_state_t>(hs->state);
switch (state) {
case state_start_accept:
case state12_start_accept:
ret = do_start_accept(hs);
break;
case state_read_client_hello:
case state12_read_client_hello:
ret = do_read_client_hello(hs);
break;
case state_select_certificate:
case state12_select_certificate:
ret = do_select_certificate(hs);
break;
case state_tls13:
case state12_tls13:
ret = do_tls13(hs);
break;
case state_select_parameters:
case state12_select_parameters:
ret = do_select_parameters(hs);
break;
case state_send_server_hello:
case state12_send_server_hello:
ret = do_send_server_hello(hs);
break;
case state_send_server_certificate:
case state12_send_server_certificate:
ret = do_send_server_certificate(hs);
break;
case state_send_server_key_exchange:
case state12_send_server_key_exchange:
ret = do_send_server_key_exchange(hs);
break;
case state_send_server_hello_done:
case state12_send_server_hello_done:
ret = do_send_server_hello_done(hs);
break;
case state_read_client_certificate:
case state12_read_client_certificate:
ret = do_read_client_certificate(hs);
break;
case state_verify_client_certificate:
case state12_verify_client_certificate:
ret = do_verify_client_certificate(hs);
break;
case state_read_client_key_exchange:
case state12_read_client_key_exchange:
ret = do_read_client_key_exchange(hs);
break;
case state_read_client_certificate_verify:
case state12_read_client_certificate_verify:
ret = do_read_client_certificate_verify(hs);
break;
case state_read_change_cipher_spec:
case state12_read_change_cipher_spec:
ret = do_read_change_cipher_spec(hs);
break;
case state_process_change_cipher_spec:
case state12_process_change_cipher_spec:
ret = do_process_change_cipher_spec(hs);
break;
case state_read_next_proto:
case state12_read_next_proto:
ret = do_read_next_proto(hs);
break;
case state_read_channel_id:
case state12_read_channel_id:
ret = do_read_channel_id(hs);
break;
case state_read_client_finished:
case state12_read_client_finished:
ret = do_read_client_finished(hs);
break;
case state_send_server_finished:
case state12_send_server_finished:
ret = do_send_server_finished(hs);
break;
case state_finish_server_handshake:
case state12_finish_server_handshake:
ret = do_finish_server_handshake(hs);
break;
case state_done:
case state12_done:
ret = ssl_hs_ok;
break;
}
@@ -1621,50 +1605,50 @@ enum ssl_hs_wait_t ssl_server_handshake(SSL_HANDSHAKE *hs) {
}

const char *ssl_server_handshake_state(SSL_HANDSHAKE *hs) {
enum ssl_server_hs_state_t state =
static_cast<enum ssl_server_hs_state_t>(hs->state);
enum tls12_server_hs_state_t state =
static_cast<enum tls12_server_hs_state_t>(hs->state);
switch (state) {
case state_start_accept:
case state12_start_accept:
return "TLS server start_accept";
case state_read_client_hello:
case state12_read_client_hello:
return "TLS server read_client_hello";
case state_select_certificate:
case state12_select_certificate:
return "TLS server select_certificate";
case state_tls13:
case state12_tls13:
return tls13_server_handshake_state(hs);
case state_select_parameters:
case state12_select_parameters:
return "TLS server select_parameters";
case state_send_server_hello:
case state12_send_server_hello:
return "TLS server send_server_hello";
case state_send_server_certificate:
case state12_send_server_certificate:
return "TLS server send_server_certificate";
case state_send_server_key_exchange:
case state12_send_server_key_exchange:
return "TLS server send_server_key_exchange";
case state_send_server_hello_done:
case state12_send_server_hello_done:
return "TLS server send_server_hello_done";
case state_read_client_certificate:
case state12_read_client_certificate:
return "TLS server read_client_certificate";
case state_verify_client_certificate:
case state12_verify_client_certificate:
return "TLS server verify_client_certificate";
case state_read_client_key_exchange:
case state12_read_client_key_exchange:
return "TLS server read_client_key_exchange";
case state_read_client_certificate_verify:
case state12_read_client_certificate_verify:
return "TLS server read_client_certificate_verify";
case state_read_change_cipher_spec:
case state12_read_change_cipher_spec:
return "TLS server read_change_cipher_spec";
case state_process_change_cipher_spec:
case state12_process_change_cipher_spec:
return "TLS server process_change_cipher_spec";
case state_read_next_proto:
case state12_read_next_proto:
return "TLS server read_next_proto";
case state_read_channel_id:
case state12_read_channel_id:
return "TLS server read_channel_id";
case state_read_client_finished:
case state12_read_client_finished:
return "TLS server read_client_finished";
case state_send_server_finished:
case state12_send_server_finished:
return "TLS server send_server_finished";
case state_finish_server_handshake:
case state12_finish_server_handshake:
return "TLS server finish_server_handshake";
case state_done:
case state12_done:
return "TLS server done";
}



+ 42
- 0
ssl/internal.h Visa fil

@@ -929,6 +929,10 @@ class SSLKeyShare {
// nullptr on error.
static UniquePtr<SSLKeyShare> Create(uint16_t group_id);

// Create deserializes an SSLKeyShare instance previously serialized by
// |Serialize|.
static UniquePtr<SSLKeyShare> Create(CBS *in);

// GroupID returns the group ID.
virtual uint16_t GroupID() const PURE_VIRTUAL;

@@ -952,6 +956,14 @@ class SSLKeyShare {
// send to the peer.
virtual bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert,
Span<const uint8_t> peer_key) PURE_VIRTUAL;

// Serialize writes the state of the key exchange to |out|, returning true if
// successful and false otherwise.
virtual bool Serialize(CBB *out) { return false; }

// Deserialize initializes the state of the key exchange from |in|, returning
// true if successful and false otherwise. It is called by |Create|.
virtual bool Deserialize(CBS *in) { return false; }
};

// ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it
@@ -1258,6 +1270,7 @@ enum ssl_hs_wait_t {
ssl_hs_flush,
ssl_hs_certificate_selection_pending,
ssl_hs_handoff,
ssl_hs_handback,
ssl_hs_x509_lookup,
ssl_hs_channel_id_lookup,
ssl_hs_private_key_operation,
@@ -1280,6 +1293,30 @@ enum ssl_grease_index_t {
ssl_grease_last_index = ssl_grease_ticket_extension,
};

enum tls12_server_hs_state_t {
state12_start_accept = 0,
state12_read_client_hello,
state12_select_certificate,
state12_tls13,
state12_select_parameters,
state12_send_server_hello,
state12_send_server_certificate,
state12_send_server_key_exchange,
state12_send_server_hello_done,
state12_read_client_certificate,
state12_verify_client_certificate,
state12_read_client_key_exchange,
state12_read_client_certificate_verify,
state12_read_change_cipher_spec,
state12_process_change_cipher_spec,
state12_read_next_proto,
state12_read_channel_id,
state12_read_client_finished,
state12_send_server_finished,
state12_finish_server_handshake,
state12_done,
};

struct SSL_HANDSHAKE {
explicit SSL_HANDSHAKE(SSL *ssl);
~SSL_HANDSHAKE();
@@ -2676,6 +2713,11 @@ struct SSLConnection {
// element of the same name and may be cleared if the handoff is declined.
bool handoff:1;

// handback indicates that a server should pause the handshake after
// finishing operations that require private key material, in such a way that
// |SSL_get_error| returns |SSL_HANDBACK|. It is set by |SSL_apply_handoff|.
bool handback : 1;

// did_dummy_pq_padding is only valid for a client. In that context, it is
// true iff the client observed the server echoing a dummy PQ padding
// extension.


+ 54
- 0
ssl/ssl_key_share.cc Visa fil

@@ -124,6 +124,32 @@ class ECKeyShare : public SSLKeyShare {
return true;
}

bool Serialize(CBB *out) override {
assert(private_key_);
CBB cbb;
UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_));
// Padding is added to avoid leaking the length.
size_t len = BN_num_bytes(EC_GROUP_get0_order(group.get()));
if (!CBB_add_asn1_uint64(out, group_id_) ||
!CBB_add_asn1(out, &cbb, CBS_ASN1_OCTETSTRING) ||
!BN_bn2cbb_padded(&cbb, len, private_key_.get()) ||
!CBB_flush(out)) {
return false;
}
return true;
}

bool Deserialize(CBS *in) override {
assert(!private_key_);
CBS private_key;
if (!CBS_get_asn1(in, &private_key, CBS_ASN1_OCTETSTRING)) {
return false;
}
private_key_.reset(BN_bin2bn(CBS_data(&private_key),
CBS_len(&private_key), nullptr));
return private_key_ != nullptr;
}

private:
UniquePtr<BIGNUM> private_key_;
int nid_;
@@ -166,6 +192,21 @@ class X25519KeyShare : public SSLKeyShare {
return true;
}

bool Serialize(CBB *out) override {
return (CBB_add_asn1_uint64(out, GroupID()) &&
CBB_add_asn1_octet_string(out, private_key_, sizeof(private_key_)));
}

bool Deserialize(CBS *in) override {
CBS key;
if (!CBS_get_asn1(in, &key, CBS_ASN1_OCTETSTRING) ||
CBS_len(&key) != sizeof(private_key_) ||
!CBS_copy_bytes(&key, private_key_, sizeof(private_key_))) {
return false;
}
return true;
}

private:
uint8_t private_key_[32];
};
@@ -205,6 +246,19 @@ UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) {
}
}

UniquePtr<SSLKeyShare> SSLKeyShare::Create(CBS *in) {
uint64_t group;
if (!CBS_get_asn1_uint64(in, &group)) {
return nullptr;
}
UniquePtr<SSLKeyShare> key_share = Create(static_cast<uint64_t>(group));
if (!key_share->Deserialize(in)) {
return nullptr;
}
return key_share;
}


bool SSLKeyShare::Accept(CBB *out_public_key, Array<uint8_t> *out_secret,
uint8_t *out_alert, Span<const uint8_t> peer_key) {
*out_alert = SSL_AD_INTERNAL_ERROR;


+ 3
- 0
ssl/ssl_lib.cc Visa fil

@@ -1274,6 +1274,9 @@ int SSL_get_error(const SSL *ssl, int ret_code) {
case SSL_HANDOFF:
return SSL_ERROR_HANDOFF;

case SSL_HANDBACK:
return SSL_ERROR_HANDBACK;

case SSL_READING: {
BIO *bio = SSL_get_rbio(ssl);
if (BIO_should_read(bio)) {


+ 7
- 2
ssl/ssl_test.cc Visa fil

@@ -3949,9 +3949,13 @@ TEST(SSLTest, Handoff) {

int handshake_ret = SSL_do_handshake(handshaker.get());
int handshake_err = SSL_get_error(handshaker.get(), handshake_ret);
ASSERT_EQ(handshake_err, SSL_ERROR_WANT_READ);
ASSERT_EQ(handshake_err, SSL_ERROR_HANDBACK);

ASSERT_TRUE(CompleteHandshakes(client.get(), handshaker.get()));
// Double-check that additional calls to |SSL_do_handshake| continue
// to get |SSL_ERRROR_HANDBACK|.
handshake_ret = SSL_do_handshake(handshaker.get());
handshake_err = SSL_get_error(handshaker.get(), handshake_ret);
ASSERT_EQ(handshake_err, SSL_ERROR_HANDBACK);

ScopedCBB cbb_handback;
Array<uint8_t> handback;
@@ -3963,6 +3967,7 @@ TEST(SSLTest, Handoff) {
ASSERT_TRUE(SSL_apply_handback(server2.get(), handback));

MoveBIOs(server2.get(), handshaker.get());
ASSERT_TRUE(CompleteHandshakes(client.get(), server2.get()));

uint8_t byte = 42;
EXPECT_EQ(SSL_write(client.get(), &byte, 1), 1);


+ 0
- 4
ssl/ssl_transcript.cc Visa fil

@@ -368,10 +368,6 @@ bool SSLTranscript::GetFinishedMAC(uint8_t *out, size_t *out_len,
return true;
}

// At this point, the handshake should have released the handshake buffer on
// its own.
assert(!buffer_);

static const char kClientLabel[] = "client finished";
static const char kServerLabel[] = "server finished";
auto label = from_server


+ 106
- 69
ssl/test/bssl_shim.cc Visa fil

@@ -1937,40 +1937,34 @@ static bool WriteSettings(int i, const TestConfig *config,
return fwrite(settings, settings_len, 1, file.get()) == 1;
}

static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
bssl::UniquePtr<SSL> *ssl_uniqueptr,
const TestConfig *config, bool is_resume, bool is_retry);

// DoConnection tests an SSL connection against the peer. On success, it returns
// true and sets |*out_session| to the negotiated SSL session. If the test is a
// resumption attempt, |is_resume| is true and |session| is the session from the
// previous exchange.
static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
SSL_CTX *ssl_ctx, const TestConfig *config,
const TestConfig *retry_config, bool is_resume,
SSL_SESSION *session) {
static bssl::UniquePtr<SSL> NewSSL(SSL_CTX *ssl_ctx, const TestConfig *config,
SSL_SESSION *session, bool is_resume,
std::unique_ptr<TestState> test_state) {
bssl::UniquePtr<SSL> ssl(SSL_new(ssl_ctx));
if (!ssl) {
return false;
return nullptr;
}

if (!SetTestConfig(ssl.get(), config) ||
!SetTestState(ssl.get(), std::unique_ptr<TestState>(new TestState))) {
return false;
if (!SetTestConfig(ssl.get(), config)) {
return nullptr;
}
if (test_state != nullptr) {
if (!SetTestState(ssl.get(), std::move(test_state))) {
return nullptr;
}
GetTestState(ssl.get())->is_resume = is_resume;
}

GetTestState(ssl.get())->is_resume = is_resume;

if (config->fallback_scsv &&
!SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) {
return false;
return nullptr;
}
// Install the certificate synchronously if nothing else will handle it.
if (!config->use_early_callback &&
!config->use_old_client_cert_callback &&
!config->async &&
!InstallCertificate(ssl.get())) {
return false;
return nullptr;
}
if (!config->use_old_client_cert_callback) {
SSL_set_cert_cb(ssl.get(), CertCallback, nullptr);
@@ -2027,7 +2021,7 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
// The async case will be supplied by |ChannelIdCallback|.
bssl::UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(config->send_channel_id);
if (!pkey || !SSL_set1_tls_channel_id(ssl.get(), pkey.get())) {
return false;
return nullptr;
}
}
}
@@ -2039,13 +2033,13 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
}
if (!config->host_name.empty() &&
!SSL_set_tlsext_host_name(ssl.get(), config->host_name.c_str())) {
return false;
return nullptr;
}
if (!config->advertise_alpn.empty() &&
SSL_set_alpn_protos(ssl.get(),
(const uint8_t *)config->advertise_alpn.data(),
config->advertise_alpn.size()) != 0) {
return false;
return nullptr;
}
if (!config->psk.empty()) {
SSL_set_psk_client_callback(ssl.get(), PskClientCallback);
@@ -2053,11 +2047,11 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
}
if (!config->psk_identity.empty() &&
!SSL_use_psk_identity_hint(ssl.get(), config->psk_identity.c_str())) {
return false;
return nullptr;
}
if (!config->srtp_profiles.empty() &&
!SSL_set_srtp_profiles(ssl.get(), config->srtp_profiles.c_str())) {
return false;
return nullptr;
}
if (config->enable_ocsp_stapling) {
SSL_enable_ocsp_stapling(ssl.get());
@@ -2067,11 +2061,11 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
}
if (config->min_version != 0 &&
!SSL_set_min_proto_version(ssl.get(), (uint16_t)config->min_version)) {
return false;
return nullptr;
}
if (config->max_version != 0 &&
!SSL_set_max_proto_version(ssl.get(), (uint16_t)config->max_version)) {
return false;
return nullptr;
}
if (config->mtu != 0) {
SSL_set_options(ssl.get(), SSL_OP_NO_QUERY_MTU);
@@ -2095,7 +2089,7 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
if (config->p384_only) {
int nid = NID_secp384r1;
if (!SSL_set1_curves(ssl.get(), &nid, 1)) {
return false;
return nullptr;
}
}
if (config->enable_all_curves) {
@@ -2105,7 +2099,7 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
};
if (!SSL_set1_curves(ssl.get(), kAllCurves,
OPENSSL_ARRAY_SIZE(kAllCurves))) {
return false;
return nullptr;
}
}
if (config->initial_timeout_duration_ms > 0) {
@@ -2123,7 +2117,7 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
}
if (config->dummy_pq_padding_len > 0 &&
!SSL_set_dummy_pq_padding_size(ssl.get(), config->dummy_pq_padding_len)) {
return false;
return nullptr;
}
if (!config->quic_transport_params.empty()) {
if (!SSL_set_quic_transport_params(
@@ -2131,10 +2125,55 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
reinterpret_cast<const uint8_t *>(
config->quic_transport_params.data()),
config->quic_transport_params.size())) {
return false;
return nullptr;
}
}

if (session != NULL) {
if (!config->is_server) {
if (SSL_set_session(ssl.get(), session) != 1) {
return nullptr;
}
} else if (config->async) {
// The internal session cache is disabled, so install the session
// manually.
SSL_SESSION_up_ref(session);
GetTestState(ssl.get())->pending_session.reset(session);
}
}

if (SSL_get_current_cipher(ssl.get()) != nullptr) {
fprintf(stderr, "non-null cipher before handshake\n");
return nullptr;
}

return ssl;
}

static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
bssl::UniquePtr<SSL> *ssl_uniqueptr,
const TestConfig *config, bool is_resume, bool is_retry);

// DoConnection tests an SSL connection against the peer. On success, it returns
// true and sets |*out_session| to the negotiated SSL session. If the test is a
// resumption attempt, |is_resume| is true and |session| is the session from the
// previous exchange.
static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
SSL_CTX *ssl_ctx, const TestConfig *config,
const TestConfig *retry_config, bool is_resume,
SSL_SESSION *session) {
bssl::UniquePtr<SSL> ssl = NewSSL(ssl_ctx, config, session, is_resume,
std::unique_ptr<TestState>(new TestState));
if (!ssl) {
return false;
}
if (config->is_server) {
SSL_set_accept_state(ssl.get());
} else {
SSL_set_connect_state(ssl.get());
}


int sock = Connect(config->port);
if (sock == -1) {
return false;
@@ -2167,30 +2206,6 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
SSL_set_bio(ssl.get(), bio.get(), bio.get());
bio.release(); // SSL_set_bio takes ownership.

if (session != NULL) {
if (!config->is_server) {
if (SSL_set_session(ssl.get(), session) != 1) {
return false;
}
} else if (config->async) {
// The internal session cache is disabled, so install the session
// manually.
SSL_SESSION_up_ref(session);
GetTestState(ssl.get())->pending_session.reset(session);
}
}

if (SSL_get_current_cipher(ssl.get()) != nullptr) {
fprintf(stderr, "non-null cipher before handshake\n");
return false;
}

if (config->is_server) {
SSL_set_accept_state(ssl.get());
} else {
SSL_set_connect_state(ssl.get());
}

bool ret = DoExchange(out_session, &ssl, config, is_resume, false);
if (!config->is_server && is_resume && config->expect_reject_early_data) {
// We must have failed due to an early data rejection.
@@ -2253,22 +2268,28 @@ static bool HandoffReady(SSL *ssl, int ret) {
return ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_HANDOFF;
}

static bool HandbackReady(SSL *ssl, int ret) {
return ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_HANDBACK;
}

static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
bssl::UniquePtr<SSL> *ssl_uniqueptr,
const TestConfig *config, bool is_resume,
bool is_retry) {
int ret;
SSL *ssl = ssl_uniqueptr->get();
SSL_CTX *session_ctx = ssl->ctx;

if (!config->implicit_handshake) {
if (config->handoff) {
bssl::UniquePtr<SSL_CTX> ctx_handoff(SSL_CTX_new(TLSv1_method()));
bssl::UniquePtr<SSL_CTX> ctx_handoff = SetupCtx(ssl->ctx, config);
if (!ctx_handoff) {
return false;
}
SSL_CTX_set_handoff_mode(ctx_handoff.get(), 1);

bssl::UniquePtr<SSL> ssl_handoff(SSL_new(ctx_handoff.get()));
bssl::UniquePtr<SSL> ssl_handoff =
NewSSL(ctx_handoff.get(), config, nullptr, false, nullptr);
if (!ssl_handoff) {
return false;
}
@@ -2318,12 +2339,12 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
});
} while (config->async && RetryAsync(ssl, ret));

if (ret != 1 ||
!CheckHandshakeProperties(ssl, is_resume, config)) {
return false;
}

if (config->handoff) {
if (!HandbackReady(ssl, ret)) {
fprintf(stderr, "Connection failed to handback.\n");
return false;
}

bssl::ScopedCBB cbb;
bssl::Array<uint8_t> handback;
if (!CBB_init(cbb.get(), 512) ||
@@ -2333,26 +2354,42 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
return false;
}

bssl::UniquePtr<SSL_CTX> ctx_handback(SSL_CTX_new(TLSv1_method()));
SSL_CTX_set_msg_callback(ctx_handback.get(), MessageCallback);
bssl::UniquePtr<SSL> ssl_handback(SSL_new(ctx_handback.get()));
if (!ssl_handback) {
bssl::UniquePtr<SSL_CTX> ctx_handback = SetupCtx(ssl->ctx, config);
if (!ctx_handback) {
return false;
}
if (!SSL_apply_handback(ssl_handback.get(), handback)) {
fprintf(stderr, "Applying handback failed.\n");
bssl::UniquePtr<SSL> ssl_handback =
NewSSL(ctx_handback.get(), config, nullptr, false, nullptr);
if (!ssl_handback) {
return false;
}

MoveBIOs(ssl_handback.get(), ssl);
if (!MoveExData(ssl_handback.get(), ssl)) {
return false;
}

if (!SSL_apply_handback(ssl_handback.get(), handback)) {
fprintf(stderr, "Applying handback failed.\n");
return false;
}

*ssl_uniqueptr = std::move(ssl_handback);
ssl = ssl_uniqueptr->get();

do {
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;
}

lh_SSL_SESSION_doall_arg(ssl->ctx->sessions, ssl_ctx_add_session,
session_ctx);

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");


Laddar…
Avbryt
Spara