Add a QUIC test for HelloRetryRequest.

There's no reason to believe it doesn't work, but as it's a slightly different
flow (two unencrypted ClientHellos), it makes sense to test it.

Change-Id: Ic230f7720b459c99b9662cbab847d730d772ab2c
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/37064
Commit-Queue: David Benjamin <davidben@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index 6f180c7..03760b6 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -4951,7 +4951,7 @@
 
 UnownedSSLExData<MockQUICTransport> QUICMethodTest::ex_data_;
 
-// Test a full handshake works.
+// Test a full handshake and resumption work.
 TEST_F(QUICMethodTest, Basic) {
   const SSL_QUIC_METHOD quic_method = {
       SetEncryptionSecretsCallback,
@@ -5034,6 +5034,56 @@
   EXPECT_TRUE(SSL_session_reused(server_.get()));
 }
 
+// Test that HelloRetryRequest in QUIC works.
+TEST_F(QUICMethodTest, HelloRetryRequest) {
+  const SSL_QUIC_METHOD quic_method = {
+      SetEncryptionSecretsCallback,
+      AddHandshakeDataCallback,
+      FlushFlightCallback,
+      SendAlertCallback,
+  };
+
+  ASSERT_TRUE(SSL_CTX_set_quic_method(client_ctx_.get(), &quic_method));
+  ASSERT_TRUE(SSL_CTX_set_quic_method(server_ctx_.get(), &quic_method));
+
+  // BoringSSL predicts the most preferred curve, so using different preferences
+  // will trigger HelloRetryRequest.
+  static const int kClientPrefs[] = {NID_X25519, NID_X9_62_prime256v1};
+  ASSERT_TRUE(SSL_CTX_set1_curves(client_ctx_.get(), kClientPrefs,
+                                  OPENSSL_ARRAY_SIZE(kClientPrefs)));
+  static const int kServerPrefs[] = {NID_X9_62_prime256v1, NID_X25519};
+  ASSERT_TRUE(SSL_CTX_set1_curves(server_ctx_.get(), kServerPrefs,
+                                  OPENSSL_ARRAY_SIZE(kServerPrefs)));
+
+  ASSERT_TRUE(CreateClientAndServer());
+
+  for (;;) {
+    ASSERT_TRUE(ProvideHandshakeData(client_.get()));
+    int client_ret = SSL_do_handshake(client_.get());
+    if (client_ret != 1) {
+      ASSERT_EQ(client_ret, -1);
+      ASSERT_EQ(SSL_get_error(client_.get(), client_ret), SSL_ERROR_WANT_READ);
+    }
+
+    ASSERT_TRUE(ProvideHandshakeData(server_.get()));
+    int server_ret = SSL_do_handshake(server_.get());
+    if (server_ret != 1) {
+      ASSERT_EQ(server_ret, -1);
+      ASSERT_EQ(SSL_get_error(server_.get(), server_ret), SSL_ERROR_WANT_READ);
+    }
+
+    if (client_ret == 1 && server_ret == 1) {
+      break;
+    }
+  }
+
+  EXPECT_EQ(SSL_do_handshake(client_.get()), 1);
+  EXPECT_EQ(SSL_do_handshake(server_.get()), 1);
+  EXPECT_TRUE(transport_.SecretsMatch(ssl_encryption_application));
+  EXPECT_FALSE(transport_.client()->has_alert());
+  EXPECT_FALSE(transport_.server()->has_alert());
+}
+
 // Test only releasing data to QUIC one byte at a time on request, to maximize
 // state machine pauses. Additionally, test that existing asynchronous callbacks
 // still work.