Add functions to allow the mocking of AES hw support for testing. Bug: 586 Change-Id: I5bc8e6df3a5a14e6b218f41181d06406e835f9c1 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58605 Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/ssl/encrypted_client_hello.cc b/ssl/encrypted_client_hello.cc index 8d35f18..a5492e9 100644 --- a/ssl/encrypted_client_hello.cc +++ b/ssl/encrypted_client_hello.cc
@@ -601,8 +601,8 @@ static bool select_ech_cipher_suite(const EVP_HPKE_KDF **out_kdf, const EVP_HPKE_AEAD **out_aead, - Span<const uint8_t> cipher_suites) { - const bool has_aes_hardware = EVP_has_aes_hardware(); + Span<const uint8_t> cipher_suites, + const bool has_aes_hardware) { const EVP_HPKE_AEAD *aead = nullptr; CBS cbs = cipher_suites; while (CBS_len(&cbs) != 0) { @@ -660,7 +660,10 @@ const EVP_HPKE_AEAD *aead; if (supported && // ech_config.kem_id == EVP_HPKE_DHKEM_X25519_HKDF_SHA256 && - select_ech_cipher_suite(&kdf, &aead, ech_config.cipher_suites)) { + select_ech_cipher_suite(&kdf, &aead, ech_config.cipher_suites, + hs->ssl->config->aes_hw_override + ? hs->ssl->config->aes_hw_override_value + : EVP_has_aes_hardware())) { ScopedCBB info; static const uint8_t kInfoLabel[] = "tls ech"; // includes trailing NUL if (!CBB_init(info.get(), sizeof(kInfoLabel) + ech_config.raw.size()) || @@ -714,9 +717,11 @@ } const uint16_t kdf_id = EVP_HPKE_HKDF_SHA256; - const EVP_HPKE_AEAD *aead = EVP_has_aes_hardware() - ? EVP_hpke_aes_128_gcm() - : EVP_hpke_chacha20_poly1305(); + const bool has_aes_hw = hs->ssl->config->aes_hw_override + ? hs->ssl->config->aes_hw_override_value + : EVP_has_aes_hardware(); + const EVP_HPKE_AEAD *aead = + has_aes_hw ? EVP_hpke_aes_128_gcm() : EVP_hpke_chacha20_poly1305(); static_assert(ssl_grease_ech_config_id < sizeof(hs->grease_seed), "hs->grease_seed is too small"); uint8_t config_id = hs->grease_seed[ssl_grease_ech_config_id];
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc index 3e63019..7fe2a2b 100644 --- a/ssl/handshake_client.cc +++ b/ssl/handshake_client.cc
@@ -239,8 +239,12 @@ TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff, ssl->config->only_fips_cipher_suites_in_tls13); - if (!EVP_has_aes_hardware() && // - include_chacha20 && // + const bool has_aes_hw = ssl->config->aes_hw_override + ? ssl->config->aes_hw_override_value + : EVP_has_aes_hardware(); + + if (!has_aes_hw && // + include_chacha20 && // !CBB_add_u16(&child, TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { return false; } @@ -248,8 +252,8 @@ !CBB_add_u16(&child, TLS1_3_CK_AES_256_GCM_SHA384 & 0xffff)) { return false; } - if (EVP_has_aes_hardware() && // - include_chacha20 && // + if (has_aes_hw && // + include_chacha20 && // !CBB_add_u16(&child, TLS1_3_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) { return false; }
diff --git a/ssl/internal.h b/ssl/internal.h index b4d853a..15ad6c2 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -633,9 +633,11 @@ // newly-allocated |SSLCipherPreferenceList| containing the result. It returns // true on success and false on failure. If |strict| is true, nonsense will be // rejected. If false, nonsense will be silently ignored. An empty result is -// considered an error regardless of |strict|. +// considered an error regardless of |strict|. |has_aes_hw| indicates if the +// list should be ordered based on having support for AES in hardware or not. bool ssl_create_cipher_list(UniquePtr<SSLCipherPreferenceList> *out_cipher_list, - const char *rule_str, bool strict); + const bool has_aes_hw, const char *rule_str, + bool strict); // ssl_cipher_auth_mask_for_key returns the mask of cipher |algorithm_auth| // values suitable for use with |key| in TLS 1.2 and below. @@ -659,9 +661,12 @@ // ssl_choose_tls13_cipher returns an |SSL_CIPHER| corresponding with the best // available from |cipher_suites| compatible with |version|, |group_id|, and -// |only_fips|. It returns NULL if there isn't a compatible cipher. -const SSL_CIPHER *ssl_choose_tls13_cipher(CBS cipher_suites, uint16_t version, - uint16_t group_id, bool only_fips); +// |only_fips|. It returns NULL if there isn't a compatible cipher. |has_aes_hw| +// indicates if the choice should be made as if support for AES in hardware +// is available. +const SSL_CIPHER *ssl_choose_tls13_cipher(CBS cipher_suites, bool has_aes_hw, + uint16_t version, uint16_t group_id, + bool only_fips); // ssl_tls13_cipher_meets_policy returns true if |cipher_id| is acceptable given // |only_fips|. (For now there's only a single policy and so the policy argument @@ -3111,6 +3116,15 @@ // only_fips_cipher_suites_in_tls13 constrains the selection of cipher suites // in TLS 1.3 such that only FIPS approved ones will be selected. bool only_fips_cipher_suites_in_tls13 : 1; + + // aes_hw_override if set indicates we should override checking for aes + // hardware support, and use the value in aes_hw_override_value instead. + bool aes_hw_override : 1; + + // aes_hw_override_value is used for testing to indicate the support or lack + // of support for AES hw. The value is only considered if |aes_hw_override| is + // true. + bool aes_hw_override_value : 1; }; // From RFC 8446, used in determining PSK modes. @@ -3722,6 +3736,15 @@ // in TLS 1.3 such that only FIPS approved ones will be selected. bool only_fips_cipher_suites_in_tls13 : 1; + // aes_hw_override if set indicates we should override checking for AES + // hardware support, and use the value in aes_hw_override_value instead. + bool aes_hw_override : 1; + + // aes_hw_override_value is used for testing to indicate the support or lack + // of support for AES hardware. The value is only considered if + // |aes_hw_override| is true. + bool aes_hw_override_value : 1; + private: ~ssl_ctx_st(); friend OPENSSL_EXPORT void SSL_CTX_free(SSL_CTX *);
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc index eb9da0d..f8352f3 100644 --- a/ssl/s3_both.cc +++ b/ssl/s3_both.cc
@@ -663,7 +663,7 @@ // the client. class CipherScorer { public: - CipherScorer() : aes_is_fine_(EVP_has_aes_hardware()) {} + CipherScorer(bool has_aes_hw) : aes_is_fine_(has_aes_hw) {} typedef std::tuple<bool, bool> Score; @@ -702,14 +702,15 @@ } } -const SSL_CIPHER *ssl_choose_tls13_cipher(CBS cipher_suites, uint16_t version, - uint16_t group_id, bool only_fips) { +const SSL_CIPHER *ssl_choose_tls13_cipher(CBS cipher_suites, bool has_aes_hw, + uint16_t version, uint16_t group_id, + bool only_fips) { if (CBS_len(&cipher_suites) % 2 != 0) { return nullptr; } const SSL_CIPHER *best = nullptr; - CipherScorer scorer; + CipherScorer scorer(has_aes_hw); CipherScorer::Score best_score = scorer.MinScore(); while (CBS_len(&cipher_suites) > 0) {
diff --git a/ssl/ssl_cipher.cc b/ssl/ssl_cipher.cc index b08eb20..73564b3 100644 --- a/ssl/ssl_cipher.cc +++ b/ssl/ssl_cipher.cc
@@ -1148,7 +1148,8 @@ } bool ssl_create_cipher_list(UniquePtr<SSLCipherPreferenceList> *out_cipher_list, - const char *rule_str, bool strict) { + const bool has_aes_hw, const char *rule_str, + bool strict) { // Return with error if nothing to do. if (rule_str == NULL || out_cipher_list == NULL) { return false; @@ -1179,7 +1180,7 @@ // CHACHA20 unless there is hardware support for fast and constant-time // AES_GCM. Of the two CHACHA20 variants, the new one is preferred over the // old one. - if (EVP_has_aes_hardware()) { + if (has_aes_hw) { ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES128GCM, ~0u, 0, CIPHER_ADD, -1, false, &head, &tail); ssl_cipher_apply_rule(0, ~0u, ~0u, SSL_AES256GCM, ~0u, 0, CIPHER_ADD, -1,
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc index 86e8eb3..c035825 100644 --- a/ssl/ssl_lib.cc +++ b/ssl/ssl_lib.cc
@@ -484,6 +484,17 @@ return true; } +void SSL_CTX_set_aes_hw_override_for_testing(SSL_CTX *ctx, + bool override_value) { + ctx->aes_hw_override = true; + ctx->aes_hw_override_value = override_value; +} + +void SSL_set_aes_hw_override_for_testing(SSL *ssl, bool override_value) { + ssl->config->aes_hw_override = true; + ssl->config->aes_hw_override_value = override_value; +} + BSSL_NAMESPACE_END using namespace bssl; @@ -525,7 +536,9 @@ false_start_allowed_without_alpn(false), handoff(false), enable_early_data(false), - only_fips_cipher_suites_in_tls13(false) { + only_fips_cipher_suites_in_tls13(false), + aes_hw_override(false), + aes_hw_override_value(false) { CRYPTO_MUTEX_init(&lock); CRYPTO_new_ex_data(&ex_data); } @@ -647,6 +660,8 @@ ssl->config->permute_extensions = ctx->permute_extensions; ssl->config->only_fips_cipher_suites_in_tls13 = ctx->only_fips_cipher_suites_in_tls13; + ssl->config->aes_hw_override = ctx->aes_hw_override; + ssl->config->aes_hw_override_value = ctx->aes_hw_override_value; if (!ssl->config->supported_group_list.CopyFrom(ctx->supported_group_list) || !ssl->config->alpn_client_proto_list.CopyFrom( @@ -2026,18 +2041,27 @@ } int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) { - return ssl_create_cipher_list(&ctx->cipher_list, str, false /* not strict */); + const bool has_aes_hw = ctx->aes_hw_override ? ctx->aes_hw_override_value + : EVP_has_aes_hardware(); + return ssl_create_cipher_list(&ctx->cipher_list, has_aes_hw, str, + false /* not strict */); } int SSL_CTX_set_strict_cipher_list(SSL_CTX *ctx, const char *str) { - return ssl_create_cipher_list(&ctx->cipher_list, str, true /* strict */); + const bool has_aes_hw = ctx->aes_hw_override ? ctx->aes_hw_override_value + : EVP_has_aes_hardware(); + return ssl_create_cipher_list(&ctx->cipher_list, has_aes_hw, str, + true /* strict */); } int SSL_set_cipher_list(SSL *ssl, const char *str) { if (!ssl->config) { return 0; } - return ssl_create_cipher_list(&ssl->config->cipher_list, str, + const bool has_aes_hw = ssl->config->aes_hw_override + ? ssl->config->aes_hw_override_value + : EVP_has_aes_hardware(); + return ssl_create_cipher_list(&ssl->config->cipher_list, has_aes_hw, str, false /* not strict */); } @@ -2045,7 +2069,10 @@ if (!ssl->config) { return 0; } - return ssl_create_cipher_list(&ssl->config->cipher_list, str, + const bool has_aes_hw = ssl->config->aes_hw_override + ? ssl->config->aes_hw_override_value + : EVP_has_aes_hardware(); + return ssl_create_cipher_list(&ssl->config->cipher_list, has_aes_hw, str, true /* strict */); }
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index 684c254..c64bb16 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc
@@ -583,16 +583,14 @@ } uint16_t cipher_id = SSL_CIPHER_get_protocol_id(SSL_get_current_cipher(ssl)); - if (config->expect_cipher_aes != 0 && - EVP_has_aes_hardware() && + if (config->expect_cipher_aes != 0 && EVP_has_aes_hardware() && config->expect_cipher_aes != cipher_id) { fprintf(stderr, "Cipher ID was %04x, wanted %04x (has AES hardware)\n", cipher_id, config->expect_cipher_aes); return false; } - if (config->expect_cipher_no_aes != 0 && - !EVP_has_aes_hardware() && + if (config->expect_cipher_no_aes != 0 && !EVP_has_aes_hardware() && config->expect_cipher_no_aes != cipher_id) { fprintf(stderr, "Cipher ID was %04x, wanted %04x (no AES hardware)\n", cipher_id, config->expect_cipher_no_aes);
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc index 0bbe97f..c97e3f5 100644 --- a/ssl/tls13_server.cc +++ b/ssl/tls13_server.cc
@@ -116,8 +116,11 @@ const uint16_t version = ssl_protocol_version(ssl); - return ssl_choose_tls13_cipher(cipher_suites, version, group_id, - ssl->config->only_fips_cipher_suites_in_tls13); + return ssl_choose_tls13_cipher( + cipher_suites, + ssl->config->aes_hw_override ? ssl->config->aes_hw_override_value + : EVP_has_aes_hardware(), + version, group_id, ssl->config->only_fips_cipher_suites_in_tls13); } static bool add_new_session_tickets(SSL_HANDSHAKE *hs, bool *out_sent_tickets) {