Add SSL_CTX_set_verify_algorithm_prefs.
When writing tests and BoGo isn't available, it is useful to be able to
configure the set of signature algorithms accepted on the verify side.
Add an API for this.
Change-Id: Ic873189da7f8853e412acd68614df9d9a872a0c8
Reviewed-on: https://boringssl-review.googlesource.com/15125
Reviewed-by: Steven Valdez <svaldez@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/fuzz/ssl_ctx_api.cc b/fuzz/ssl_ctx_api.cc
index 60058fa..75066cd 100644
--- a/fuzz/ssl_ctx_api.cc
+++ b/fuzz/ssl_ctx_api.cc
@@ -354,8 +354,14 @@
SSL_CTX_set_cipher_list(ctx, ciphers.c_str());
},
[](SSL_CTX *ctx, CBS *cbs) {
- // This function was left blank rather than removed to avoid invalidating
- // the existing corpus. New entries may reuse it.
+ std::string verify_algos;
+ if (!GetString(&verify_algos, cbs)) {
+ return;
+ }
+
+ SSL_CTX_set_verify_algorithm_prefs(
+ ctx, reinterpret_cast<const uint16_t *>(verify_algos.data()),
+ verify_algos.size() / sizeof(uint16_t));
},
[](SSL_CTX *ctx, CBS *cbs) {
std::string ciphers;
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index c4b7387..b52d80c 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2366,9 +2366,17 @@
OPENSSL_EXPORT int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store);
/* SSL_CTX_set_ed25519_enabled configures whether |ctx| advertises support for
- * the Ed25519 signature algorithm. */
+ * the Ed25519 signature algorithm when using the default preference list. */
OPENSSL_EXPORT void SSL_CTX_set_ed25519_enabled(SSL_CTX *ctx, int enabled);
+/* SSL_CTX_set_verify_algorithm_prefs confingures |ctx| to use |prefs| as the
+ * preference list when verifying signature's from the peer's long-term key. It
+ * returns one on zero on error. |prefs| should not include the internal-only
+ * value |SSL_SIGN_RSA_PKCS1_MD5_SHA1|. */
+OPENSSL_EXPORT int SSL_CTX_set_verify_algorithm_prefs(SSL_CTX *ctx,
+ const uint16_t *prefs,
+ size_t num_prefs);
+
/* Client certificate CA list.
*
@@ -4245,6 +4253,11 @@
* session tickets. */
const SSL_TICKET_AEAD_METHOD *ticket_aead_method;
+ /* verify_sigalgs, if not empty, is the set of signature algorithms
+ * accepted from the peer in decreasing order of preference. */
+ uint16_t *verify_sigalgs;
+ size_t num_verify_sigalgs;
+
/* quiet_shutdown is true if the connection should not send a close_notify on
* shutdown. */
unsigned quiet_shutdown:1;
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 7db06d5..0806084 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -350,6 +350,7 @@
OPENSSL_free(ctx->supported_group_list);
OPENSSL_free(ctx->alpn_client_proto_list);
EVP_PKEY_free(ctx->tlsext_channel_id_private);
+ OPENSSL_free(ctx->verify_sigalgs);
OPENSSL_free(ctx);
}
diff --git a/ssl/ssl_privkey.c b/ssl/ssl_privkey.c
index 57fb0dd..f429c1d 100644
--- a/ssl/ssl_privkey.c
+++ b/ssl/ssl_privkey.c
@@ -222,30 +222,38 @@
ctx->cert->key_method = key_method;
}
-static int set_signing_algorithm_prefs(CERT *cert, const uint16_t *prefs,
- size_t num_prefs) {
- OPENSSL_free(cert->sigalgs);
+static int set_algorithm_prefs(uint16_t **out_prefs, size_t *out_num_prefs,
+ const uint16_t *prefs, size_t num_prefs) {
+ OPENSSL_free(*out_prefs);
- cert->num_sigalgs = 0;
- cert->sigalgs = BUF_memdup(prefs, num_prefs * sizeof(prefs[0]));
- if (cert->sigalgs == NULL) {
+ *out_num_prefs = 0;
+ *out_prefs = BUF_memdup(prefs, num_prefs * sizeof(prefs[0]));
+ if (*out_prefs == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
- cert->num_sigalgs = num_prefs;
+ *out_num_prefs = num_prefs;
return 1;
}
int SSL_CTX_set_signing_algorithm_prefs(SSL_CTX *ctx, const uint16_t *prefs,
size_t num_prefs) {
- return set_signing_algorithm_prefs(ctx->cert, prefs, num_prefs);
+ return set_algorithm_prefs(&ctx->cert->sigalgs, &ctx->cert->num_sigalgs,
+ prefs, num_prefs);
}
int SSL_set_signing_algorithm_prefs(SSL *ssl, const uint16_t *prefs,
size_t num_prefs) {
- return set_signing_algorithm_prefs(ssl->cert, prefs, num_prefs);
+ return set_algorithm_prefs(&ssl->cert->sigalgs, &ssl->cert->num_sigalgs,
+ prefs, num_prefs);
+}
+
+int SSL_CTX_set_verify_algorithm_prefs(SSL_CTX *ctx, const uint16_t *prefs,
+ size_t num_prefs) {
+ return set_algorithm_prefs(&ctx->verify_sigalgs, &ctx->num_verify_sigalgs,
+ prefs, num_prefs);
}
int SSL_set_private_key_digest_prefs(SSL *ssl, const int *digest_nids,
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index fe038b8..c2a5dde 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -515,12 +515,20 @@
}
int tls12_add_verify_sigalgs(const SSL *ssl, CBB *out) {
- for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kVerifySignatureAlgorithms); i++) {
- if (kVerifySignatureAlgorithms[i] == SSL_SIGN_ED25519 &&
+ const uint16_t *sigalgs = kVerifySignatureAlgorithms;
+ size_t num_sigalgs = OPENSSL_ARRAY_SIZE(kVerifySignatureAlgorithms);
+ if (ssl->ctx->num_verify_sigalgs != 0) {
+ sigalgs = ssl->ctx->verify_sigalgs;
+ num_sigalgs = ssl->ctx->num_verify_sigalgs;
+ }
+
+ for (size_t i = 0; i < num_sigalgs; i++) {
+ if (sigalgs == kVerifySignatureAlgorithms &&
+ sigalgs[i] == SSL_SIGN_ED25519 &&
!ssl->ctx->ed25519_enabled) {
continue;
}
- if (!CBB_add_u16(out, kVerifySignatureAlgorithms[i])) {
+ if (!CBB_add_u16(out, sigalgs[i])) {
return 0;
}
}
@@ -529,12 +537,20 @@
}
int tls12_check_peer_sigalg(SSL *ssl, int *out_alert, uint16_t sigalg) {
- for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kVerifySignatureAlgorithms); i++) {
- if (kVerifySignatureAlgorithms[i] == SSL_SIGN_ED25519 &&
+ const uint16_t *sigalgs = kVerifySignatureAlgorithms;
+ size_t num_sigalgs = OPENSSL_ARRAY_SIZE(kVerifySignatureAlgorithms);
+ if (ssl->ctx->num_verify_sigalgs != 0) {
+ sigalgs = ssl->ctx->verify_sigalgs;
+ num_sigalgs = ssl->ctx->num_verify_sigalgs;
+ }
+
+ for (size_t i = 0; i < num_sigalgs; i++) {
+ if (sigalgs == kVerifySignatureAlgorithms &&
+ sigalgs[i] == SSL_SIGN_ED25519 &&
!ssl->ctx->ed25519_enabled) {
continue;
}
- if (sigalg == kVerifySignatureAlgorithms[i]) {
+ if (sigalg == sigalgs[i]) {
return 1;
}
}
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index bbdd344..d57339f 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -1157,6 +1157,15 @@
SSL_CTX_set_ed25519_enabled(ssl_ctx.get(), 1);
}
+ if (!config->verify_prefs.empty()) {
+ std::vector<uint16_t> u16s(config->verify_prefs.begin(),
+ config->verify_prefs.end());
+ if (!SSL_CTX_set_verify_algorithm_prefs(ssl_ctx.get(), u16s.data(),
+ u16s.size())) {
+ return nullptr;
+ }
+ }
+
return ssl_ctx;
}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index dd6926d..b795d0a 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -7658,6 +7658,75 @@
expectedLocalError: "remote error: illegal parameter",
expectedError: ":WRONG_SIGNATURE_TYPE:",
})
+
+ // Test that configuring verify preferences changes what the client
+ // advertises.
+ testCases = append(testCases, testCase{
+ name: "VerifyPreferences-Advertised",
+ config: Config{
+ Certificates: []Certificate{rsaCertificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ signatureRSAPSSWithSHA384,
+ signatureRSAPSSWithSHA512,
+ },
+ },
+ flags: []string{
+ "-verify-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA384)),
+ "-expect-peer-signature-algorithm", strconv.Itoa(int(signatureRSAPSSWithSHA384)),
+ },
+ })
+
+ // Test that the client advertises a set which the runner can find
+ // nothing in common with.
+ testCases = append(testCases, testCase{
+ name: "VerifyPreferences-NoCommonAlgorithms",
+ config: Config{
+ Certificates: []Certificate{rsaCertificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ signatureRSAPSSWithSHA512,
+ },
+ },
+ flags: []string{
+ "-verify-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA384)),
+ },
+ shouldFail: true,
+ expectedLocalError: "tls: no common signature algorithms",
+ })
+
+ // Test that the client enforces its preferences when configured.
+ testCases = append(testCases, testCase{
+ name: "VerifyPreferences-Enforced",
+ config: Config{
+ Certificates: []Certificate{rsaCertificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ signatureRSAPSSWithSHA512,
+ },
+ Bugs: ProtocolBugs{
+ IgnorePeerSignatureAlgorithmPreferences: true,
+ },
+ },
+ flags: []string{
+ "-verify-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA384)),
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: illegal parameter",
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ // Test that explicitly configuring Ed25519 is as good as changing the
+ // boolean toggle.
+ testCases = append(testCases, testCase{
+ name: "VerifyPreferences-Ed25519",
+ config: Config{
+ Certificates: []Certificate{ed25519Certificate},
+ },
+ flags: []string{
+ "-verify-prefs", strconv.Itoa(int(signatureEd25519)),
+ },
+ })
}
// timeouts is the retransmit schedule for BoringSSL. It doubles and
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 77fc89f..5c5d346 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -195,6 +195,7 @@
const Flag<std::vector<int>> kIntVectorFlags[] = {
{ "-signing-prefs", &TestConfig::signing_prefs },
+ { "-verify-prefs", &TestConfig::verify_prefs },
};
} // namespace
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index 24e6f69..279b13d 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -27,6 +27,7 @@
bool fallback_scsv = false;
std::string digest_prefs;
std::vector<int> signing_prefs;
+ std::vector<int> verify_prefs;
std::string key_file;
std::string cert_file;
std::string expected_server_name;