Tidy up a few certificate-related utility functions.

These will all want to be shared with the TLS 1.3 handshake.

Change-Id: I4e50dc0ed2295d43c7ae800015d71c1406311801
Reviewed-on: https://boringssl-review.googlesource.com/8776
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/ssl/ssl_cert.c b/ssl/ssl_cert.c
index dead3ba..75f6ce0 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -417,6 +417,10 @@
   return add_client_CA(&ctx->client_CA, x509);
 }
 
+int ssl_has_certificate(const SSL *ssl) {
+  return ssl->cert->x509 != NULL && ssl_has_private_key(ssl);
+}
+
 int ssl_add_cert_to_cbb(CBB *cbb, X509 *x509) {
   int len = i2d_X509(x509, NULL);
   if (len < 0) {
@@ -441,12 +445,12 @@
 }
 
 int ssl_add_cert_chain(SSL *ssl, CBB *cbb) {
+  if (!ssl_has_certificate(ssl)) {
+    return CBB_add_u24(cbb, 0);
+  }
+
   CERT *cert = ssl->cert;
   X509 *x = cert->x509;
-  if (x == NULL) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET);
-    return 0;
-  }
 
   CBB child;
   if (!CBB_add_u24_length_prefixed(cbb, &child)) {
@@ -497,6 +501,34 @@
   return CBB_flush(cbb);
 }
 
+int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) {
+  CBB child, name_cbb;
+  if (!CBB_add_u16_length_prefixed(cbb, &child)) {
+    return 0;
+  }
+
+  STACK_OF(X509_NAME) *sk = SSL_get_client_CA_list(ssl);
+  if (sk == NULL) {
+    return CBB_flush(cbb);
+  }
+
+  for (size_t i = 0; i < sk_X509_NAME_num(sk); i++) {
+    X509_NAME *name = sk_X509_NAME_value(sk, i);
+    int len = i2d_X509_NAME(name, NULL);
+    if (len < 0) {
+      return 0;
+    }
+    uint8_t *ptr;
+    if (!CBB_add_u16_length_prefixed(&child, &name_cbb) ||
+        !CBB_add_space(&name_cbb, &ptr, (size_t)len) ||
+        (len > 0 && i2d_X509_NAME(name, &ptr) < 0)) {
+      return 0;
+    }
+  }
+
+  return CBB_flush(cbb);
+}
+
 static int set_cert_store(X509_STORE **store_ptr, X509_STORE *new_store, int take_ref) {
   X509_STORE_free(*store_ptr);
   *store_ptr = new_store;