diff options
Diffstat (limited to 'src/ssl/ssl_test.cc')
-rw-r--r-- | src/ssl/ssl_test.cc | 514 |
1 files changed, 335 insertions, 179 deletions
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index d01b6495..6f180c74 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -737,103 +737,77 @@ static bool DecodeBase64(std::vector<uint8_t> *out, const char *in) { return true; } -static bool TestSSL_SESSIONEncoding(const char *input_b64) { - const uint8_t *cptr; - uint8_t *ptr; - - // Decode the input. - std::vector<uint8_t> input; - if (!DecodeBase64(&input, input_b64)) { - return false; - } - - // Verify the SSL_SESSION decodes. - bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); - if (!ssl_ctx) { - return false; - } - bssl::UniquePtr<SSL_SESSION> session( - SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get())); - if (!session) { - fprintf(stderr, "SSL_SESSION_from_bytes failed\n"); - return false; - } - - // Verify the SSL_SESSION encoding round-trips. - size_t encoded_len; - bssl::UniquePtr<uint8_t> encoded; - uint8_t *encoded_raw; - if (!SSL_SESSION_to_bytes(session.get(), &encoded_raw, &encoded_len)) { - fprintf(stderr, "SSL_SESSION_to_bytes failed\n"); - return false; - } - encoded.reset(encoded_raw); - if (encoded_len != input.size() || - OPENSSL_memcmp(input.data(), encoded.get(), input.size()) != 0) { - fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n"); - hexdump(stderr, "Before: ", input.data(), input.size()); - hexdump(stderr, "After: ", encoded_raw, encoded_len); - return false; - } - - // Verify the SSL_SESSION also decodes with the legacy API. - cptr = input.data(); - session.reset(d2i_SSL_SESSION(NULL, &cptr, input.size())); - if (!session || cptr != input.data() + input.size()) { - fprintf(stderr, "d2i_SSL_SESSION failed\n"); - return false; - } - - // Verify the SSL_SESSION encoding round-trips via the legacy API. - int len = i2d_SSL_SESSION(session.get(), NULL); - if (len < 0 || (size_t)len != input.size()) { - fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n"); - return false; - } - - encoded.reset((uint8_t *)OPENSSL_malloc(input.size())); - if (!encoded) { - fprintf(stderr, "malloc failed\n"); - return false; - } - - ptr = encoded.get(); - len = i2d_SSL_SESSION(session.get(), &ptr); - if (len < 0 || (size_t)len != input.size()) { - fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n"); - return false; - } - if (ptr != encoded.get() + input.size()) { - fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n"); - return false; - } - if (OPENSSL_memcmp(input.data(), encoded.get(), input.size()) != 0) { - fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n"); - return false; - } - - return true; -} - -static bool TestBadSSL_SESSIONEncoding(const char *input_b64) { - std::vector<uint8_t> input; - if (!DecodeBase64(&input, input_b64)) { - return false; - } - - // Verify that the SSL_SESSION fails to decode. - bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); - if (!ssl_ctx) { - return false; - } - bssl::UniquePtr<SSL_SESSION> session( - SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get())); - if (session) { - fprintf(stderr, "SSL_SESSION_from_bytes unexpectedly succeeded\n"); - return false; +TEST(SSLTest, SessionEncoding) { + for (const char *input_b64 : { + kOpenSSLSession, + kCustomSession, + kBoringSSLSession, + }) { + SCOPED_TRACE(std::string(input_b64)); + // Decode the input. + std::vector<uint8_t> input; + ASSERT_TRUE(DecodeBase64(&input, input_b64)); + + // Verify the SSL_SESSION decodes. + bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); + ASSERT_TRUE(ssl_ctx); + bssl::UniquePtr<SSL_SESSION> session( + SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get())); + ASSERT_TRUE(session) << "SSL_SESSION_from_bytes failed"; + + // Verify the SSL_SESSION encoding round-trips. + size_t encoded_len; + bssl::UniquePtr<uint8_t> encoded; + uint8_t *encoded_raw; + ASSERT_TRUE(SSL_SESSION_to_bytes(session.get(), &encoded_raw, &encoded_len)) + << "SSL_SESSION_to_bytes failed"; + encoded.reset(encoded_raw); + EXPECT_EQ(Bytes(encoded.get(), encoded_len), Bytes(input)) + << "SSL_SESSION_to_bytes did not round-trip"; + + // Verify the SSL_SESSION also decodes with the legacy API. + const uint8_t *cptr = input.data(); + session.reset(d2i_SSL_SESSION(NULL, &cptr, input.size())); + ASSERT_TRUE(session) << "d2i_SSL_SESSION failed"; + EXPECT_EQ(cptr, input.data() + input.size()); + + // Verify the SSL_SESSION encoding round-trips via the legacy API. + int len = i2d_SSL_SESSION(session.get(), NULL); + ASSERT_GT(len, 0) << "i2d_SSL_SESSION failed"; + ASSERT_EQ(static_cast<size_t>(len), input.size()) + << "i2d_SSL_SESSION(NULL) returned invalid length"; + + encoded.reset((uint8_t *)OPENSSL_malloc(input.size())); + ASSERT_TRUE(encoded); + + uint8_t *ptr = encoded.get(); + len = i2d_SSL_SESSION(session.get(), &ptr); + ASSERT_GT(len, 0) << "i2d_SSL_SESSION failed"; + ASSERT_EQ(static_cast<size_t>(len), input.size()) + << "i2d_SSL_SESSION(NULL) returned invalid length"; + ASSERT_EQ(ptr, encoded.get() + input.size()) + << "i2d_SSL_SESSION did not advance ptr correctly"; + EXPECT_EQ(Bytes(encoded.get(), encoded_len), Bytes(input)) + << "SSL_SESSION_to_bytes did not round-trip"; + } + + for (const char *input_b64 : { + kBadSessionExtraField, + kBadSessionVersion, + kBadSessionTrailingData, + }) { + SCOPED_TRACE(std::string(input_b64)); + std::vector<uint8_t> input; + ASSERT_TRUE(DecodeBase64(&input, input_b64)); + + // Verify that the SSL_SESSION fails to decode. + bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); + ASSERT_TRUE(ssl_ctx); + bssl::UniquePtr<SSL_SESSION> session( + SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get())); + EXPECT_FALSE(session) << "SSL_SESSION_from_bytes unexpectedly succeeded"; + ERR_clear_error(); } - ERR_clear_error(); - return true; } static void ExpectDefaultVersion(uint16_t min_version, uint16_t max_version, @@ -1087,63 +1061,67 @@ static size_t GetClientHelloLen(uint16_t max_version, uint16_t session_version, return client_hello.size() - SSL3_RT_HEADER_LENGTH; } -struct PaddingTest { - size_t input_len, padded_len; -}; +TEST(SSLTest, Padding) { + struct PaddingVersions { + uint16_t max_version, session_version; + }; + static const PaddingVersions kPaddingVersions[] = { + // Test the padding extension at TLS 1.2. + {TLS1_2_VERSION, TLS1_2_VERSION}, + // Test the padding extension at TLS 1.3 with a TLS 1.2 session, so there + // will be no PSK binder after the padding extension. + {TLS1_3_VERSION, TLS1_2_VERSION}, + // 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. + {TLS1_3_VERSION, TLS1_3_VERSION}, -static const PaddingTest kPaddingTests[] = { - // ClientHellos of length below 0x100 do not require padding. - {0xfe, 0xfe}, - {0xff, 0xff}, - // ClientHellos of length 0x100 through 0x1fb are padded up to 0x200. - {0x100, 0x200}, - {0x123, 0x200}, - {0x1fb, 0x200}, - // ClientHellos of length 0x1fc through 0x1ff get padded beyond 0x200. The - // padding extension takes a minimum of four bytes plus one required content - // byte. (To work around yet more server bugs, we avoid empty final - // extensions.) - {0x1fc, 0x201}, - {0x1fd, 0x202}, - {0x1fe, 0x203}, - {0x1ff, 0x204}, - // Finally, larger ClientHellos need no padding. - {0x200, 0x200}, - {0x201, 0x201}, -}; + }; -static bool TestPaddingExtension(uint16_t max_version, - uint16_t session_version) { - // Sample a baseline length. - size_t base_len = GetClientHelloLen(max_version, session_version, 1); - if (base_len == 0) { - return false; - } + struct PaddingTest { + size_t input_len, padded_len; + }; + static const PaddingTest kPaddingTests[] = { + // ClientHellos of length below 0x100 do not require padding. + {0xfe, 0xfe}, + {0xff, 0xff}, + // ClientHellos of length 0x100 through 0x1fb are padded up to 0x200. + {0x100, 0x200}, + {0x123, 0x200}, + {0x1fb, 0x200}, + // ClientHellos of length 0x1fc through 0x1ff get padded beyond 0x200. The + // padding extension takes a minimum of four bytes plus one required + // content + // byte. (To work around yet more server bugs, we avoid empty final + // extensions.) + {0x1fc, 0x201}, + {0x1fd, 0x202}, + {0x1fe, 0x203}, + {0x1ff, 0x204}, + // Finally, larger ClientHellos need no padding. + {0x200, 0x200}, + {0x201, 0x201}, + }; - for (const PaddingTest &test : kPaddingTests) { - if (base_len > test.input_len) { - fprintf(stderr, - "Baseline ClientHello too long (max_version = %04x, " - "session_version = %04x).\n", - max_version, session_version); - return false; - } + for (const PaddingVersions &versions : kPaddingVersions) { + SCOPED_TRACE(versions.max_version); + SCOPED_TRACE(versions.session_version); - size_t padded_len = GetClientHelloLen(max_version, session_version, - 1 + test.input_len - base_len); - if (padded_len != test.padded_len) { - fprintf(stderr, - "%u-byte ClientHello padded to %u bytes, not %u (max_version = " - "%04x, session_version = %04x).\n", - static_cast<unsigned>(test.input_len), - static_cast<unsigned>(padded_len), - static_cast<unsigned>(test.padded_len), max_version, - session_version); - return false; + // Sample a baseline length. + size_t base_len = + GetClientHelloLen(versions.max_version, versions.session_version, 1); + ASSERT_NE(base_len, 0u) << "Baseline length could not be sampled"; + + for (const PaddingTest &test : kPaddingTests) { + SCOPED_TRACE(test.input_len); + ASSERT_LE(base_len, test.input_len) << "Baseline ClientHello too long"; + + size_t padded_len = + GetClientHelloLen(versions.max_version, versions.session_version, + 1 + test.input_len - base_len); + EXPECT_EQ(padded_len, test.padded_len) + << "ClientHello was not padded to expected length"; } } - - return true; } static bssl::UniquePtr<X509> GetTestCertificate() { @@ -1550,6 +1528,37 @@ static bool CompleteHandshakes(SSL *client, SSL *server) { return true; } +static bool FlushNewSessionTickets(SSL *client, SSL *server) { + // NewSessionTickets are deferred on the server to |SSL_write|, and clients do + // not pick them up until |SSL_read|. + for (;;) { + int server_ret = SSL_write(server, nullptr, 0); + int server_err = SSL_get_error(server, server_ret); + // The server may either succeed (|server_ret| is zero) or block on write + // (|server_ret| is -1 and |server_err| is |SSL_ERROR_WANT_WRITE|). + if (server_ret > 0 || + (server_ret < 0 && server_err != SSL_ERROR_WANT_WRITE)) { + fprintf(stderr, "Unexpected server result: %d %d\n", server_ret, + server_err); + return false; + } + + int client_ret = SSL_read(client, nullptr, 0); + int client_err = SSL_get_error(client, client_ret); + // The client must always block on read. + if (client_ret != -1 || client_err != SSL_ERROR_WANT_READ) { + fprintf(stderr, "Unexpected client result: %d %d\n", client_ret, + client_err); + return false; + } + + // The server flushed everything it had to write. + if (server_ret == 0) { + return true; + } + } +} + struct ClientConfig { SSL_SESSION *session = nullptr; std::string servername; @@ -1661,9 +1670,7 @@ TEST_P(SSLVersionTest, SequenceNumber) { // Drain any post-handshake messages to ensure there are no unread records // on either end. - uint8_t byte = 0; - ASSERT_LE(SSL_read(client_.get(), &byte, 1), 0); - ASSERT_LE(SSL_read(server_.get(), &byte, 1), 0); + ASSERT_TRUE(FlushNewSessionTickets(client_.get(), server_.get())); uint64_t client_read_seq = SSL_get_read_sequence(client_.get()); uint64_t client_write_seq = SSL_get_write_sequence(client_.get()); @@ -1687,6 +1694,7 @@ TEST_P(SSLVersionTest, SequenceNumber) { } // Send a record from client to server. + uint8_t byte = 0; EXPECT_EQ(SSL_write(client_.get(), &byte, 1), 1); EXPECT_EQ(SSL_read(server_.get(), &byte, 1), 1); @@ -2084,14 +2092,12 @@ static bssl::UniquePtr<SSL_SESSION> CreateClientSession( // Connect client and server to get a session. bssl::UniquePtr<SSL> client, server; if (!ConnectClientAndServer(&client, &server, client_ctx, server_ctx, - config)) { + config) || + !FlushNewSessionTickets(client.get(), server.get())) { fprintf(stderr, "Failed to connect client and server.\n"); return nullptr; } - // Run the read loop to account for post-handshake tickets in TLS 1.3. - SSL_read(client.get(), nullptr, 0); - SSL_CTX_sess_set_new_cb(client_ctx, nullptr); if (!g_last_session) { @@ -2125,7 +2131,8 @@ static bssl::UniquePtr<SSL_SESSION> ExpectSessionRenewed(SSL_CTX *client_ctx, ClientConfig config; config.session = session; if (!ConnectClientAndServer(&client, &server, client_ctx, server_ctx, - config)) { + config) || + !FlushNewSessionTickets(client.get(), server.get())) { fprintf(stderr, "Failed to connect client and server.\n"); return nullptr; } @@ -2140,9 +2147,6 @@ static bssl::UniquePtr<SSL_SESSION> ExpectSessionRenewed(SSL_CTX *client_ctx, return nullptr; } - // Run the read loop to account for post-handshake tickets in TLS 1.3. - SSL_read(client.get(), nullptr, 0); - SSL_CTX_sess_set_new_cb(client_ctx, nullptr); if (!g_last_session) { @@ -3055,6 +3059,82 @@ TEST_P(SSLVersionTest, ClientSessionCacheMode) { EXPECT_FALSE(CreateClientSession(client_ctx_.get(), server_ctx_.get())); } +// Test that all versions survive tiny write buffers. In particular, TLS 1.3 +// NewSessionTickets are written post-handshake. Servers that block +// |SSL_do_handshake| on writing them will deadlock if clients are not draining +// the buffer. Test that we do not do this. +TEST_P(SSLVersionTest, SmallBuffer) { + // DTLS is a datagram protocol and requires packet-sized buffers. + if (is_dtls()) { + return; + } + + // Test both flushing NewSessionTickets with a zero-sized write and + // non-zero-sized write. + for (bool use_zero_write : {false, true}) { + SCOPED_TRACE(use_zero_write); + + g_last_session = nullptr; + SSL_CTX_set_session_cache_mode(client_ctx_.get(), SSL_SESS_CACHE_BOTH); + SSL_CTX_sess_set_new_cb(client_ctx_.get(), SaveLastSession); + + bssl::UniquePtr<SSL> client(SSL_new(client_ctx_.get())), + server(SSL_new(server_ctx_.get())); + ASSERT_TRUE(client); + ASSERT_TRUE(server); + SSL_set_connect_state(client.get()); + SSL_set_accept_state(server.get()); + + // Use a tiny buffer. + BIO *bio1, *bio2; + ASSERT_TRUE(BIO_new_bio_pair(&bio1, 1, &bio2, 1)); + + // SSL_set_bio takes ownership. + SSL_set_bio(client.get(), bio1, bio1); + SSL_set_bio(server.get(), bio2, bio2); + + ASSERT_TRUE(CompleteHandshakes(client.get(), server.get())); + if (version() >= TLS1_3_VERSION) { + // The post-handshake ticket should not have been processed yet. + EXPECT_FALSE(g_last_session); + } + + if (use_zero_write) { + ASSERT_TRUE(FlushNewSessionTickets(client.get(), server.get())); + EXPECT_TRUE(g_last_session); + } + + // Send some data from server to client. If |use_zero_write| is false, this + // will also flush the NewSessionTickets. + static const char kMessage[] = "hello world"; + char buf[sizeof(kMessage)]; + for (;;) { + int server_ret = SSL_write(server.get(), kMessage, sizeof(kMessage)); + int server_err = SSL_get_error(server.get(), server_ret); + int client_ret = SSL_read(client.get(), buf, sizeof(buf)); + int client_err = SSL_get_error(client.get(), client_ret); + + // The server will write a single record, so every iteration should see + // |SSL_ERROR_WANT_WRITE| and |SSL_ERROR_WANT_READ|, until the final + // iteration, where both will complete. + if (server_ret > 0) { + EXPECT_EQ(server_ret, static_cast<int>(sizeof(kMessage))); + EXPECT_EQ(client_ret, static_cast<int>(sizeof(kMessage))); + EXPECT_EQ(Bytes(buf), Bytes(kMessage)); + break; + } + + ASSERT_EQ(server_ret, -1); + ASSERT_EQ(server_err, SSL_ERROR_WANT_WRITE); + ASSERT_EQ(client_ret, -1); + ASSERT_EQ(client_err, SSL_ERROR_WANT_READ); + } + + // The NewSessionTickets should have been flushed and processed. + EXPECT_TRUE(g_last_session); + } +} + TEST(SSLTest, AddChainCertHack) { // Ensure that we don't accidently break the hack that we have in place to // keep curl and serf happy when they use an |X509| even after transfering @@ -3514,9 +3594,7 @@ TEST_P(TicketAEADMethodTest, Resume) { EXPECT_FALSE(SSL_session_reused(client.get())); EXPECT_FALSE(SSL_session_reused(server.get())); - // Run the read loop to account for post-handshake tickets in TLS 1.3. - SSL_read(client.get(), nullptr, 0); - + ASSERT_TRUE(FlushNewSessionTickets(client.get(), server.get())); bssl::UniquePtr<SSL_SESSION> session = std::move(g_last_session); ConnectClientAndServerWithTicketMethod(&client, &server, client_ctx.get(), server_ctx.get(), retry_count, @@ -4606,7 +4684,7 @@ TEST_P(SSLVersionTest, SessionPropertiesThreads) { thread.join(); } } -#endif +#endif // OPENSSL_THREADS constexpr size_t kNumQUICLevels = 4; static_assert(ssl_encryption_initial < kNumQUICLevels, @@ -5263,23 +5341,101 @@ TEST_F(QUICMethodTest, BadPostHandshake) { EXPECT_EQ(SSL_process_quic_post_handshake(client_.get()), 0); } -// TODO(davidben): Convert this file to GTest properly. -TEST(SSLTest, AllTests) { - if (!TestSSL_SESSIONEncoding(kOpenSSLSession) || - !TestSSL_SESSIONEncoding(kCustomSession) || - !TestSSL_SESSIONEncoding(kBoringSSLSession) || - !TestBadSSL_SESSIONEncoding(kBadSessionExtraField) || - !TestBadSSL_SESSIONEncoding(kBadSessionVersion) || - !TestBadSSL_SESSIONEncoding(kBadSessionTrailingData) || - // Test the padding extension at TLS 1.2. - !TestPaddingExtension(TLS1_2_VERSION, TLS1_2_VERSION) || - // Test the padding extension at TLS 1.3 with a TLS 1.2 session, so there - // will be no PSK binder after the padding extension. - !TestPaddingExtension(TLS1_3_VERSION, TLS1_2_VERSION) || - // 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_VERSION)) { - ADD_FAILURE() << "Tests failed"; +extern "C" { +int BORINGSSL_enum_c_type_test(void); +} + +TEST(SSLTest, EnumTypes) { + EXPECT_EQ(sizeof(int), sizeof(ssl_private_key_result_t)); + EXPECT_EQ(1, BORINGSSL_enum_c_type_test()); +} + +TEST_P(SSLVersionTest, DoubleSSLError) { + // Connect the inner SSL connections. + ASSERT_TRUE(Connect()); + + // Make a pair of |BIO|s which wrap |client_| and |server_|. + UniquePtr<BIO_METHOD> bio_method(BIO_meth_new(0, nullptr)); + ASSERT_TRUE(bio_method); + ASSERT_TRUE(BIO_meth_set_read( + bio_method.get(), [](BIO *bio, char *out, int len) -> int { + SSL *ssl = static_cast<SSL *>(BIO_get_data(bio)); + int ret = SSL_read(ssl, out, len); + int ssl_ret = SSL_get_error(ssl, ret); + if (ssl_ret == SSL_ERROR_WANT_READ) { + BIO_set_retry_read(bio); + } + return ret; + })); + ASSERT_TRUE(BIO_meth_set_write( + bio_method.get(), [](BIO *bio, const char *in, int len) -> int { + SSL *ssl = static_cast<SSL *>(BIO_get_data(bio)); + int ret = SSL_write(ssl, in, len); + int ssl_ret = SSL_get_error(ssl, ret); + if (ssl_ret == SSL_ERROR_WANT_WRITE) { + BIO_set_retry_write(bio); + } + return ret; + })); + ASSERT_TRUE(BIO_meth_set_ctrl( + bio_method.get(), [](BIO *bio, int cmd, long larg, void *parg) -> long { + // |SSL| objects require |BIO_flush| support. + if (cmd == BIO_CTRL_FLUSH) { + return 1; + } + return 0; + })); + + UniquePtr<BIO> client_bio(BIO_new(bio_method.get())); + ASSERT_TRUE(client_bio); + BIO_set_data(client_bio.get(), client_.get()); + BIO_set_init(client_bio.get(), 1); + + UniquePtr<BIO> server_bio(BIO_new(bio_method.get())); + ASSERT_TRUE(server_bio); + BIO_set_data(server_bio.get(), server_.get()); + BIO_set_init(server_bio.get(), 1); + + // Wrap the inner connections in another layer of SSL. + UniquePtr<SSL> client_outer(SSL_new(client_ctx_.get())); + ASSERT_TRUE(client_outer); + SSL_set_connect_state(client_outer.get()); + SSL_set_bio(client_outer.get(), client_bio.get(), client_bio.get()); + client_bio.release(); // |SSL_set_bio| takes ownership. + + UniquePtr<SSL> server_outer(SSL_new(server_ctx_.get())); + ASSERT_TRUE(server_outer); + SSL_set_accept_state(server_outer.get()); + SSL_set_bio(server_outer.get(), server_bio.get(), server_bio.get()); + server_bio.release(); // |SSL_set_bio| takes ownership. + + // Configure |client_outer| to reject the server certificate. + SSL_set_custom_verify( + client_outer.get(), SSL_VERIFY_PEER, + [](SSL *ssl, uint8_t *out_alert) -> ssl_verify_result_t { + return ssl_verify_invalid; + }); + + for (;;) { + int client_ret = SSL_do_handshake(client_outer.get()); + int client_err = SSL_get_error(client_outer.get(), client_ret); + if (client_err != SSL_ERROR_WANT_READ && + client_err != SSL_ERROR_WANT_WRITE) { + // The client handshake should terminate on a certificate verification + // error. + EXPECT_EQ(SSL_ERROR_SSL, client_err); + uint32_t err = ERR_peek_error(); + EXPECT_EQ(ERR_LIB_SSL, ERR_GET_LIB(err)); + EXPECT_EQ(SSL_R_CERTIFICATE_VERIFY_FAILED, ERR_GET_REASON(err)); + break; + } + + // Run the server handshake and continue. + int server_ret = SSL_do_handshake(server_outer.get()); + int server_err = SSL_get_error(server_outer.get(), server_ret); + ASSERT_TRUE(server_err == SSL_ERROR_NONE || + server_err == SSL_ERROR_WANT_READ || + server_err == SSL_ERROR_WANT_WRITE); } } |