diff options
Diffstat (limited to 'src/ssl/ssl_test.cc')
-rw-r--r-- | src/ssl/ssl_test.cc | 1452 |
1 files changed, 554 insertions, 898 deletions
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index 898cd04b..bc89202a 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -49,6 +49,40 @@ OPENSSL_MSVC_PRAGMA(warning(pop)) #endif +namespace bssl { + +namespace { + +#define TRACED_CALL(code) \ + do { \ + SCOPED_TRACE("<- called from here"); \ + code; \ + if (::testing::Test::HasFatalFailure()) { \ + return; \ + } \ + } while (false) + +struct VersionParam { + uint16_t version; + enum { is_tls, is_dtls } ssl_method; + const char name[8]; +}; + +static const size_t kTicketKeyLen = 48; + +static const VersionParam kAllVersions[] = { + {SSL3_VERSION, VersionParam::is_tls, "SSL3"}, + {TLS1_VERSION, VersionParam::is_tls, "TLS1"}, + {TLS1_1_VERSION, VersionParam::is_tls, "TLS1_1"}, + {TLS1_2_VERSION, VersionParam::is_tls, "TLS1_2"}, +// TLS 1.3 requires RSA-PSS, which is disabled for Android system builds. +#if !defined(BORINGSSL_ANDROID_SYSTEM) + {TLS1_3_VERSION, VersionParam::is_tls, "TLS1_3"}, +#endif + {DTLS1_VERSION, VersionParam::is_dtls, "DTLS1"}, + {DTLS1_2_VERSION, VersionParam::is_dtls, "DTLS1_2"}, +}; + struct ExpectedCipher { unsigned long id; int in_group_flag; @@ -1473,148 +1507,130 @@ static bool ConnectClientAndServer(bssl::UniquePtr<SSL> *out_client, return true; } -static bool TestSequenceNumber(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method)); - bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)); - if (!server_ctx || !client_ctx || - !SSL_CTX_set_min_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_min_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) { - return false; +/* SSLVersionTest executes its test cases under all available protocol versions. + * Test cases call |Connect| to create a connection using context objects with + * the protocol version fixed to the current version under test. */ +class SSLVersionTest : public ::testing::TestWithParam<VersionParam> { + protected: + SSLVersionTest() : cert_(GetTestCertificate()), key_(GetTestKey()) {} + + void SetUp() { ResetContexts(); } + + bssl::UniquePtr<SSL_CTX> CreateContext() const { + const SSL_METHOD *method = is_dtls() ? DTLS_method() : TLS_method(); + bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method)); + if (!ctx || !SSL_CTX_set_min_proto_version(ctx.get(), version()) || + !SSL_CTX_set_max_proto_version(ctx.get(), version())) { + return nullptr; + } + return ctx; } - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!cert || !key || !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) { - return false; + void ResetContexts() { + ASSERT_TRUE(cert_); + ASSERT_TRUE(key_); + client_ctx_ = CreateContext(); + ASSERT_TRUE(client_ctx_); + server_ctx_ = CreateContext(); + ASSERT_TRUE(server_ctx_); + // Set up a server cert. Client certs can be set up explicitly. + ASSERT_TRUE(UseCertAndKey(server_ctx_.get())); } - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, client_ctx.get(), - server_ctx.get(), nullptr /* no session */)) { - return false; + bool UseCertAndKey(SSL_CTX *ctx) const { + return SSL_CTX_use_certificate(ctx, cert_.get()) && + SSL_CTX_use_PrivateKey(ctx, key_.get()); + } + + bool Connect() { + return ConnectClientAndServer(&client_, &server_, client_ctx_.get(), + server_ctx_.get(), nullptr /* no session */); + } + + uint16_t version() const { return GetParam().version; } + + bool is_dtls() const { + return GetParam().ssl_method == VersionParam::is_dtls; } + bssl::UniquePtr<SSL> client_, server_; + bssl::UniquePtr<SSL_CTX> server_ctx_, client_ctx_; + bssl::UniquePtr<X509> cert_; + bssl::UniquePtr<EVP_PKEY> key_; +}; + +INSTANTIATE_TEST_CASE_P(WithVersion, SSLVersionTest, + testing::ValuesIn(kAllVersions), + [](const testing::TestParamInfo<VersionParam> &i) { + return i.param.name; + }); + +TEST_P(SSLVersionTest, SequenceNumber) { + ASSERT_TRUE(Connect()); + // Drain any post-handshake messages to ensure there are no unread records // on either end. uint8_t byte = 0; - if (SSL_read(client.get(), &byte, 1) > 0 || - SSL_read(server.get(), &byte, 1) > 0) { - fprintf(stderr, "Received unexpected data.\n"); - return false; - } + ASSERT_LE(SSL_read(client_.get(), &byte, 1), 0); + ASSERT_LE(SSL_read(server_.get(), &byte, 1), 0); - uint64_t client_read_seq = SSL_get_read_sequence(client.get()); - uint64_t client_write_seq = SSL_get_write_sequence(client.get()); - uint64_t server_read_seq = SSL_get_read_sequence(server.get()); - uint64_t server_write_seq = SSL_get_write_sequence(server.get()); + uint64_t client_read_seq = SSL_get_read_sequence(client_.get()); + uint64_t client_write_seq = SSL_get_write_sequence(client_.get()); + uint64_t server_read_seq = SSL_get_read_sequence(server_.get()); + uint64_t server_write_seq = SSL_get_write_sequence(server_.get()); - if (is_dtls) { + if (is_dtls()) { // Both client and server must be at epoch 1. - if (EpochFromSequence(client_read_seq) != 1 || - EpochFromSequence(client_write_seq) != 1 || - EpochFromSequence(server_read_seq) != 1 || - EpochFromSequence(server_write_seq) != 1) { - fprintf(stderr, "Bad epochs.\n"); - return false; - } + EXPECT_EQ(EpochFromSequence(client_read_seq), 1); + EXPECT_EQ(EpochFromSequence(client_write_seq), 1); + EXPECT_EQ(EpochFromSequence(server_read_seq), 1); + EXPECT_EQ(EpochFromSequence(server_write_seq), 1); // The next record to be written should exceed the largest received. - if (client_write_seq <= server_read_seq || - server_write_seq <= client_read_seq) { - fprintf(stderr, "Inconsistent sequence numbers.\n"); - return false; - } + EXPECT_GT(client_write_seq, server_read_seq); + EXPECT_GT(server_write_seq, client_read_seq); } else { // The next record to be written should equal the next to be received. - if (client_write_seq != server_read_seq || - server_write_seq != client_read_seq) { - fprintf(stderr, "Inconsistent sequence numbers.\n"); - return false; - } + EXPECT_EQ(client_write_seq, server_read_seq); + EXPECT_EQ(server_write_seq, client_read_seq); } // Send a record from client to server. - if (SSL_write(client.get(), &byte, 1) != 1 || - SSL_read(server.get(), &byte, 1) != 1) { - fprintf(stderr, "Could not send byte.\n"); - return false; - } + EXPECT_EQ(SSL_write(client_.get(), &byte, 1), 1); + EXPECT_EQ(SSL_read(server_.get(), &byte, 1), 1); // The client write and server read sequence numbers should have // incremented. - if (client_write_seq + 1 != SSL_get_write_sequence(client.get()) || - server_read_seq + 1 != SSL_get_read_sequence(server.get())) { - fprintf(stderr, "Sequence numbers did not increment.\n"); - return false; - } - - return true; + EXPECT_EQ(client_write_seq + 1, SSL_get_write_sequence(client_.get())); + EXPECT_EQ(server_read_seq + 1, SSL_get_read_sequence(server_.get())); } -static bool TestOneSidedShutdown(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { +TEST_P(SSLVersionTest, OneSidedShutdown) { // SSL_shutdown is a no-op in DTLS. - if (is_dtls) { - return true; - } - - bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method)); - bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)); - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!client_ctx || !server_ctx || !cert || !key || - !SSL_CTX_set_min_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_min_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(client_ctx.get(), version) || - !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) { - return false; - } - - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, client_ctx.get(), - server_ctx.get(), nullptr /* no session */)) { - return false; + if (is_dtls()) { + return; } + ASSERT_TRUE(Connect()); // Shut down half the connection. SSL_shutdown will return 0 to signal only // one side has shut down. - if (SSL_shutdown(client.get()) != 0) { - fprintf(stderr, "Could not shutdown.\n"); - return false; - } + ASSERT_EQ(SSL_shutdown(client_.get()), 0); // Reading from the server should consume the EOF. uint8_t byte; - if (SSL_read(server.get(), &byte, 1) != 0 || - SSL_get_error(server.get(), 0) != SSL_ERROR_ZERO_RETURN) { - fprintf(stderr, "Connection was not shut down cleanly.\n"); - return false; - } + ASSERT_EQ(SSL_read(server_.get(), &byte, 1), 0); + ASSERT_EQ(SSL_get_error(server_.get(), 0), SSL_ERROR_ZERO_RETURN); // However, the server may continue to write data and then shut down the // connection. byte = 42; - if (SSL_write(server.get(), &byte, 1) != 1 || - SSL_read(client.get(), &byte, 1) != 1 || - byte != 42) { - fprintf(stderr, "Could not send byte.\n"); - return false; - } + ASSERT_EQ(SSL_write(server_.get(), &byte, 1), 1); + ASSERT_EQ(SSL_read(client_.get(), &byte, 1), 1); + ASSERT_EQ(byte, 42); // The server may then shutdown the connection. - if (SSL_shutdown(server.get()) != 1 || - SSL_shutdown(client.get()) != 1) { - fprintf(stderr, "Could not complete shutdown.\n"); - return false; - } - - return true; + EXPECT_EQ(SSL_shutdown(server_.get()), 1); + EXPECT_EQ(SSL_shutdown(client_.get()), 1); } TEST(SSLTest, SessionDuplication) { @@ -1786,164 +1802,87 @@ TEST(SSLTest, SetBIO) { static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) { return 1; } -static bool TestGetPeerCertificate(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!cert || !key) { - return false; - } +TEST_P(SSLVersionTest, GetPeerCertificate) { + ASSERT_TRUE(UseCertAndKey(client_ctx_.get())); // Configure both client and server to accept any certificate. - bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method)); - if (!ctx || - !SSL_CTX_use_certificate(ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(ctx.get(), version) || - !SSL_CTX_set_max_proto_version(ctx.get(), version)) { - return false; - } - SSL_CTX_set_verify( - ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); - SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL); + SSL_CTX_set_verify(client_ctx_.get(), + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + nullptr); + SSL_CTX_set_cert_verify_callback(client_ctx_.get(), VerifySucceed, NULL); + SSL_CTX_set_verify(server_ctx_.get(), + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + nullptr); + SSL_CTX_set_cert_verify_callback(server_ctx_.get(), VerifySucceed, NULL); - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(), - nullptr /* no session */)) { - return false; - } + ASSERT_TRUE(Connect()); // Client and server should both see the leaf certificate. - bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get())); - if (!peer || X509_cmp(cert.get(), peer.get()) != 0) { - fprintf(stderr, "Server peer certificate did not match.\n"); - return false; - } + bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server_.get())); + ASSERT_TRUE(peer); + ASSERT_EQ(X509_cmp(cert_.get(), peer.get()), 0); - peer.reset(SSL_get_peer_certificate(client.get())); - if (!peer || X509_cmp(cert.get(), peer.get()) != 0) { - fprintf(stderr, "Client peer certificate did not match.\n"); - return false; - } + peer.reset(SSL_get_peer_certificate(client_.get())); + ASSERT_TRUE(peer); + ASSERT_EQ(X509_cmp(cert_.get(), peer.get()), 0); // However, for historical reasons, the X509 chain includes the leaf on the // client, but does not on the server. - if (sk_X509_num(SSL_get_peer_cert_chain(client.get())) != 1 || - sk_CRYPTO_BUFFER_num(SSL_get0_peer_certificates(client.get())) != 1) { - fprintf(stderr, "Client peer chain was incorrect.\n"); - return false; - } - - if (sk_X509_num(SSL_get_peer_cert_chain(server.get())) != 0 || - sk_CRYPTO_BUFFER_num(SSL_get0_peer_certificates(server.get())) != 1) { - fprintf(stderr, "Server peer chain was incorrect.\n"); - return false; - } + EXPECT_EQ(sk_X509_num(SSL_get_peer_cert_chain(client_.get())), 1u); + EXPECT_EQ(sk_CRYPTO_BUFFER_num(SSL_get0_peer_certificates(client_.get())), + 1u); - return true; + EXPECT_EQ(sk_X509_num(SSL_get_peer_cert_chain(server_.get())), 0u); + EXPECT_EQ(sk_CRYPTO_BUFFER_num(SSL_get0_peer_certificates(server_.get())), + 1u); } -static bool TestNoPeerCertificate(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!cert || !key) { - return false; - } - - // Configure an anonymous client. - bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)), - client_ctx(SSL_CTX_new(method)); - if (!server_ctx || !client_ctx || - !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_min_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(client_ctx.get(), version)) { - return false; - } - SSL_CTX_set_verify( - server_ctx.get(), SSL_VERIFY_PEER, nullptr); - SSL_CTX_set_cert_verify_callback(server_ctx.get(), VerifySucceed, NULL); - SSL_CTX_set_cert_verify_callback(client_ctx.get(), VerifySucceed, NULL); - - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, client_ctx.get(), - server_ctx.get(), nullptr /* no session */)) { - return false; - } +TEST_P(SSLVersionTest, NoPeerCertificate) { + SSL_CTX_set_verify(server_ctx_.get(), SSL_VERIFY_PEER, nullptr); + SSL_CTX_set_cert_verify_callback(server_ctx_.get(), VerifySucceed, NULL); + SSL_CTX_set_cert_verify_callback(client_ctx_.get(), VerifySucceed, NULL); - // Client and server should both see the leaf certificate. - bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get())); - if (peer || - SSL_get0_peer_certificates(server.get()) != nullptr) { - fprintf(stderr, "Server peer certificate was non-null.\n"); - return false; - } + ASSERT_TRUE(Connect()); - return true; + // Server should not see a peer certificate. + bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server_.get())); + ASSERT_FALSE(peer); + ASSERT_FALSE(SSL_get0_peer_certificates(server_.get())); } -static bool TestRetainOnlySHA256OfCerts(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!cert || !key) { - return false; - } - +TEST_P(SSLVersionTest, RetainOnlySHA256OfCerts) { uint8_t *cert_der = NULL; - int cert_der_len = i2d_X509(cert.get(), &cert_der); - if (cert_der_len < 0) { - return false; - } + int cert_der_len = i2d_X509(cert_.get(), &cert_der); + ASSERT_GE(cert_der_len, 0); bssl::UniquePtr<uint8_t> free_cert_der(cert_der); uint8_t cert_sha256[SHA256_DIGEST_LENGTH]; SHA256(cert_der, cert_der_len, cert_sha256); + ASSERT_TRUE(UseCertAndKey(client_ctx_.get())); + // Configure both client and server to accept any certificate, but the // server must retain only the SHA-256 of the peer. - bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method)); - if (!ctx || - !SSL_CTX_use_certificate(ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(ctx.get(), version) || - !SSL_CTX_set_max_proto_version(ctx.get(), version)) { - return false; - } - SSL_CTX_set_verify( - ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); - SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL); - SSL_CTX_set_retain_only_sha256_of_client_certs(ctx.get(), 1); - - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(), - nullptr /* no session */)) { - return false; - } + SSL_CTX_set_verify(client_ctx_.get(), + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + nullptr); + SSL_CTX_set_verify(server_ctx_.get(), + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + nullptr); + SSL_CTX_set_cert_verify_callback(client_ctx_.get(), VerifySucceed, NULL); + SSL_CTX_set_cert_verify_callback(server_ctx_.get(), VerifySucceed, NULL); + SSL_CTX_set_retain_only_sha256_of_client_certs(server_ctx_.get(), 1); + + ASSERT_TRUE(Connect()); // The peer certificate has been dropped. - bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get())); - if (peer) { - fprintf(stderr, "Peer certificate was retained.\n"); - return false; - } - - SSL_SESSION *session = SSL_get_session(server.get()); - if (!session->peer_sha256_valid) { - fprintf(stderr, "peer_sha256_valid was not set.\n"); - return false; - } + bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server_.get())); + EXPECT_FALSE(peer); - if (OPENSSL_memcmp(cert_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH) != - 0) { - fprintf(stderr, "peer_sha256 did not match.\n"); - return false; - } + SSL_SESSION *session = SSL_get_session(server_.get()); + EXPECT_TRUE(session->peer_sha256_valid); - return true; + EXPECT_EQ(Bytes(cert_sha256), Bytes(session->peer_sha256)); } static bool ClientHelloMatches(uint16_t version, const uint8_t *expected, @@ -2172,29 +2111,16 @@ static bssl::UniquePtr<SSL_SESSION> CreateClientSession(SSL_CTX *client_ctx, return std::move(g_last_session); } -static bool ExpectSessionReused(SSL_CTX *client_ctx, SSL_CTX *server_ctx, - SSL_SESSION *session, - bool reused) { +static void ExpectSessionReused(SSL_CTX *client_ctx, SSL_CTX *server_ctx, + SSL_SESSION *session, bool want_reused) { bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, client_ctx, - server_ctx, session)) { - fprintf(stderr, "Failed to connect client and server.\n"); - return false; - } + EXPECT_TRUE(ConnectClientAndServer(&client, &server, client_ctx, server_ctx, + session)); - if (SSL_session_reused(client.get()) != SSL_session_reused(server.get())) { - fprintf(stderr, "Client and server were inconsistent.\n"); - return false; - } + EXPECT_EQ(SSL_session_reused(client.get()), SSL_session_reused(server.get())); bool was_reused = !!SSL_session_reused(client.get()); - if (was_reused != reused) { - fprintf(stderr, "Session was%s reused, but we expected the opposite.\n", - was_reused ? "" : " not"); - return false; - } - - return true; + EXPECT_EQ(was_reused, want_reused); } static bssl::UniquePtr<SSL_SESSION> ExpectSessionRenewed(SSL_CTX *client_ctx, @@ -2232,6 +2158,19 @@ static bssl::UniquePtr<SSL_SESSION> ExpectSessionRenewed(SSL_CTX *client_ctx, return std::move(g_last_session); } +static void ExpectTicketKeyChanged(SSL_CTX *ctx, uint8_t *inout_key, + bool changed) { + uint8_t new_key[kTicketKeyLen]; + /* May return 0, 1 or 48. */ + ASSERT_EQ(SSL_CTX_get_tlsext_ticket_keys(ctx, new_key, kTicketKeyLen), 1); + if (changed) { + ASSERT_NE(Bytes(inout_key, kTicketKeyLen), Bytes(new_key)); + } else { + ASSERT_EQ(Bytes(inout_key, kTicketKeyLen), Bytes(new_key)); + } + OPENSSL_memcpy(inout_key, new_key, kTicketKeyLen); +} + static int SwitchSessionIDContextSNI(SSL *ssl, int *out_alert, void *arg) { static const uint8_t kContext[] = {3}; @@ -2242,79 +2181,48 @@ static int SwitchSessionIDContextSNI(SSL *ssl, int *out_alert, void *arg) { return SSL_TLSEXT_ERR_OK; } -static bool TestSessionIDContext(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!cert || !key) { - return false; - } - +TEST_P(SSLVersionTest, SessionIDContext) { static const uint8_t kContext1[] = {1}; static const uint8_t kContext2[] = {2}; - bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)); - bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method)); - if (!server_ctx || !client_ctx || - !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) || - !SSL_CTX_set_session_id_context(server_ctx.get(), kContext1, - sizeof(kContext1)) || - !SSL_CTX_set_min_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_min_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) { - return false; - } + ASSERT_TRUE(SSL_CTX_set_session_id_context(server_ctx_.get(), kContext1, + sizeof(kContext1))); - SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH); - SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH); + SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH); + SSL_CTX_set_session_cache_mode(server_ctx_.get(), SSL_SESS_CACHE_BOTH); bssl::UniquePtr<SSL_SESSION> session = - CreateClientSession(client_ctx.get(), server_ctx.get()); - if (!session) { - fprintf(stderr, "Error getting session.\n"); - return false; - } + CreateClientSession(client_ctx_.get(), server_ctx_.get()); + ASSERT_TRUE(session); - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(), - true /* expect session reused */)) { - fprintf(stderr, "Error resuming session.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), + true /* expect session reused */)); // Change the session ID context. - if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext2, - sizeof(kContext2))) { - return false; - } + ASSERT_TRUE(SSL_CTX_set_session_id_context(server_ctx_.get(), kContext2, + sizeof(kContext2))); - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(), - false /* expect session not reused */)) { - fprintf(stderr, "Error connecting with a different context.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), + false /* expect session not reused */)); // Change the session ID context back and install an SNI callback to switch // it. - if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext1, - sizeof(kContext1))) { - return false; - } + ASSERT_TRUE(SSL_CTX_set_session_id_context(server_ctx_.get(), kContext1, + sizeof(kContext1))); - SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), + SSL_CTX_set_tlsext_servername_callback(server_ctx_.get(), SwitchSessionIDContextSNI); - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(), - false /* expect session not reused */)) { - fprintf(stderr, "Error connecting with a context switch on SNI callback.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), + false /* expect session not reused */)); // Switch the session ID context with the early callback instead. - SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), nullptr); + SSL_CTX_set_tlsext_servername_callback(server_ctx_.get(), nullptr); SSL_CTX_set_select_certificate_cb( - server_ctx.get(), + server_ctx_.get(), [](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t { static const uint8_t kContext[] = {3}; @@ -2326,14 +2234,9 @@ static bool TestSessionIDContext(bool is_dtls, const SSL_METHOD *method, return ssl_select_cert_success; }); - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(), - false /* expect session not reused */)) { - fprintf(stderr, - "Error connecting with a context switch on early callback.\n"); - return false; - } - - return true; + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), + false /* expect session not reused */)); } static timeval g_current_time; @@ -2409,142 +2312,99 @@ static bool GetServerTicketTime(long *out, const SSL_SESSION *session) { return true; } -static bool TestSessionTimeout(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!cert || !key) { - return false; - } +TEST_P(SSLVersionTest, SessionTimeout) { + for (bool server_test : {false, true}) { + SCOPED_TRACE(server_test); + + ResetContexts(); + SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH); + SSL_CTX_set_session_cache_mode(server_ctx_.get(), SSL_SESS_CACHE_BOTH); - for (bool server_test : std::vector<bool>{false, true}) { static const time_t kStartTime = 1000; g_current_time.tv_sec = kStartTime; // We are willing to use a longer lifetime for TLS 1.3 sessions as // resumptions still perform ECDHE. - const time_t timeout = version == TLS1_3_VERSION + const time_t timeout = version() == TLS1_3_VERSION ? SSL_DEFAULT_SESSION_PSK_DHE_TIMEOUT : SSL_DEFAULT_SESSION_TIMEOUT; - bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)); - bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method)); - if (!server_ctx || !client_ctx || - !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_min_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) { - return false; - } - - SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH); - SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH); - // Both client and server must enforce session timeouts. We configure the // other side with a frozen clock so it never expires tickets. if (server_test) { - SSL_CTX_set_current_time_cb(client_ctx.get(), FrozenTimeCallback); - SSL_CTX_set_current_time_cb(server_ctx.get(), CurrentTimeCallback); + SSL_CTX_set_current_time_cb(client_ctx_.get(), FrozenTimeCallback); + SSL_CTX_set_current_time_cb(server_ctx_.get(), CurrentTimeCallback); } else { - SSL_CTX_set_current_time_cb(client_ctx.get(), CurrentTimeCallback); - SSL_CTX_set_current_time_cb(server_ctx.get(), FrozenTimeCallback); + SSL_CTX_set_current_time_cb(client_ctx_.get(), CurrentTimeCallback); + SSL_CTX_set_current_time_cb(server_ctx_.get(), FrozenTimeCallback); } // Configure a ticket callback which renews tickets. - SSL_CTX_set_tlsext_ticket_key_cb(server_ctx.get(), RenewTicketCallback); + SSL_CTX_set_tlsext_ticket_key_cb(server_ctx_.get(), RenewTicketCallback); bssl::UniquePtr<SSL_SESSION> session = - CreateClientSession(client_ctx.get(), server_ctx.get()); - if (!session) { - fprintf(stderr, "Error getting session.\n"); - return false; - } + CreateClientSession(client_ctx_.get(), server_ctx_.get()); + ASSERT_TRUE(session); // Advance the clock just behind the timeout. g_current_time.tv_sec += timeout - 1; - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(), - true /* expect session reused */)) { - fprintf(stderr, "Error resuming session.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), + true /* expect session reused */)); // Advance the clock one more second. g_current_time.tv_sec++; - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(), - false /* expect session not reused */)) { - fprintf(stderr, "Error resuming session.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), + false /* expect session not reused */)); // Rewind the clock to before the session was minted. g_current_time.tv_sec = kStartTime - 1; - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(), - false /* expect session not reused */)) { - fprintf(stderr, "Error resuming session.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), + false /* expect session not reused */)); // SSL 3.0 cannot renew sessions. - if (version == SSL3_VERSION) { + if (version() == SSL3_VERSION) { continue; } // Renew the session 10 seconds before expiration. time_t new_start_time = kStartTime + timeout - 10; g_current_time.tv_sec = new_start_time; - bssl::UniquePtr<SSL_SESSION> new_session = - ExpectSessionRenewed(client_ctx.get(), server_ctx.get(), session.get()); - if (!new_session) { - fprintf(stderr, "Error renewing session.\n"); - return false; - } + bssl::UniquePtr<SSL_SESSION> new_session = ExpectSessionRenewed( + client_ctx_.get(), server_ctx_.get(), session.get()); + ASSERT_TRUE(new_session); // This new session is not the same object as before. - if (session.get() == new_session.get()) { - fprintf(stderr, "New and old sessions alias.\n"); - return false; - } + EXPECT_NE(session.get(), new_session.get()); // Check the sessions have timestamps measured from issuance. long session_time = 0; if (server_test) { - if (!GetServerTicketTime(&session_time, new_session.get())) { - fprintf(stderr, "Failed to decode session ticket.\n"); - return false; - } + ASSERT_TRUE(GetServerTicketTime(&session_time, new_session.get())); } else { session_time = new_session->time; } - if (session_time != g_current_time.tv_sec) { - fprintf(stderr, "New session is not measured from issuance.\n"); - return false; - } + ASSERT_EQ(session_time, g_current_time.tv_sec); - if (version == TLS1_3_VERSION) { + if (version() == TLS1_3_VERSION) { // Renewal incorporates fresh key material in TLS 1.3, so we extend the // lifetime TLS 1.3. g_current_time.tv_sec = new_start_time + timeout - 1; - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), - new_session.get(), - true /* expect session reused */)) { - fprintf(stderr, "Error resuming renewed session.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + new_session.get(), + true /* expect session reused */)); // The new session expires after the new timeout. g_current_time.tv_sec = new_start_time + timeout + 1; - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), - new_session.get(), - false /* expect session ot reused */)) { - fprintf(stderr, "Renewed session's lifetime is too long.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + new_session.get(), + false /* expect session ot reused */)); // Renew the session until it begins just past the auth timeout. time_t auth_end_time = kStartTime + SSL_DEFAULT_SESSION_AUTH_TIMEOUT; @@ -2553,75 +2413,129 @@ static bool TestSessionTimeout(bool is_dtls, const SSL_METHOD *method, new_start_time = std::min(auth_end_time - 1000, new_start_time + timeout - 1); g_current_time.tv_sec = new_start_time; - new_session = ExpectSessionRenewed(client_ctx.get(), server_ctx.get(), + new_session = ExpectSessionRenewed(client_ctx_.get(), server_ctx_.get(), new_session.get()); - if (!new_session) { - fprintf(stderr, "Error renewing session.\n"); - return false; - } + ASSERT_TRUE(new_session); } // Now the session's lifetime is bound by the auth timeout. g_current_time.tv_sec = auth_end_time - 1; - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), - new_session.get(), - true /* expect session reused */)) { - fprintf(stderr, "Error resuming renewed session.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + new_session.get(), + true /* expect session reused */)); g_current_time.tv_sec = auth_end_time + 1; - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), - new_session.get(), - false /* expect session ot reused */)) { - fprintf(stderr, "Renewed session's lifetime is too long.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + new_session.get(), + false /* expect session ot reused */)); } else { // The new session is usable just before the old expiration. g_current_time.tv_sec = kStartTime + timeout - 1; - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), - new_session.get(), - true /* expect session reused */)) { - fprintf(stderr, "Error resuming renewed session.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + new_session.get(), + true /* expect session reused */)); // Renewal does not extend the lifetime, so it is not usable beyond the // old expiration. g_current_time.tv_sec = kStartTime + timeout + 1; - if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), - new_session.get(), - false /* expect session not reused */)) { - fprintf(stderr, "Renewed session's lifetime is too long.\n"); - return false; - } + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + new_session.get(), + false /* expect session not reused */)); } } +} - return true; +TEST_P(SSLVersionTest, DefaultTicketKeyInitialization) { + static const uint8_t kZeroKey[kTicketKeyLen] = {}; + uint8_t ticket_key[kTicketKeyLen]; + ASSERT_EQ(1, SSL_CTX_get_tlsext_ticket_keys(server_ctx_.get(), ticket_key, + kTicketKeyLen)); + ASSERT_NE(0, OPENSSL_memcmp(ticket_key, kZeroKey, kTicketKeyLen)); +} + +TEST_P(SSLVersionTest, DefaultTicketKeyRotation) { + if (GetParam().version == SSL3_VERSION) { + return; + } + + static const time_t kStartTime = 1001; + g_current_time.tv_sec = kStartTime; + uint8_t ticket_key[kTicketKeyLen]; + + /* We use session reuse as a proxy for ticket decryption success, hence + * disable session timeouts. */ + SSL_CTX_set_timeout(server_ctx_.get(), std::numeric_limits<uint32_t>::max()); + SSL_CTX_set_session_psk_dhe_timeout(server_ctx_.get(), + std::numeric_limits<uint32_t>::max()); + + SSL_CTX_set_current_time_cb(client_ctx_.get(), FrozenTimeCallback); + SSL_CTX_set_current_time_cb(server_ctx_.get(), CurrentTimeCallback); + + SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH); + SSL_CTX_set_session_cache_mode(server_ctx_.get(), SSL_SESS_CACHE_OFF); + + /* Initialize ticket_key with the current key. */ + TRACED_CALL(ExpectTicketKeyChanged(server_ctx_.get(), ticket_key, + true /* changed */)); + + /* Verify ticket resumption actually works. */ + bssl::UniquePtr<SSL> client, server; + bssl::UniquePtr<SSL_SESSION> session = + CreateClientSession(client_ctx_.get(), server_ctx_.get()); + ASSERT_TRUE(session); + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), true /* reused */)); + + /* Advance time to just before key rotation. */ + g_current_time.tv_sec += SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL - 1; + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), true /* reused */)); + TRACED_CALL(ExpectTicketKeyChanged(server_ctx_.get(), ticket_key, + false /* NOT changed */)); + + /* Force key rotation. */ + g_current_time.tv_sec += 1; + bssl::UniquePtr<SSL_SESSION> new_session = + CreateClientSession(client_ctx_.get(), server_ctx_.get()); + TRACED_CALL(ExpectTicketKeyChanged(server_ctx_.get(), ticket_key, + true /* changed */)); + + /* Resumption with both old and new ticket should work. */ + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), true /* reused */)); + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + new_session.get(), true /* reused */)); + TRACED_CALL(ExpectTicketKeyChanged(server_ctx_.get(), ticket_key, + false /* NOT changed */)); + + /* Force key rotation again. Resumption with the old ticket now fails. */ + g_current_time.tv_sec += SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL; + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + session.get(), false /* NOT reused */)); + TRACED_CALL(ExpectTicketKeyChanged(server_ctx_.get(), ticket_key, + true /* changed */)); + + /* But resumption with the newer session still works. */ + TRACED_CALL(ExpectSessionReused(client_ctx_.get(), server_ctx_.get(), + new_session.get(), true /* reused */)); } static int SwitchContext(SSL *ssl, int *out_alert, void *arg) { - SSL_CTX *ctx = reinterpret_cast<SSL_CTX*>(arg); + SSL_CTX *ctx = reinterpret_cast<SSL_CTX *>(arg); SSL_set_SSL_CTX(ssl, ctx); return SSL_TLSEXT_ERR_OK; } -static bool TestSNICallback(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { +TEST_P(SSLVersionTest, SNICallback) { // SSL 3.0 lacks extensions. - if (version == SSL3_VERSION) { - return true; + if (version() == SSL3_VERSION) { + return; } - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); bssl::UniquePtr<X509> cert2 = GetECDSATestCertificate(); + ASSERT_TRUE(cert2); bssl::UniquePtr<EVP_PKEY> key2 = GetECDSATestKey(); - if (!cert || !key || !cert2 || !key2) { - return false; - } + ASSERT_TRUE(key2); // Test that switching the |SSL_CTX| at the SNI callback behaves correctly. static const uint16_t kECDSAWithSHA256 = SSL_SIGN_ECDSA_SECP256R1_SHA256; @@ -2629,70 +2543,43 @@ static bool TestSNICallback(bool is_dtls, const SSL_METHOD *method, static const uint8_t kSCTList[] = {0, 6, 0, 4, 5, 6, 7, 8}; static const uint8_t kOCSPResponse[] = {1, 2, 3, 4}; - bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)); - bssl::UniquePtr<SSL_CTX> server_ctx2(SSL_CTX_new(method)); - bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method)); - if (!server_ctx || !server_ctx2 || !client_ctx || - !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) || - !SSL_CTX_use_certificate(server_ctx2.get(), cert2.get()) || - !SSL_CTX_use_PrivateKey(server_ctx2.get(), key2.get()) || - !SSL_CTX_set_signed_cert_timestamp_list(server_ctx2.get(), kSCTList, - sizeof(kSCTList)) || - !SSL_CTX_set_ocsp_response(server_ctx2.get(), kOCSPResponse, - sizeof(kOCSPResponse)) || - // Historically signing preferences would be lost in some cases with the - // SNI callback, which triggers the TLS 1.2 SHA-1 default. To ensure - // this doesn't happen when |version| is TLS 1.2, configure the private - // key to only sign SHA-256. - !SSL_CTX_set_signing_algorithm_prefs(server_ctx2.get(), &kECDSAWithSHA256, - 1) || - !SSL_CTX_set_min_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_min_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_min_proto_version(server_ctx2.get(), version) || - !SSL_CTX_set_max_proto_version(server_ctx2.get(), version)) { - return false; - } - - SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), SwitchContext); - SSL_CTX_set_tlsext_servername_arg(server_ctx.get(), server_ctx2.get()); - - SSL_CTX_enable_signed_cert_timestamps(client_ctx.get()); - SSL_CTX_enable_ocsp_stapling(client_ctx.get()); - - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, client_ctx.get(), - server_ctx.get(), nullptr)) { - fprintf(stderr, "Handshake failed.\n"); - return false; - } + bssl::UniquePtr<SSL_CTX> server_ctx2 = CreateContext(); + ASSERT_TRUE(server_ctx2); + ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx2.get(), cert2.get())); + ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx2.get(), key2.get())); + ASSERT_TRUE(SSL_CTX_set_signed_cert_timestamp_list( + server_ctx2.get(), kSCTList, sizeof(kSCTList))); + ASSERT_TRUE(SSL_CTX_set_ocsp_response(server_ctx2.get(), kOCSPResponse, + sizeof(kOCSPResponse))); + // Historically signing preferences would be lost in some cases with the + // SNI callback, which triggers the TLS 1.2 SHA-1 default. To ensure + // this doesn't happen when |version| is TLS 1.2, configure the private + // key to only sign SHA-256. + ASSERT_TRUE(SSL_CTX_set_signing_algorithm_prefs(server_ctx2.get(), + &kECDSAWithSHA256, 1)); + + SSL_CTX_set_tlsext_servername_callback(server_ctx_.get(), SwitchContext); + SSL_CTX_set_tlsext_servername_arg(server_ctx_.get(), server_ctx2.get()); + + SSL_CTX_enable_signed_cert_timestamps(client_ctx_.get()); + SSL_CTX_enable_ocsp_stapling(client_ctx_.get()); + + ASSERT_TRUE(Connect()); // The client should have received |cert2|. - bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(client.get())); - if (!peer || X509_cmp(peer.get(), cert2.get()) != 0) { - fprintf(stderr, "Incorrect certificate received.\n"); - return false; - } + bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(client_.get())); + ASSERT_TRUE(peer); + EXPECT_EQ(X509_cmp(peer.get(), cert2.get()), 0); // The client should have received |server_ctx2|'s SCT list. const uint8_t *data; size_t len; - SSL_get0_signed_cert_timestamp_list(client.get(), &data, &len); - if (Bytes(kSCTList) != Bytes(data, len)) { - fprintf(stderr, "Incorrect SCT list received.\n"); - return false; - } + SSL_get0_signed_cert_timestamp_list(client_.get(), &data, &len); + EXPECT_EQ(Bytes(kSCTList), Bytes(data, len)); // The client should have received |server_ctx2|'s OCSP response. - SSL_get0_ocsp_response(client.get(), &data, &len); - if (Bytes(kOCSPResponse) != Bytes(data, len)) { - fprintf(stderr, "Incorrect OCSP response received.\n"); - return false; - } - - return true; + SSL_get0_ocsp_response(client_.get(), &data, &len); + EXPECT_EQ(Bytes(kOCSPResponse), Bytes(data, len)); } // Test that the early callback can swap the maximum version. @@ -2804,95 +2691,46 @@ static const char *GetVersionName(uint16_t version) { } } -static bool TestVersion(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!cert || !key) { - return false; - } - - bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)); - bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method)); - bssl::UniquePtr<SSL> client, server; - if (!server_ctx || !client_ctx || - !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_min_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(server_ctx.get(), version) || - !ConnectClientAndServer(&client, &server, client_ctx.get(), - server_ctx.get(), nullptr /* no session */)) { - fprintf(stderr, "Failed to connect.\n"); - return false; - } +TEST_P(SSLVersionTest, Version) { + ASSERT_TRUE(Connect()); - if (SSL_version(client.get()) != version || - SSL_version(server.get()) != version) { - fprintf(stderr, "Version mismatch. Got %04x and %04x, wanted %04x.\n", - SSL_version(client.get()), SSL_version(server.get()), version); - return false; - } + EXPECT_EQ(SSL_version(client_.get()), version()); + EXPECT_EQ(SSL_version(server_.get()), version()); // Test the version name is reported as expected. - const char *version_name = GetVersionName(version); - if (strcmp(version_name, SSL_get_version(client.get())) != 0 || - strcmp(version_name, SSL_get_version(server.get())) != 0) { - fprintf(stderr, "Version name mismatch. Got '%s' and '%s', wanted '%s'.\n", - SSL_get_version(client.get()), SSL_get_version(server.get()), - version_name); - return false; - } + const char *version_name = GetVersionName(version()); + EXPECT_EQ(strcmp(version_name, SSL_get_version(client_.get())), 0); + EXPECT_EQ(strcmp(version_name, SSL_get_version(server_.get())), 0); // Test SSL_SESSION reports the same name. const char *client_name = - SSL_SESSION_get_version(SSL_get_session(client.get())); + SSL_SESSION_get_version(SSL_get_session(client_.get())); const char *server_name = - SSL_SESSION_get_version(SSL_get_session(server.get())); - if (strcmp(version_name, client_name) != 0 || - strcmp(version_name, server_name) != 0) { - fprintf(stderr, - "Session version name mismatch. Got '%s' and '%s', wanted '%s'.\n", - client_name, server_name, version_name); - return false; - } - - return true; + SSL_SESSION_get_version(SSL_get_session(server_.get())); + EXPECT_EQ(strcmp(version_name, client_name), 0); + EXPECT_EQ(strcmp(version_name, server_name), 0); } // Tests that that |SSL_get_pending_cipher| is available during the ALPN // selection callback. -static bool TestALPNCipherAvailable(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { +TEST_P(SSLVersionTest, ALPNCipherAvailable) { // SSL 3.0 lacks extensions. - if (version == SSL3_VERSION) { - return true; + if (version() == SSL3_VERSION) { + return; } - static const uint8_t kALPNProtos[] = {0x03, 'f', 'o', 'o'}; + ASSERT_TRUE(UseCertAndKey(client_ctx_.get())); - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!cert || !key) { - return false; - } - - bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method)); - if (!ctx || !SSL_CTX_use_certificate(ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(ctx.get(), version) || - !SSL_CTX_set_max_proto_version(ctx.get(), version) || - SSL_CTX_set_alpn_protos(ctx.get(), kALPNProtos, sizeof(kALPNProtos)) != - 0) { - return false; - } + static const uint8_t kALPNProtos[] = {0x03, 'f', 'o', 'o'}; + ASSERT_EQ(SSL_CTX_set_alpn_protos(client_ctx_.get(), kALPNProtos, + sizeof(kALPNProtos)), + 0); // The ALPN callback does not fail the handshake on error, so have the // callback write a boolean. - std::pair<uint16_t, bool> callback_state(version, false); + std::pair<uint16_t, bool> callback_state(version(), false); SSL_CTX_set_alpn_select_cb( - ctx.get(), + server_ctx_.get(), [](SSL *ssl, const uint8_t **out, uint8_t *out_len, const uint8_t *in, unsigned in_len, void *arg) -> int { auto state = reinterpret_cast<std::pair<uint16_t, bool> *>(arg); @@ -2904,81 +2742,37 @@ static bool TestALPNCipherAvailable(bool is_dtls, const SSL_METHOD *method, }, &callback_state); - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(), - nullptr /* no session */)) { - return false; - } - - if (!callback_state.second) { - fprintf(stderr, "The pending cipher was not known in the ALPN callback.\n"); - return false; - } + ASSERT_TRUE(Connect()); - return true; + ASSERT_TRUE(callback_state.second); } -static bool TestSSLClearSessionResumption(bool is_dtls, - const SSL_METHOD *method, - uint16_t version) { +TEST_P(SSLVersionTest, SSLClearSessionResumption) { // Skip this for TLS 1.3. TLS 1.3's ticket mechanism is incompatible with this // API pattern. - if (version == TLS1_3_VERSION) { - return true; - } - - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)); - bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method)); - if (!cert || !key || !server_ctx || !client_ctx || - !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(client_ctx.get(), version) || - !SSL_CTX_set_min_proto_version(server_ctx.get(), version) || - !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) { - return false; + if (version() == TLS1_3_VERSION) { + return; } - // Connect a client and a server. - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, client_ctx.get(), - server_ctx.get(), nullptr /* no session */)) { - return false; - } + ASSERT_TRUE(Connect()); - if (SSL_session_reused(client.get()) || - SSL_session_reused(server.get())) { - fprintf(stderr, "Session unexpectedly reused.\n"); - return false; - } + EXPECT_FALSE(SSL_session_reused(client_.get())); + EXPECT_FALSE(SSL_session_reused(server_.get())); // Reset everything. - if (!SSL_clear(client.get()) || - !SSL_clear(server.get())) { - fprintf(stderr, "SSL_clear failed.\n"); - return false; - } + ASSERT_TRUE(SSL_clear(client_.get())); + ASSERT_TRUE(SSL_clear(server_.get())); // Attempt to connect a second time. - if (!CompleteHandshakes(client.get(), server.get())) { - fprintf(stderr, "Could not reuse SSL objects.\n"); - return false; - } + ASSERT_TRUE(CompleteHandshakes(client_.get(), server_.get())); // |SSL_clear| should implicitly offer the previous session to the server. - if (!SSL_session_reused(client.get()) || - !SSL_session_reused(server.get())) { - fprintf(stderr, "Session was not reused in second try.\n"); - return false; - } - - return true; + EXPECT_TRUE(SSL_session_reused(client_.get())); + EXPECT_TRUE(SSL_session_reused(server_.get())); } -static bool ChainsEqual(STACK_OF(X509) *chain, - const std::vector<X509 *> &expected) { +static bool ChainsEqual(STACK_OF(X509) * chain, + const std::vector<X509 *> &expected) { if (sk_X509_num(chain) != expected.size()) { return false; } @@ -2992,91 +2786,60 @@ static bool ChainsEqual(STACK_OF(X509) *chain, return true; } -static bool TestAutoChain(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - bssl::UniquePtr<X509> cert = GetChainTestCertificate(); +TEST_P(SSLVersionTest, AutoChain) { + cert_ = GetChainTestCertificate(); + ASSERT_TRUE(cert_); + key_ = GetChainTestKey(); + ASSERT_TRUE(key_); bssl::UniquePtr<X509> intermediate = GetChainTestIntermediate(); - bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey(); - if (!cert || !intermediate || !key) { - return false; - } + ASSERT_TRUE(intermediate); + + ASSERT_TRUE(UseCertAndKey(client_ctx_.get())); + ASSERT_TRUE(UseCertAndKey(server_ctx_.get())); // Configure both client and server to accept any certificate. Add // |intermediate| to the cert store. - bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method)); - if (!ctx || - !SSL_CTX_use_certificate(ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(ctx.get(), version) || - !SSL_CTX_set_max_proto_version(ctx.get(), version) || - !X509_STORE_add_cert(SSL_CTX_get_cert_store(ctx.get()), - intermediate.get())) { - return false; - } - SSL_CTX_set_verify( - ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); - SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL); + ASSERT_TRUE(X509_STORE_add_cert(SSL_CTX_get_cert_store(client_ctx_.get()), + intermediate.get())); + ASSERT_TRUE(X509_STORE_add_cert(SSL_CTX_get_cert_store(server_ctx_.get()), + intermediate.get())); + SSL_CTX_set_verify(client_ctx_.get(), + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + nullptr); + SSL_CTX_set_verify(server_ctx_.get(), + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + nullptr); + SSL_CTX_set_cert_verify_callback(client_ctx_.get(), VerifySucceed, NULL); + SSL_CTX_set_cert_verify_callback(server_ctx_.get(), VerifySucceed, NULL); // By default, the client and server should each only send the leaf. - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(), - nullptr /* no session */)) { - return false; - } + ASSERT_TRUE(Connect()); - if (!ChainsEqual(SSL_get_peer_full_cert_chain(client.get()), {cert.get()})) { - fprintf(stderr, "Client-received chain did not match.\n"); - return false; - } - - if (!ChainsEqual(SSL_get_peer_full_cert_chain(server.get()), {cert.get()})) { - fprintf(stderr, "Server-received chain did not match.\n"); - return false; - } + EXPECT_TRUE( + ChainsEqual(SSL_get_peer_full_cert_chain(client_.get()), {cert_.get()})); + EXPECT_TRUE( + ChainsEqual(SSL_get_peer_full_cert_chain(server_.get()), {cert_.get()})); // If auto-chaining is enabled, then the intermediate is sent. - SSL_CTX_clear_mode(ctx.get(), SSL_MODE_NO_AUTO_CHAIN); - if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(), - nullptr /* no session */)) { - return false; - } - - if (!ChainsEqual(SSL_get_peer_full_cert_chain(client.get()), - {cert.get(), intermediate.get()})) { - fprintf(stderr, "Client-received chain did not match (auto-chaining).\n"); - return false; - } + SSL_CTX_clear_mode(client_ctx_.get(), SSL_MODE_NO_AUTO_CHAIN); + SSL_CTX_clear_mode(server_ctx_.get(), SSL_MODE_NO_AUTO_CHAIN); + ASSERT_TRUE(Connect()); - if (!ChainsEqual(SSL_get_peer_full_cert_chain(server.get()), - {cert.get(), intermediate.get()})) { - fprintf(stderr, "Server-received chain did not match (auto-chaining).\n"); - return false; - } + EXPECT_TRUE(ChainsEqual(SSL_get_peer_full_cert_chain(client_.get()), + {cert_.get(), intermediate.get()})); + EXPECT_TRUE(ChainsEqual(SSL_get_peer_full_cert_chain(server_.get()), + {cert_.get(), intermediate.get()})); // Auto-chaining does not override explicitly-configured intermediates. - if (!SSL_CTX_add1_chain_cert(ctx.get(), cert.get()) || - !ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(), - nullptr /* no session */)) { - return false; - } + ASSERT_TRUE(SSL_CTX_add1_chain_cert(client_ctx_.get(), cert_.get())); + ASSERT_TRUE(SSL_CTX_add1_chain_cert(server_ctx_.get(), cert_.get())); + ASSERT_TRUE(Connect()); - if (!ChainsEqual(SSL_get_peer_full_cert_chain(client.get()), - {cert.get(), cert.get()})) { - fprintf(stderr, - "Client-received chain did not match (auto-chaining, explicit " - "intermediate).\n"); - return false; - } + EXPECT_TRUE(ChainsEqual(SSL_get_peer_full_cert_chain(client_.get()), + {cert_.get(), cert_.get()})); - if (!ChainsEqual(SSL_get_peer_full_cert_chain(server.get()), - {cert.get(), cert.get()})) { - fprintf(stderr, - "Server-received chain did not match (auto-chaining, explicit " - "intermediate).\n"); - return false; - } - - return true; + EXPECT_TRUE(ChainsEqual(SSL_get_peer_full_cert_chain(server_.get()), + {cert_.get(), cert_.get()})); } static bool ExpectBadWriteRetry() { @@ -3097,30 +2860,21 @@ static bool ExpectBadWriteRetry() { return true; } -static bool TestSSLWriteRetry(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - if (is_dtls) { - return true; +TEST_P(SSLVersionTest, SSLWriteRetry) { + if (is_dtls()) { + return; } - for (bool enable_partial_write : std::vector<bool>{false, true}) { + for (bool enable_partial_write : {false, true}) { + SCOPED_TRACE(enable_partial_write); + // Connect a client and server. - bssl::UniquePtr<X509> cert = GetTestCertificate(); - bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method)); - bssl::UniquePtr<SSL> client, server; - if (!cert || !key || !ctx || - !SSL_CTX_use_certificate(ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(ctx.get(), version) || - !SSL_CTX_set_max_proto_version(ctx.get(), version) || - !ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(), - nullptr /* no session */)) { - return false; - } + ASSERT_TRUE(UseCertAndKey(client_ctx_.get())); + + ASSERT_TRUE(Connect()); if (enable_partial_write) { - SSL_set_mode(client.get(), SSL_MODE_ENABLE_PARTIAL_WRITE); + SSL_set_mode(client_.get(), SSL_MODE_ENABLE_PARTIAL_WRITE); } // Write without reading until the buffer is full and we have an unfinished @@ -3130,83 +2884,57 @@ static bool TestSSLWriteRetry(bool is_dtls, const SSL_METHOD *method, static const int kChunkLen = 5; // The length of "hello". unsigned count = 0; for (;;) { - int ret = SSL_write(client.get(), data, kChunkLen); + int ret = SSL_write(client_.get(), data, kChunkLen); if (ret <= 0) { - int err = SSL_get_error(client.get(), ret); - if (SSL_get_error(client.get(), ret) == SSL_ERROR_WANT_WRITE) { - break; - } - fprintf(stderr, "SSL_write failed in unexpected way: %d\n", err); - return false; + ASSERT_EQ(SSL_get_error(client_.get(), ret), SSL_ERROR_WANT_WRITE); + break; } - if (ret != 5) { - fprintf(stderr, "SSL_write wrote %d bytes, expected 5.\n", ret); - return false; - } + ASSERT_EQ(ret, 5); count++; } // Retrying with the same parameters is legal. - if (SSL_get_error(client.get(), SSL_write(client.get(), data, kChunkLen)) != - SSL_ERROR_WANT_WRITE) { - fprintf(stderr, "SSL_write retry unexpectedly failed.\n"); - return false; - } + ASSERT_EQ( + SSL_get_error(client_.get(), SSL_write(client_.get(), data, kChunkLen)), + SSL_ERROR_WANT_WRITE); // Retrying with the same buffer but shorter length is not legal. - if (SSL_get_error(client.get(), - SSL_write(client.get(), data, kChunkLen - 1)) != - SSL_ERROR_SSL || - !ExpectBadWriteRetry()) { - fprintf(stderr, "SSL_write retry did not fail as expected.\n"); - return false; - } + ASSERT_EQ(SSL_get_error(client_.get(), + SSL_write(client_.get(), data, kChunkLen - 1)), + SSL_ERROR_SSL); + ASSERT_TRUE(ExpectBadWriteRetry()); // Retrying with a different buffer pointer is not legal. char data2[] = "hello"; - if (SSL_get_error(client.get(), SSL_write(client.get(), data2, - kChunkLen)) != SSL_ERROR_SSL || - !ExpectBadWriteRetry()) { - fprintf(stderr, "SSL_write retry did not fail as expected.\n"); - return false; - } + ASSERT_EQ(SSL_get_error(client_.get(), + SSL_write(client_.get(), data2, kChunkLen)), + SSL_ERROR_SSL); + ASSERT_TRUE(ExpectBadWriteRetry()); // With |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|, the buffer may move. - SSL_set_mode(client.get(), SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - if (SSL_get_error(client.get(), - SSL_write(client.get(), data2, kChunkLen)) != - SSL_ERROR_WANT_WRITE) { - fprintf(stderr, "SSL_write retry unexpectedly failed.\n"); - return false; - } + SSL_set_mode(client_.get(), SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + ASSERT_EQ(SSL_get_error(client_.get(), + SSL_write(client_.get(), data2, kChunkLen)), + SSL_ERROR_WANT_WRITE); // |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER| does not disable length checks. - if (SSL_get_error(client.get(), - SSL_write(client.get(), data2, kChunkLen - 1)) != - SSL_ERROR_SSL || - !ExpectBadWriteRetry()) { - fprintf(stderr, "SSL_write retry did not fail as expected.\n"); - return false; - } + ASSERT_EQ(SSL_get_error(client_.get(), + SSL_write(client_.get(), data2, kChunkLen - 1)), + SSL_ERROR_SSL); + ASSERT_TRUE(ExpectBadWriteRetry()); // Retrying with a larger buffer is legal. - if (SSL_get_error(client.get(), - SSL_write(client.get(), data, kChunkLen + 1)) != - SSL_ERROR_WANT_WRITE) { - fprintf(stderr, "SSL_write retry unexpectedly failed.\n"); - return false; - } + ASSERT_EQ(SSL_get_error(client_.get(), + SSL_write(client_.get(), data, kChunkLen + 1)), + SSL_ERROR_WANT_WRITE); // Drain the buffer. char buf[20]; for (unsigned i = 0; i < count; i++) { - if (SSL_read(server.get(), buf, sizeof(buf)) != kChunkLen || - OPENSSL_memcmp(buf, "hello", kChunkLen) != 0) { - fprintf(stderr, "Failed to read initial records.\n"); - return false; - } + ASSERT_EQ(SSL_read(server_.get(), buf, sizeof(buf)), kChunkLen); + ASSERT_EQ(OPENSSL_memcmp(buf, "hello", kChunkLen), 0); } // Now that there is space, a retry with a larger buffer should flush the @@ -3215,138 +2943,77 @@ static bool TestSSLWriteRetry(bool is_dtls, const SSL_METHOD *method, // is set, this will complete in two steps. char data3[] = "_____!"; if (enable_partial_write) { - if (SSL_write(client.get(), data3, kChunkLen + 1) != kChunkLen || - SSL_write(client.get(), data3 + kChunkLen, 1) != 1) { - fprintf(stderr, "SSL_write retry failed.\n"); - return false; - } - } else if (SSL_write(client.get(), data3, kChunkLen + 1) != kChunkLen + 1) { - fprintf(stderr, "SSL_write retry failed.\n"); - return false; + ASSERT_EQ(SSL_write(client_.get(), data3, kChunkLen + 1), kChunkLen); + ASSERT_EQ(SSL_write(client_.get(), data3 + kChunkLen, 1), 1); + } else { + ASSERT_EQ(SSL_write(client_.get(), data3, kChunkLen + 1), kChunkLen + 1); } // Check the last write was correct. The data will be spread over two // records, so SSL_read returns twice. - if (SSL_read(server.get(), buf, sizeof(buf)) != kChunkLen || - OPENSSL_memcmp(buf, "hello", kChunkLen) != 0 || - SSL_read(server.get(), buf, sizeof(buf)) != 1 || - buf[0] != '!') { - fprintf(stderr, "Failed to read write retry.\n"); - return false; - } + ASSERT_EQ(SSL_read(server_.get(), buf, sizeof(buf)), kChunkLen); + ASSERT_EQ(OPENSSL_memcmp(buf, "hello", kChunkLen), 0); + ASSERT_EQ(SSL_read(server_.get(), buf, sizeof(buf)), 1); + ASSERT_EQ(buf[0], '!'); } - - return true; } -static bool TestRecordCallback(bool is_dtls, const SSL_METHOD *method, - uint16_t version) { - bssl::UniquePtr<X509> cert = GetChainTestCertificate(); - bssl::UniquePtr<X509> intermediate = GetChainTestIntermediate(); - bssl::UniquePtr<EVP_PKEY> key = GetChainTestKey(); - if (!cert || !intermediate || !key) { - return false; - } +TEST_P(SSLVersionTest, RecordCallback) { + for (bool test_server : {true, false}) { + SCOPED_TRACE(test_server); + ResetContexts(); - bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method)); - if (!ctx || - !SSL_CTX_use_certificate(ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) || - !SSL_CTX_set_min_proto_version(ctx.get(), version) || - !SSL_CTX_set_max_proto_version(ctx.get(), version)) { - return false; - } - - bool read_seen = false; - bool write_seen = false; - auto cb = [&](int is_write, int cb_version, int cb_type, const void *buf, - size_t len, SSL *ssl) { - if (cb_type != SSL3_RT_HEADER) { - return; - } - - // The callback does not report a version for records. - EXPECT_EQ(0, cb_version); - - if (is_write) { - write_seen = true; - } else { - read_seen = true; - } - - // Sanity-check that the record header is plausible. - CBS cbs; - CBS_init(&cbs, reinterpret_cast<const uint8_t *>(buf), len); - uint8_t type; - uint16_t record_version, length; - ASSERT_TRUE(CBS_get_u8(&cbs, &type)); - ASSERT_TRUE(CBS_get_u16(&cbs, &record_version)); - EXPECT_TRUE(record_version == version || - record_version == (is_dtls ? DTLS1_VERSION : TLS1_VERSION)) - << "Invalid record version: " << record_version; - if (is_dtls) { - uint16_t epoch; - ASSERT_TRUE(CBS_get_u16(&cbs, &epoch)); - EXPECT_TRUE(epoch == 0 || epoch == 1) << "Invalid epoch: " << epoch; - ASSERT_TRUE(CBS_skip(&cbs, 6)); - } - ASSERT_TRUE(CBS_get_u16(&cbs, &length)); - EXPECT_EQ(0u, CBS_len(&cbs)); - }; - using CallbackType = decltype(cb); - SSL_CTX_set_msg_callback( - ctx.get(), [](int is_write, int cb_version, int cb_type, const void *buf, - size_t len, SSL *ssl, void *arg) { - CallbackType *cb_ptr = reinterpret_cast<CallbackType *>(arg); - (*cb_ptr)(is_write, cb_version, cb_type, buf, len, ssl); - }); - SSL_CTX_set_msg_callback_arg(ctx.get(), &cb); - - bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(), - nullptr /* no session */)) { - return false; - } - - EXPECT_TRUE(read_seen); - EXPECT_TRUE(write_seen); - return true; -} + bool read_seen = false; + bool write_seen = false; + auto cb = [&](int is_write, int cb_version, int cb_type, const void *buf, + size_t len, SSL *ssl) { + if (cb_type != SSL3_RT_HEADER) { + return; + } + // The callback does not report a version for records. + EXPECT_EQ(0, cb_version); -static bool ForEachVersion(bool (*test_func)(bool is_dtls, - const SSL_METHOD *method, - uint16_t version)) { - static uint16_t kTLSVersions[] = { - SSL3_VERSION, - TLS1_VERSION, - TLS1_1_VERSION, - TLS1_2_VERSION, -// TLS 1.3 requires RSA-PSS, which is disabled for Android system builds. -#if !defined(BORINGSSL_ANDROID_SYSTEM) - TLS1_3_VERSION, -#endif - }; + if (is_write) { + write_seen = true; + } else { + read_seen = true; + } - static uint16_t kDTLSVersions[] = { - DTLS1_VERSION, DTLS1_2_VERSION, - }; + // Sanity-check that the record header is plausible. + CBS cbs; + CBS_init(&cbs, reinterpret_cast<const uint8_t *>(buf), len); + uint8_t type; + uint16_t record_version, length; + ASSERT_TRUE(CBS_get_u8(&cbs, &type)); + ASSERT_TRUE(CBS_get_u16(&cbs, &record_version)); + EXPECT_TRUE(record_version == version() || + record_version == (is_dtls() ? DTLS1_VERSION : TLS1_VERSION)) + << "Invalid record version: " << record_version; + if (is_dtls()) { + uint16_t epoch; + ASSERT_TRUE(CBS_get_u16(&cbs, &epoch)); + EXPECT_TRUE(epoch == 0 || epoch == 1) << "Invalid epoch: " << epoch; + ASSERT_TRUE(CBS_skip(&cbs, 6)); + } + ASSERT_TRUE(CBS_get_u16(&cbs, &length)); + EXPECT_EQ(0u, CBS_len(&cbs)); + }; + using CallbackType = decltype(cb); + SSL_CTX *ctx = test_server ? server_ctx_.get() : client_ctx_.get(); + SSL_CTX_set_msg_callback( + ctx, [](int is_write, int cb_version, int cb_type, const void *buf, + size_t len, SSL *ssl, void *arg) { + CallbackType *cb_ptr = reinterpret_cast<CallbackType *>(arg); + (*cb_ptr)(is_write, cb_version, cb_type, buf, len, ssl); + }); + SSL_CTX_set_msg_callback_arg(ctx, &cb); - for (uint16_t version : kTLSVersions) { - if (!test_func(false, TLS_method(), version)) { - fprintf(stderr, "Test failed at TLS version %04x.\n", version); - return false; - } - } + ASSERT_TRUE(Connect()); - for (uint16_t version : kDTLSVersions) { - if (!test_func(true, DTLS_method(), version)) { - fprintf(stderr, "Test failed at DTLS version %04x.\n", version); - return false; - } + EXPECT_TRUE(read_seen); + EXPECT_TRUE(write_seen); } - - return true; } TEST(SSLTest, AddChainCertHack) { @@ -4046,21 +3713,10 @@ TEST(SSLTest, AllTests) { // Test the padding extension at TLS 1.3 with a TLS 1.3 session, so there // will be a PSK binder after the padding extension. !TestPaddingExtension(TLS1_3_VERSION, TLS1_3_DRAFT_VERSION) || - !ForEachVersion(TestSequenceNumber) || - !ForEachVersion(TestOneSidedShutdown) || - !ForEachVersion(TestGetPeerCertificate) || - !ForEachVersion(TestNoPeerCertificate) || - !ForEachVersion(TestRetainOnlySHA256OfCerts) || - !TestClientHello() || - !ForEachVersion(TestSessionIDContext) || - !ForEachVersion(TestSessionTimeout) || - !ForEachVersion(TestSNICallback) || - !ForEachVersion(TestVersion) || - !ForEachVersion(TestALPNCipherAvailable) || - !ForEachVersion(TestSSLClearSessionResumption) || - !ForEachVersion(TestAutoChain) || - !ForEachVersion(TestSSLWriteRetry) || - !ForEachVersion(TestRecordCallback)) { + !TestClientHello()) { ADD_FAILURE() << "Tests failed"; } } + +} // namespace +} // namespace bssl |