|
26 | 26 |
|
27 | 27 | #include <openssl/aead.h>
|
28 | 28 | #include <openssl/base64.h>
|
| 29 | +#include <openssl/bytestring.h> |
29 | 30 | #include <openssl/bio.h>
|
30 | 31 | #include <openssl/cipher.h>
|
31 | 32 | #include <openssl/crypto.h>
|
@@ -7369,5 +7370,126 @@ TEST(SSLTest, CanReleasePrivateKey) {
|
7369 | 7370 | }
|
7370 | 7371 | }
|
7371 | 7372 |
|
| 7373 | +// GetExtensionOrder sets |*out| to the list of extensions a client attached to |
| 7374 | +// |ctx| will send in the ClientHello. If |ech_keys| is non-null, the client |
| 7375 | +// will offer ECH with the public component. If |decrypt_ech| is true, |*out| |
| 7376 | +// will be set to the ClientHelloInner's extensions, rather than |
| 7377 | +// ClientHelloOuter. |
| 7378 | +static bool GetExtensionOrder(SSL_CTX *client_ctx, std::vector<uint16_t> *out, |
| 7379 | + SSL_ECH_KEYS *ech_keys, bool decrypt_ech) { |
| 7380 | + struct AppData { |
| 7381 | + std::vector<uint16_t> *out; |
| 7382 | + bool decrypt_ech; |
| 7383 | + bool callback_done = false; |
| 7384 | + }; |
| 7385 | + AppData app_data; |
| 7386 | + app_data.out = out; |
| 7387 | + app_data.decrypt_ech = decrypt_ech; |
| 7388 | + |
| 7389 | + bssl::UniquePtr<SSL_CTX> server_ctx = |
| 7390 | + CreateContextWithTestCertificate(TLS_method()); |
| 7391 | + if (!server_ctx || // |
| 7392 | + !SSL_CTX_set_app_data(server_ctx.get(), &app_data) || |
| 7393 | + (decrypt_ech && !SSL_CTX_set1_ech_keys(server_ctx.get(), ech_keys))) { |
| 7394 | + return false; |
| 7395 | + } |
| 7396 | + |
| 7397 | + // Configure the server to record the ClientHello extension order. We use a |
| 7398 | + // server rather than |GetClientHello| so it can decrypt ClientHelloInner. |
| 7399 | + SSL_CTX_set_select_certificate_cb( |
| 7400 | + server_ctx.get(), |
| 7401 | + [](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t { |
| 7402 | + AppData *app_data_ptr = static_cast<AppData *>( |
| 7403 | + SSL_CTX_get_app_data(SSL_get_SSL_CTX(client_hello->ssl))); |
| 7404 | + EXPECT_EQ(app_data_ptr->decrypt_ech ? 1 : 0, |
| 7405 | + SSL_ech_accepted(client_hello->ssl)); |
| 7406 | + |
| 7407 | + app_data_ptr->out->clear(); |
| 7408 | + CBS extensions; |
| 7409 | + CBS_init(&extensions, client_hello->extensions, |
| 7410 | + client_hello->extensions_len); |
| 7411 | + while (CBS_len(&extensions)) { |
| 7412 | + uint16_t type; |
| 7413 | + CBS body; |
| 7414 | + if (!CBS_get_u16(&extensions, &type) || |
| 7415 | + !CBS_get_u16_length_prefixed(&extensions, &body)) { |
| 7416 | + return ssl_select_cert_error; |
| 7417 | + } |
| 7418 | + app_data_ptr->out->push_back(type); |
| 7419 | + } |
| 7420 | + |
| 7421 | + // Don't bother completing the handshake. |
| 7422 | + app_data_ptr->callback_done = true; |
| 7423 | + return ssl_select_cert_error; |
| 7424 | + }); |
| 7425 | + |
| 7426 | + bssl::UniquePtr<SSL> client, server; |
| 7427 | + if (!CreateClientAndServer(&client, &server, client_ctx, server_ctx.get()) || |
| 7428 | + (ech_keys != nullptr && !InstallECHConfigList(client.get(), ech_keys))) { |
| 7429 | + return false; |
| 7430 | + } |
| 7431 | + |
| 7432 | + // Run the handshake far enough to process the ClientHello. |
| 7433 | + SSL_do_handshake(client.get()); |
| 7434 | + SSL_do_handshake(server.get()); |
| 7435 | + return app_data.callback_done; |
| 7436 | +} |
| 7437 | + |
| 7438 | +// Test that, when extension permutation is enabled, the ClientHello extension |
| 7439 | +// order changes, both with and without ECH, and in both ClientHelloInner and |
| 7440 | +// ClientHelloOuter. |
| 7441 | +TEST(SSLTest, PermuteExtensions) { |
| 7442 | + bssl::UniquePtr<SSL_ECH_KEYS> keys = MakeTestECHKeys(); |
| 7443 | + ASSERT_TRUE(keys); |
| 7444 | + for (bool offer_ech : {false, true}) { |
| 7445 | + SCOPED_TRACE(offer_ech); |
| 7446 | + SSL_ECH_KEYS *maybe_keys = offer_ech ? keys.get() : nullptr; |
| 7447 | + for (bool decrypt_ech : {false, true}) { |
| 7448 | + SCOPED_TRACE(decrypt_ech); |
| 7449 | + if (!offer_ech && decrypt_ech) { |
| 7450 | + continue; |
| 7451 | + } |
| 7452 | + |
| 7453 | + // When extension permutation is disabled, the order should be consistent. |
| 7454 | + bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); |
| 7455 | + ASSERT_TRUE(ctx); |
| 7456 | + std::vector<uint16_t> order1, order2; |
| 7457 | + ASSERT_TRUE( |
| 7458 | + GetExtensionOrder(ctx.get(), &order1, maybe_keys, decrypt_ech)); |
| 7459 | + ASSERT_TRUE( |
| 7460 | + GetExtensionOrder(ctx.get(), &order2, maybe_keys, decrypt_ech)); |
| 7461 | + EXPECT_EQ(order1, order2); |
| 7462 | + |
| 7463 | + ctx.reset(SSL_CTX_new(TLS_method())); |
| 7464 | + ASSERT_TRUE(ctx); |
| 7465 | + SSL_CTX_set_permute_extensions(ctx.get(), 1); |
| 7466 | + |
| 7467 | + // When extension permutation is enabled, each ClientHello should have a |
| 7468 | + // different order. |
| 7469 | + // |
| 7470 | + // This test is inherently flaky, so we run it multiple times. We send at |
| 7471 | + // least five extensions by default from TLS 1.3: supported_versions, |
| 7472 | + // key_share, supported_groups, psk_key_exchange_modes, and |
| 7473 | + // signature_algorithms. That means the probability of a false negative is |
| 7474 | + // at most 1/120. Repeating the test 14 times lowers false negative rate |
| 7475 | + // to under 2^-96. |
| 7476 | + ASSERT_TRUE( |
| 7477 | + GetExtensionOrder(ctx.get(), &order1, maybe_keys, decrypt_ech)); |
| 7478 | + EXPECT_GE(order1.size(), 5u); |
| 7479 | + static const int kNumIterations = 14; |
| 7480 | + bool passed = false; |
| 7481 | + for (int i = 0; i < kNumIterations; i++) { |
| 7482 | + ASSERT_TRUE( |
| 7483 | + GetExtensionOrder(ctx.get(), &order2, maybe_keys, decrypt_ech)); |
| 7484 | + if (order1 != order2) { |
| 7485 | + passed = true; |
| 7486 | + break; |
| 7487 | + } |
| 7488 | + } |
| 7489 | + EXPECT_TRUE(passed) << "Extensions were not permuted"; |
| 7490 | + } |
| 7491 | + } |
| 7492 | +} |
| 7493 | + |
7372 | 7494 | } // namespace
|
7373 | 7495 | BSSL_NAMESPACE_END
|
0 commit comments