Files
cli/vendor/aws-lc-sys/aws-lc/ssl/ssl_common_test.cc

690 lines
26 KiB
C++

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include "ssl_common_test.h"
#include <openssl/ssl.h>
#include <gtest/gtest.h>
#include "../crypto/test/test_util.h"
BSSL_NAMESPACE_BEGIN
UniquePtr<SSL_SESSION> g_last_session;
bool GetClientHello(SSL *ssl, std::vector<uint8_t> *out) {
bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
if (!bio) {
return false;
}
// Do not configure a reading BIO, but record what's written to a memory BIO.
BIO_up_ref(bio.get());
SSL_set_bio(ssl, nullptr /* rbio */, bio.get());
int ret = SSL_connect(ssl);
if (ret > 0) {
// SSL_connect should fail without a BIO to write to.
return false;
}
ERR_clear_error();
const uint8_t *client_hello = nullptr;
size_t client_hello_len = 0;
if (!BIO_mem_contents(bio.get(), &client_hello, &client_hello_len)) {
return false;
}
// We did not get far enough to write a ClientHello.
if (client_hello_len == 0) {
return false;
}
*out = std::vector<uint8_t>(client_hello, client_hello + client_hello_len);
return true;
}
// These test certificates generated with the following Go program.
/* clang-format off
func main() {
notBefore := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
notAfter := time.Date(2099, time.January, 1, 0, 0, 0, 0, time.UTC)
rootKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
rootTemplate := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: "Test CA"},
NotBefore: notBefore,
NotAfter: notAfter,
BasicConstraintsValid: true,
IsCA: true,
}
rootDER, _ := x509.CreateCertificate(rand.Reader, rootTemplate, rootTemplate, &rootKey.PublicKey, rootKey)
root, _ := x509.ParseCertificate(rootDER)
pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: rootDER})
leafKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
leafKeyDER, _ := x509.MarshalPKCS8PrivateKey(leafKey)
pem.Encode(os.Stdout, &pem.Block{Type: "PRIVATE KEY", Bytes: leafKeyDER})
for i, name := range []string{"public.example", "secret.example"} {
leafTemplate := &x509.Certificate{
SerialNumber: big.NewInt(int64(i) + 2),
Subject: pkix.Name{CommonName: name},
NotBefore: notBefore,
NotAfter: notAfter,
BasicConstraintsValid: true,
DNSNames: []string{name},
}
leafDER, _ := x509.CreateCertificate(rand.Reader, leafTemplate, root, &leafKey.PublicKey, rootKey)
pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: leafDER})
}
}
clang-format on */
UniquePtr<X509> GetLeafRoot() {
bssl::UniquePtr<X509> root = CertFromPEM(R"(
-----BEGIN CERTIFICATE-----
MIIBRzCB7aADAgECAgEBMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMTB1Rlc3QgQ0Ew
IBcNMDAwMTAxMDAwMDAwWhgPMjA5OTAxMDEwMDAwMDBaMBIxEDAOBgNVBAMTB1Rl
c3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT5JUjrI1DAxSpEl88UkmJw
tAJqxo/YrSFo9V3MkcNkfTixi5p6MUtO8DazhEgekBcd2+tBAWtl7dy0qpvTqx92
ozIwMDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTw6ftkexAI6o4r5FntJIfL
GU5F4zAKBggqhkjOPQQDAgNJADBGAiEAiiNowddQeHZaZFIygwe6RW5/WG4sUXWC
dkyl9CQzRaYCIQCFS1EvwZbZtMny27fYm1eeYciY0TkJTEi34H1KwyzzIA==
-----END CERTIFICATE-----
)");
EXPECT_TRUE(root);
return root;
}
UniquePtr<EVP_PKEY> GetLeafKey() {
bssl::UniquePtr<EVP_PKEY> leaf_key = KeyFromPEM(R"(
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgj5WKHwHnziiyPauf
7QukxTwtTyGZkk8qNdms4puJfxqhRANCAARNrkhxabALDlJrHtvkuDwvCWUF/oVC
hr6PDITHi1lDlJzvVT4aXBH87sH2n2UV5zpx13NHkq1bIC8eRT8eOIe0
-----END PRIVATE KEY-----
)");
EXPECT_TRUE(leaf_key);
return leaf_key;
}
UniquePtr<X509> GetLeafPublic() {
bssl::UniquePtr<X509> leaf_public = CertFromPEM(R"(
-----BEGIN CERTIFICATE-----
MIIBaDCCAQ6gAwIBAgIBAjAKBggqhkjOPQQDAjASMRAwDgYDVQQDEwdUZXN0IENB
MCAXDTAwMDEwMTAwMDAwMFoYDzIwOTkwMTAxMDAwMDAwWjAZMRcwFQYDVQQDEw5w
dWJsaWMuZXhhbXBsZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE2uSHFpsAsO
Umse2+S4PC8JZQX+hUKGvo8MhMeLWUOUnO9VPhpcEfzuwfafZRXnOnHXc0eSrVsg
Lx5FPx44h7SjTDBKMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU8On7ZHsQCOqO
K+RZ7SSHyxlOReMwGQYDVR0RBBIwEIIOcHVibGljLmV4YW1wbGUwCgYIKoZIzj0E
AwIDSAAwRQIhANqZRhDR/+QL05hsWXMYEwaiHifd9iakKoFEhKFchcF3AiBRAeXw
wRGGT6+iPmTYM6N5/IDyAb5B9Ke38O6lLEsUwA==
-----END CERTIFICATE-----
)");
EXPECT_TRUE(leaf_public);
return leaf_public;
}
UniquePtr<X509> GetLeafSecret() {
bssl::UniquePtr<X509> leaf_secret = CertFromPEM(R"(
-----BEGIN CERTIFICATE-----
MIIBaTCCAQ6gAwIBAgIBAzAKBggqhkjOPQQDAjASMRAwDgYDVQQDEwdUZXN0IENB
MCAXDTAwMDEwMTAwMDAwMFoYDzIwOTkwMTAxMDAwMDAwWjAZMRcwFQYDVQQDEw5z
ZWNyZXQuZXhhbXBsZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE2uSHFpsAsO
Umse2+S4PC8JZQX+hUKGvo8MhMeLWUOUnO9VPhpcEfzuwfafZRXnOnHXc0eSrVsg
Lx5FPx44h7SjTDBKMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU8On7ZHsQCOqO
K+RZ7SSHyxlOReMwGQYDVR0RBBIwEIIOc2VjcmV0LmV4YW1wbGUwCgYIKoZIzj0E
AwIDSQAwRgIhAPQdIz1xCFkc9WuSkxOxJDpywZiEp9SnKcxJ9nwrlRp3AiEA+O3+
XRqE7XFhHL+7TNC2a9OOAjQsEF137YPWo+rhgko=
-----END CERTIFICATE-----
)");
EXPECT_TRUE(leaf_secret);
return leaf_secret;
}
UniquePtr<X509> GetED25519TestCertificate() {
static const char kCertPEM[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIBRDCB9wIUKI+32tShPulvafJa3xZvj29Z9xgwBQYDK2VwMEUxCzAJBgNVBAYT\n"
"AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn\n"
"aXRzIFB0eSBMdGQwHhcNMjMwNzE4MTg0NzU4WhcNMjMwNzE5MTg0NzU4WjBFMQsw\n"
"CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu\n"
"ZXQgV2lkZ2l0cyBQdHkgTHRkMCowBQYDK2VwAyEAprAzqgxux8R4ZXaxn5mM/5E9\n"
"0RNE59r47BJikdOoeUwwBQYDK2VwA0EAMELt0XRGFYo4qkWwOsoSYcdGYqlxVlf9\n"
"AhTPaJ6SSzjv3n4r60wfe8Z2OPn415tcj2IIm42T64itI4OAX0aTCg==\n"
"-----END CERTIFICATE-----\n";
return CertFromPEM(kCertPEM);
}
UniquePtr<EVP_PKEY> GetED25519TestKey() {
static const char kKeyPEM[] =
"-----BEGIN PRIVATE KEY-----\n"
"MC4CAQAwBQYDK2VwBCIEIGPkz4xAobc5gtRidkHl+fxNLHfiWo3efRG2G8Z617yk\n"
"-----END PRIVATE KEY-----\n";
return KeyFromPEM(kKeyPEM);
}
// Functions used by SSL encode/decode tests.
static void EncodeAndDecodeSSL(SSL *in, SSL_CTX *ctx,
bssl::UniquePtr<SSL> *out) {
// Encoding SSL to bytes.
size_t encoded_len = 0;
bssl::UniquePtr<uint8_t> encoded;
uint8_t *encoded_raw = nullptr;
ASSERT_TRUE(SSL_to_bytes(in, &encoded_raw, &encoded_len));
ASSERT_TRUE(encoded_len) << "SSL_to_bytes failed. Error code: "
<< ERR_reason_error_string(ERR_get_error());
encoded.reset(encoded_raw);
// Decoding SSL from the bytes.
const uint8_t *ptr2 = encoded.get();
SSL *server2_ = SSL_from_bytes(ptr2, encoded_len, ctx);
ASSERT_TRUE(server2_) << "SSL_from_bytes failed. Error code: "
<< ERR_reason_error_string(ERR_get_error());
out->reset(server2_);
}
static void TransferBIOs(bssl::UniquePtr<SSL> *from, SSL *to, bool free_from) {
// Fetch the bio.
BIO *rbio = SSL_get_rbio(from->get());
ASSERT_TRUE(rbio) << "rbio is not set"
<< ERR_reason_error_string(ERR_get_error());
BIO *wbio = SSL_get_wbio(from->get());
ASSERT_TRUE(wbio) << "wbio is not set"
<< ERR_reason_error_string(ERR_get_error());
// Move the bio.
// Increase ref count of |rbio|.
// |SSL_set_bio(to, rbio, wbio)| only increments the references of |rbio| by 1
// when |rbio == wbio|. But |SSL_free| decreases the reference of |rbio| and
// |wbio|.
if (rbio == wbio) {
BIO_up_ref(rbio);
}
SSL_set_bio(to, rbio, wbio);
// TODO: test half read and write hold by SSL.
// TODO: add a test to check error code?
// e.g. ASSERT_EQ(SSL_get_error(server1_, 0), SSL_ERROR_ZERO_RETURN);
if(free_from) {
SSL_free(from->release());
}
}
// TransferSSL performs SSL transfer by
// 1. Encode the SSL of |in| into bytes.
// 2. Decode the bytes into a new SSL.
// 3. Free the SSL of |in|.
// 4. If |out| is not nullptr, |out| will hold the decoded SSL.
// Else, |in| will get reset to hold the decoded SSL.
void TransferSSL(UniquePtr<SSL> *in, SSL_CTX *in_ctx,
bssl::UniquePtr<SSL> *out, bool free_in) {
bssl::UniquePtr<SSL> decoded_ssl;
EncodeAndDecodeSSL(in->get(), in_ctx, &decoded_ssl);
if (!decoded_ssl) {
return;
}
// Transfer the bio.
TransferBIOs(in, decoded_ssl.get(), free_in);
if (out == nullptr) {
in->reset(decoded_ssl.release());
} else {
out->reset(decoded_ssl.release());
}
}
bool ConnectClientAndServer(UniquePtr<SSL> *out_client,
UniquePtr<SSL> *out_server, SSL_CTX *client_ctx,
SSL_CTX *server_ctx, const ClientConfig &config,
bool shed_handshake_config) {
bssl::UniquePtr<SSL> client, server;
if (!CreateClientAndServer(&client, &server, client_ctx, server_ctx)) {
return false;
}
if (config.early_data) {
SSL_set_early_data_enabled(client.get(), 1);
}
if (config.session) {
SSL_set_session(client.get(), config.session);
}
if (!config.servername.empty() &&
!SSL_set_tlsext_host_name(client.get(), config.servername.c_str())) {
return false;
}
if (!config.verify_hostname.empty()) {
if (!SSL_set1_host(client.get(), config.verify_hostname.c_str())) {
return false;
}
SSL_set_hostflags(client.get(), config.hostflags);
}
SSL_set_shed_handshake_config(client.get(), shed_handshake_config);
SSL_set_shed_handshake_config(server.get(), shed_handshake_config);
if (!CompleteHandshakes(client.get(), server.get())) {
return false;
}
*out_client = std::move(client);
*out_server = std::move(server);
return true;
}
void ExpectSessionReused(SSL_CTX *client_ctx, SSL_CTX *server_ctx,
SSL_SESSION *session, bool want_reused) {
UniquePtr<SSL> client, server;
ClientConfig config;
config.session = session;
ASSERT_TRUE(
ConnectClientAndServer(&client, &server, client_ctx, server_ctx, config));
EXPECT_EQ(SSL_session_reused(client.get()), SSL_session_reused(server.get()));
bool was_reused = !!SSL_session_reused(client.get());
EXPECT_EQ(was_reused, want_reused);
}
UniquePtr<SSL_SESSION> CreateClientSession(SSL_CTX *client_ctx,
SSL_CTX *server_ctx,
const ClientConfig &config) {
g_last_session = nullptr;
SSL_CTX_sess_set_new_cb(client_ctx, SaveLastSession);
// Connect client and server to get a session.
bssl::UniquePtr<SSL> client, server;
if (!ConnectClientAndServer(&client, &server, client_ctx, server_ctx,
config) ||
!FlushNewSessionTickets(client.get(), server.get())) {
fprintf(stderr, "Failed to connect client and server.\n");
return nullptr;
}
SSL_CTX_sess_set_new_cb(client_ctx, nullptr);
if (!g_last_session) {
fprintf(stderr, "Client did not receive a session.\n");
return nullptr;
}
return std::move(g_last_session);
}
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;
}
}
}
uint16_t EpochFromSequence(uint64_t seq) {
return static_cast<uint16_t>(seq >> 48);
}
int SaveLastSession(SSL *ssl, SSL_SESSION *session) {
// Save the most recent session.
g_last_session.reset(session);
return 1;
}
UniquePtr<SSL_CTX> CreateContextWithTestCertificate(const SSL_METHOD *method) {
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
bssl::UniquePtr<X509> cert = GetTestCertificate();
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
if (!ctx || !cert || !key ||
!SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
!SSL_CTX_use_PrivateKey(ctx.get(), key.get())) {
return nullptr;
}
return ctx;
}
void SetUpExpectedNewCodePoint(SSL_CTX *ctx) {
SSL_CTX_set_select_certificate_cb(
ctx,
[](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
const uint8_t *data = nullptr;
size_t len = 0;
if (!SSL_early_callback_ctx_extension_get(
client_hello, TLSEXT_TYPE_application_settings, &data, &len)) {
ADD_FAILURE() << "Could not find alps new codepoint.";
return ssl_select_cert_error;
}
return ssl_select_cert_success;
});
}
UniquePtr<X509> GetTestCertificate() {
static const char kCertPEM[] =
"-----BEGIN CERTIFICATE-----\n"
"MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV\n"
"BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n"
"aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBF\n"
"MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n"
"ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n"
"gQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLci\n"
"HnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfV\n"
"W28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNV\n"
"HQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4f\n"
"Zbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA76Hht\n"
"ldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhr\n"
"T5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4f\n"
"j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==\n"
"-----END CERTIFICATE-----\n";
return CertFromPEM(kCertPEM);
}
UniquePtr<EVP_PKEY> GetTestKey() {
static const char kKeyPEM[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXgIBAAKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92\n"
"kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiF\n"
"KKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQAB\n"
"AoGBAIBy09Fd4DOq/Ijp8HeKuCMKTHqTW1xGHshLQ6jwVV2vWZIn9aIgmDsvkjCe\n"
"i6ssZvnbjVcwzSoByhjN8ZCf/i15HECWDFFh6gt0P5z0MnChwzZmvatV/FXCT0j+\n"
"WmGNB/gkehKjGXLLcjTb6dRYVJSCZhVuOLLcbWIV10gggJQBAkEA8S8sGe4ezyyZ\n"
"m4e9r95g6s43kPqtj5rewTsUxt+2n4eVodD+ZUlCULWVNAFLkYRTBCASlSrm9Xhj\n"
"QpmWAHJUkQJBAOVzQdFUaewLtdOJoPCtpYoY1zd22eae8TQEmpGOR11L6kbxLQsk\n"
"aMly/DOnOaa82tqAGTdqDEZgSNmCeKKknmECQAvpnY8GUOVAubGR6c+W90iBuQLj\n"
"LtFp/9ihd2w/PoDwrHZaoUYVcT4VSfJQog/k7kjE4MYXYWL8eEKg3WTWQNECQQDk\n"
"104Wi91Umd1PzF0ijd2jXOERJU1wEKe6XLkYYNHWQAe5l4J4MWj9OdxFXAxIuuR/\n"
"tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n"
"moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n"
"-----END RSA PRIVATE KEY-----\n";
return KeyFromPEM(kKeyPEM);
}
static bssl::UniquePtr<CRYPTO_BUFFER> BufferFromPEM(const char *pem) {
bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
char *name = nullptr, *header = nullptr;
uint8_t *data = nullptr;
long data_len = 0;
if (!PEM_read_bio(bio.get(), &name, &header, &data, &data_len)) {
return nullptr;
}
OPENSSL_free(name);
OPENSSL_free(header);
auto ret = bssl::UniquePtr<CRYPTO_BUFFER>(
CRYPTO_BUFFER_new(data, data_len, nullptr));
OPENSSL_free(data);
return ret;
}
UniquePtr<CRYPTO_BUFFER> GetChainTestCertificateBuffer() {
static const char kCertPEM[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIC0jCCAbqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEQiBD\n"
"QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs\n"
"aWVudCBDZXJ0IEEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRvaz8\n"
"CC/cshpCafJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/\n"
"kLRcH89M/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3\n"
"tHb+xs2PSs8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+c\n"
"IDs2rQ+lP7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1\n"
"z7C8jU50Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9V\n"
"iLeXANgZi+Xx9KgfAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI\n"
"KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBFEVbmYl+2RtNw\n"
"rDftRDF1v2QUbcN2ouSnQDHxeDQdSgasLzT3ui8iYu0Rw2WWcZ0DV5e0ztGPhWq7\n"
"AO0B120aFRMOY+4+bzu9Q2FFkQqc7/fKTvTDzIJI5wrMnFvUfzzvxh3OHWMYSs/w\n"
"giq33hTKeHEq6Jyk3btCny0Ycecyc3yGXH10sizUfiHlhviCkDuESk8mFDwDDzqW\n"
"ZF0IipzFbEDHoIxLlm3GQxpiLoEV4k8KYJp3R5KBLFyxM6UGPz8h72mIPCJp2RuK\n"
"MYgF91UDvVzvnYm6TfseM2+ewKirC00GOrZ7rEcFvtxnKSqYf4ckqfNdSU1Y+RRC\n"
"1ngWZ7Ih\n"
"-----END CERTIFICATE-----\n";
return BufferFromPEM(kCertPEM);
}
UniquePtr<EVP_PKEY> GetChainTestKey() {
static const char kKeyPEM[] =
"-----BEGIN PRIVATE KEY-----\n"
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRvaz8CC/cshpC\n"
"afJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/kLRcH89M\n"
"/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3tHb+xs2P\n"
"Ss8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+cIDs2rQ+l\n"
"P7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1z7C8jU50\n"
"Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9ViLeXANgZ\n"
"i+Xx9KgfAgMBAAECggEBAK0VjSJzkyPaamcyTVSWjo7GdaBGcK60lk657RjR+lK0\n"
"YJ7pkej4oM2hdsVZFsP8Cs4E33nXLa/0pDsRov/qrp0WQm2skwqGMC1I/bZ0WRPk\n"
"wHaDrBBfESWnJDX/AGpVtlyOjPmgmK6J2usMPihQUDkKdAYrVWJePrMIxt1q6BMe\n"
"iczs3qriMmtY3bUc4UyUwJ5fhDLjshHvfuIpYQyI6EXZM6dZksn9LylXJnigY6QJ\n"
"HxOYO0BDwOsZ8yQ8J8afLk88i0GizEkgE1z3REtQUwgWfxr1WV/ud+T6/ZhSAgH9\n"
"042mQvSFZnIUSEsmCvjhWuAunfxHKCTcAoYISWfzWpkCgYEA7gpf3HHU5Tn+CgUn\n"
"1X5uGpG3DmcMgfeGgs2r2f/IIg/5Ac1dfYILiybL1tN9zbyLCJfcbFpWBc9hJL6f\n"
"CPc5hUiwWFJqBJewxQkC1Ae/HakHbip+IZ+Jr0842O4BAArvixk4Lb7/N2Ct9sTE\n"
"NJO6RtK9lbEZ5uK61DglHy8CS2UCgYEA4ZC1o36kPAMQBggajgnucb2yuUEelk0f\n"
"AEr+GI32MGE+93xMr7rAhBoqLg4AITyIfEnOSQ5HwagnIHonBbv1LV/Gf9ursx8Z\n"
"YOGbvT8zzzC+SU1bkDzdjAYnFQVGIjMtKOBJ3K07++ypwX1fr4QsQ8uKL8WSOWwt\n"
"Z3Bym6XiZzMCgYADnhy+2OwHX85AkLt+PyGlPbmuelpyTzS4IDAQbBa6jcuW/2wA\n"
"UE2km75VUXmD+u2R/9zVuLm99NzhFhSMqlUxdV1YukfqMfP5yp1EY6m/5aW7QuIP\n"
"2MDa7TVL9rIFMiVZ09RKvbBbQxjhuzPQKL6X/PPspnhiTefQ+dl2k9xREQKBgHDS\n"
"fMfGNEeAEKezrfSVqxphE9/tXms3L+ZpnCaT+yu/uEr5dTIAawKoQ6i9f/sf1/Sy\n"
"xedsqR+IB+oKrzIDDWMgoJybN4pkZ8E5lzhVQIjFjKgFdWLzzqyW9z1gYfABQPlN\n"
"FiS20WX0vgP1vcKAjdNrHzc9zyHBpgQzDmAj3NZZAoGBAI8vKCKdH7w3aL5CNkZQ\n"
"2buIeWNA2HZazVwAGG5F2TU/LmXfRKnG6dX5bkU+AkBZh56jNZy//hfFSewJB4Kk\n"
"buB7ERSdaNbO21zXt9FEA3+z0RfMd/Zv2vlIWOSB5nzl/7UKti3sribK6s9ZVLfi\n"
"SxpiPQ8d/hmSGwn4ksrWUsJD\n"
"-----END PRIVATE KEY-----\n";
return KeyFromPEM(kKeyPEM);
}
UniquePtr<X509> GetChainTestIntermediate() {
return X509FromBuffer(GetChainTestIntermediateBuffer());
}
UniquePtr<X509> GetChainTestCertificate() {
return X509FromBuffer(GetChainTestCertificateBuffer());
}
UniquePtr<X509> X509FromBuffer(UniquePtr<CRYPTO_BUFFER> buffer) {
if (!buffer) {
return nullptr;
}
const uint8_t *derp = CRYPTO_BUFFER_data(buffer.get());
return bssl::UniquePtr<X509>(
d2i_X509(NULL, &derp, CRYPTO_BUFFER_len(buffer.get())));
}
UniquePtr<CRYPTO_BUFFER> GetChainTestIntermediateBuffer() {
static const char kCertPEM[] =
"-----BEGIN CERTIFICATE-----\n"
"MIICwjCCAaqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS\n"
"b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE\n"
"AwwEQiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALsSCYmDip2D\n"
"GkjFxw7ykz26JSjELkl6ArlYjFJ3aT/SCh8qbS4gln7RH8CPBd78oFdfhIKQrwtZ\n"
"3/q21ykD9BAS3qHe2YdcJfm8/kWAy5DvXk6NXU4qX334KofBAEpgdA/igEFq1P1l\n"
"HAuIfZCpMRfT+i5WohVsGi8f/NgpRvVaMONLNfgw57mz1lbtFeBEISmX0kbsuJxF\n"
"Qj/Bwhi5/0HAEXG8e7zN4cEx0yPRvmOATRdVb/8dW2pwOHRJq9R5M0NUkIsTSnL7\n"
"6N/z8hRAHMsV3IudC5Yd7GXW1AGu9a+iKU+Q4xcZCoj0DC99tL4VKujrV1kAeqsM\n"
"cz5/dKzi6+cCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n"
"AQYwDQYJKoZIhvcNAQELBQADggEBAIIeZiEeNhWWQ8Y4D+AGDwqUUeG8NjCbKrXQ\n"
"BlHg5wZ8xftFaiP1Dp/UAezmx2LNazdmuwrYB8lm3FVTyaPDTKEGIPS4wJKHgqH1\n"
"QPDhqNm85ey7TEtI9oYjsNim/Rb+iGkIAMXaxt58SzxbjvP0kMr1JfJIZbic9vye\n"
"NwIspMFIpP3FB8ywyu0T0hWtCQgL4J47nigCHpOu58deP88fS/Nyz/fyGVWOZ76b\n"
"WhWwgM3P3X95fQ3d7oFPR/bVh0YV+Cf861INwplokXgXQ3/TCQ+HNXeAMWn3JLWv\n"
"XFwk8owk9dq/kQGdndGgy3KTEW4ctPX5GNhf3LJ9Q7dLji4ReQ4=\n"
"-----END CERTIFICATE-----\n";
return BufferFromPEM(kCertPEM);
}
UniquePtr<X509> GetECDSATestCertificate() {
static const char kCertPEM[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIBzzCCAXagAwIBAgIJANlMBNpJfb/rMAkGByqGSM49BAEwRTELMAkGA1UEBhMC\n"
"QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp\n"
"dHMgUHR5IEx0ZDAeFw0xNDA0MjMyMzIxNTdaFw0xNDA1MjMyMzIxNTdaMEUxCzAJ\n"
"BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l\n"
"dCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATmK2ni\n"
"v2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYa\n"
"HPUdfvGULUvPciLBo1AwTjAdBgNVHQ4EFgQUq4TSrKuV8IJOFngHVVdf5CaNgtEw\n"
"HwYDVR0jBBgwFoAUq4TSrKuV8IJOFngHVVdf5CaNgtEwDAYDVR0TBAUwAwEB/zAJ\n"
"BgcqhkjOPQQBA0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13E\n"
"BwIgfB55FGohg/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ=\n"
"-----END CERTIFICATE-----\n";
return CertFromPEM(kCertPEM);
}
UniquePtr<EVP_PKEY> GetECDSATestKey() {
static const char kKeyPEM[] =
"-----BEGIN PRIVATE KEY-----\n"
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgBw8IcnrUoEqc3VnJ\n"
"TYlodwi1b8ldMHcO6NHJzgqLtGqhRANCAATmK2niv2Wfl74vHg2UikzVl2u3qR4N\n"
"Rvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYaHPUdfvGULUvPciLB\n"
"-----END PRIVATE KEY-----\n";
return KeyFromPEM(kKeyPEM);
}
bool ExpectSingleError(int lib, int reason) {
const char *expected = ERR_reason_error_string(ERR_PACK(lib, reason));
int err = ERR_get_error();
if (ERR_GET_LIB(err) != lib || ERR_GET_REASON(err) != reason) {
char buf[ERR_ERROR_STRING_BUF_LEN];
ERR_error_string_n(err, buf, sizeof(buf));
fprintf(stderr, "Wanted %s, got: %s.\n", expected, buf);
return false;
}
if (ERR_peek_error() != 0) {
fprintf(stderr, "Unexpected error following %s.\n", expected);
return false;
}
return true;
}
const char *GetVersionName(uint16_t version) {
switch (version) {
case TLS1_VERSION:
return "TLSv1";
case TLS1_1_VERSION:
return "TLSv1.1";
case TLS1_2_VERSION:
return "TLSv1.2";
case TLS1_3_VERSION:
return "TLSv1.3";
case DTLS1_VERSION:
return "DTLSv1";
case DTLS1_2_VERSION:
return "DTLSv1.2";
default:
return "???";
}
}
void FrozenTimeCallback(const SSL *ssl, timeval *out_clock) {
out_clock->tv_sec = 1000;
out_clock->tv_usec = 0;
}
bool ChainsEqual(STACK_OF(X509) *chain, const std::vector<X509 *> &expected) {
if (sk_X509_num(chain) != expected.size()) {
return false;
}
for (size_t i = 0; i < expected.size(); i++) {
if (X509_cmp(sk_X509_value(chain, i), expected[i]) != 0) {
return false;
}
}
return true;
}
UniquePtr<EVP_PKEY> KeyFromPEM(const char *pem) {
UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
if (!bio) {
return nullptr;
}
return bssl::UniquePtr<EVP_PKEY>(
PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
}
// CreateClientAndServer creates a client and server |SSL| objects whose |BIO|s
// are paired with each other. It does not run the handshake. The caller is
// expected to configure the objects and drive the handshake as needed.
bool CreateClientAndServer(bssl::UniquePtr<SSL> *out_client,
bssl::UniquePtr<SSL> *out_server,
SSL_CTX *client_ctx, SSL_CTX *server_ctx) {
UniquePtr<SSL> client(SSL_new(client_ctx)), server(SSL_new(server_ctx));
if (!client || !server) {
return false;
}
SSL_set_connect_state(client.get());
SSL_set_accept_state(server.get());
BIO *bio1 = nullptr, *bio2 = nullptr;
if (!BIO_new_bio_pair(&bio1, 0, &bio2, 0)) {
return false;
}
// SSL_set_bio takes ownership.
SSL_set_bio(client.get(), bio1, bio1);
SSL_set_bio(server.get(), bio2, bio2);
*out_client = std::move(client);
*out_server = std::move(server);
return true;
}
bool CompleteHandshakes(SSL *client, SSL *server) {
// Drive both their handshakes to completion.
for (;;) {
int client_ret = SSL_do_handshake(client);
int client_err = SSL_get_error(client, client_ret);
if (client_err != SSL_ERROR_NONE && client_err != SSL_ERROR_WANT_READ &&
client_err != SSL_ERROR_WANT_WRITE &&
client_err != SSL_ERROR_PENDING_TICKET) {
fprintf(stderr, "Client error: %s\n", SSL_error_description(client_err));
return false;
}
int server_ret = SSL_do_handshake(server);
int server_err = SSL_get_error(server, server_ret);
if (server_err != SSL_ERROR_NONE && server_err != SSL_ERROR_WANT_READ &&
server_err != SSL_ERROR_WANT_WRITE &&
server_err != SSL_ERROR_PENDING_TICKET) {
fprintf(stderr, "Server error: %s\n", SSL_error_description(server_err));
return false;
}
if (client_ret == 1 && server_ret == 1) {
break;
}
}
return true;
}
void SetUpExpectedOldCodePoint(SSL_CTX *ctx) {
SSL_CTX_set_select_certificate_cb(
ctx,
[](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
const uint8_t *data = nullptr;
size_t len = 0;
if (!SSL_early_callback_ctx_extension_get(
client_hello, TLSEXT_TYPE_application_settings_old, &data,
&len)) {
ADD_FAILURE() << "Could not find alps old codepoint.";
return ssl_select_cert_error;
}
return ssl_select_cert_success;
});
}
BSSL_NAMESPACE_END