Chromium's renegotiation handling currently relies on reads being the only thing that can discover a renegotiation. However, for a number of reasons, we would like to eagerly drive the read loop after a handshake: - 0-RTT + HTTP/1.1 will otherwise not pick up ServerHellos until after we send a request. In particular, if we preconnect a 0-RTT socket sufficiently in advance, such that the ServerHello comes in by the time we use it, we should send 1-RTT data rather than 0-RTT. - In TLS 1.2 False Start, if HTTP/1.1 or preconnect, we will not pick up the server Finished and NewSessionTicket until later. This way we pick it up sooner. - If the server does not implement https://boringssl-review.googlesource.com/c/boringssl/+/34948, this plugs the theoretical deadlock on the client end. The False Start and 0-RTT scenarios above also have theoretical deadlocks and cannot be mitigated on the server. - TLS 1.3 client certificate alerts interact badly with TCP reset. Eagerly reading from the socket makes it behave slightly better, though it's still not reliable unless the server defers closing the socket. So we can SSL_peek without triggering a renegotiation, add an ssl_renegotiate_explicit mode to defer processing the renegotiation. Bug: chromium:950706, chromium:958638 Change-Id: I78242d93d651b7a32a5c4c24ea9032ef63a027cf Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/37944 Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: Adam Langley <agl@google.com>
86 lines
3.3 KiB
C++
86 lines
3.3 KiB
C++
/* Copyright (c) 2018, 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_TEST_STATE
|
|
#define HEADER_TEST_STATE
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <openssl/base.h>
|
|
|
|
struct TestState {
|
|
// Serialize writes |pending_session| and |msg_callback_text| to |out|, for
|
|
// use in split-handshake tests. We don't try to serialize every bit of test
|
|
// state, but serializing |pending_session| is necessary to exercise session
|
|
// resumption, and |msg_callback_text| is especially useful. In the general
|
|
// case, checks of state updated during the handshake can be skipped when
|
|
// |config->handoff|.
|
|
bool Serialize(CBB *out) const;
|
|
|
|
// Deserialize returns a new |TestState| from data written by |Serialize|.
|
|
static std::unique_ptr<TestState> Deserialize(CBS *cbs, SSL_CTX *ctx);
|
|
|
|
// async_bio is async BIO which pauses reads and writes.
|
|
BIO *async_bio = nullptr;
|
|
// packeted_bio is the packeted BIO which simulates read timeouts.
|
|
BIO *packeted_bio = nullptr;
|
|
bssl::UniquePtr<EVP_PKEY> channel_id;
|
|
bool cert_ready = false;
|
|
bssl::UniquePtr<SSL_SESSION> session;
|
|
bssl::UniquePtr<SSL_SESSION> pending_session;
|
|
bool early_callback_called = false;
|
|
bool handshake_done = false;
|
|
// private_key is the underlying private key used when testing custom keys.
|
|
bssl::UniquePtr<EVP_PKEY> private_key;
|
|
std::vector<uint8_t> private_key_result;
|
|
// private_key_retries is the number of times an asynchronous private key
|
|
// operation has been retried.
|
|
unsigned private_key_retries = 0;
|
|
bool got_new_session = false;
|
|
bssl::UniquePtr<SSL_SESSION> new_session;
|
|
bool ticket_decrypt_done = false;
|
|
bool alpn_select_done = false;
|
|
bool is_resume = false;
|
|
bool early_callback_ready = false;
|
|
bool custom_verify_ready = false;
|
|
std::string msg_callback_text;
|
|
bool msg_callback_ok = true;
|
|
// cert_verified is true if certificate verification has been driven to
|
|
// completion. This tests that the callback is not called again after this.
|
|
bool cert_verified = false;
|
|
int explicit_renegotiates = 0;
|
|
};
|
|
|
|
bool SetTestState(SSL *ssl, std::unique_ptr<TestState> state);
|
|
|
|
TestState *GetTestState(const SSL *ssl);
|
|
|
|
struct timeval *GetClock();
|
|
|
|
void AdvanceClock(unsigned seconds);
|
|
|
|
void CopySessions(SSL_CTX *dest, const SSL_CTX *src);
|
|
|
|
// SerializeContextState writes session material (sessions and ticket keys) from
|
|
// |ctx| into |cbb|.
|
|
bool SerializeContextState(SSL_CTX *ctx, CBB *cbb);
|
|
|
|
// DeserializeContextState updates |out| with material previously serialized by
|
|
// SerializeContextState.
|
|
bool DeserializeContextState(CBS *in, SSL_CTX *out);
|
|
|
|
#endif // HEADER_TEST_STATE
|