Add ssl_has_CA_names and ssl_add_CA_names

Change-Id: I22866c72e9cacbcceb48fc7c99dd22a5ff7edeae
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/71609
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/ssl/internal.h b/ssl/internal.h
index ccb66e0..c34e9d9 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1629,13 +1629,21 @@
                                                      uint8_t *out_alert,
                                                      CBS *cbs);
 
-// ssl_has_client_CAs returns there are configured CAs.
+// ssl_has_client_CAs returns whether there are configured CAs.
 bool ssl_has_client_CAs(const SSL_CONFIG *cfg);
 
 // ssl_add_client_CA_list adds the configured CA list to |cbb| in the format
 // used by a TLS CertificateRequest message. It returns true on success and
 // false on error.
-bool ssl_add_client_CA_list(SSL_HANDSHAKE *hs, CBB *cbb);
+bool ssl_add_client_CA_list(const SSL_HANDSHAKE *hs, CBB *cbb);
+
+// ssl_has_CA_names returns whether there are configured CA names.
+bool ssl_has_CA_names(const SSL_CONFIG *cfg);
+
+// ssl_add_CA_names adds the configured CA_names list to |cbb| in the format
+// used by a TLS Certificate Authorities extension. It returns true on success
+// and false on error.
+bool ssl_add_CA_names(const SSL_HANDSHAKE *hs, CBB *cbb);
 
 // ssl_check_leaf_certificate returns one if |pkey| and |leaf| are suitable as
 // a server's leaf certificate for |hs|. Otherwise, it returns zero and pushes
diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc
index 68e155c..541097c 100644
--- a/ssl/ssl_cert.cc
+++ b/ssl/ssl_cert.cc
@@ -513,28 +513,29 @@
   return ret;
 }
 
-bool ssl_has_client_CAs(const SSL_CONFIG *cfg) {
-  const STACK_OF(CRYPTO_BUFFER) *names = cfg->client_CA.get();
-  if (names == nullptr) {
-    names = cfg->ssl->ctx->client_CA.get();
+static bool CA_names_non_empty(const STACK_OF(CRYPTO_BUFFER) *config_names,
+                               const STACK_OF(CRYPTO_BUFFER) *ctx_names) {
+  if (config_names != nullptr) {
+    return sk_CRYPTO_BUFFER_num(config_names) > 0;
   }
-  if (names == nullptr) {
-    return false;
+  if (ctx_names != nullptr) {
+    return sk_CRYPTO_BUFFER_num(ctx_names) > 0;
   }
-  return sk_CRYPTO_BUFFER_num(names) > 0;
+  return false;
 }
 
-bool ssl_add_client_CA_list(SSL_HANDSHAKE *hs, CBB *cbb) {
+
+static bool marshal_CA_names(const STACK_OF(CRYPTO_BUFFER) *config_names,
+                             const STACK_OF(CRYPTO_BUFFER) *ctx_names,
+                             CBB *cbb) {
+  const STACK_OF(CRYPTO_BUFFER) *names = config_names == nullptr ? ctx_names : config_names;
   CBB child, name_cbb;
+
   if (!CBB_add_u16_length_prefixed(cbb, &child)) {
     return false;
   }
 
-  const STACK_OF(CRYPTO_BUFFER) *names = hs->config->client_CA.get();
-  if (names == NULL) {
-    names = hs->ssl->ctx->client_CA.get();
-  }
-  if (names == NULL) {
+  if (names == nullptr) {
     return CBB_flush(cbb);
   }
 
@@ -549,6 +550,22 @@
   return CBB_flush(cbb);
 }
 
+bool ssl_has_client_CAs(const SSL_CONFIG *cfg) {
+  return CA_names_non_empty(cfg->client_CA.get(), cfg->ssl->ctx->client_CA.get());
+}
+
+bool ssl_has_CA_names(const SSL_CONFIG *cfg) {
+  return CA_names_non_empty(cfg->CA_names.get(), cfg->ssl->ctx->CA_names.get());
+}
+
+bool ssl_add_client_CA_list(const SSL_HANDSHAKE *hs, CBB *cbb) {
+  return marshal_CA_names(hs->config->client_CA.get(), hs->ssl->ctx->client_CA.get(), cbb);
+}
+
+bool ssl_add_CA_names(const SSL_HANDSHAKE *hs, CBB *cbb) {
+  return marshal_CA_names(hs->config->CA_names.get(), hs->ssl->ctx->CA_names.get(), cbb);
+}
+
 bool ssl_check_leaf_certificate(SSL_HANDSHAKE *hs, EVP_PKEY *pkey,
                                 const CRYPTO_BUFFER *leaf) {
   assert(ssl_protocol_version(hs->ssl) < TLS1_3_VERSION);