Make SSL_get_client_CA_list slightly more OpenSSL-compatible.
SSL_get_client_CA_list is one of those dreaded functions which may query either
configuration state or handshake state. Moreover, it does so based on
|ssl->server|, which may not be configured until later. Also check
|ssl->handshake_func| to make sure |ssl| is not in an indeterminate state.
This also fixes a bug where SSL_get_client_CA_list wouldn't work in DTLS due to
the incorrect |ssl->version| check.
Change-Id: Ie564dbfeecd2c8257fd6bcb148bc5db827390c77
Reviewed-on: https://boringssl-review.googlesource.com/5827
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 296004f..46cb4c0 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -368,20 +368,20 @@
return ctx->client_CA;
}
-STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s) {
- if (s->server) {
- if (s->client_CA != NULL) {
- return s->client_CA;
- } else {
- return s->ctx->client_CA;
- }
- } else {
- if ((s->version >> 8) == SSL3_VERSION_MAJOR && s->s3 != NULL) {
- return s->s3->tmp.ca_names;
- } else {
- return NULL;
- }
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) {
+ /* For historical reasons, this function is used both to query configuration
+ * state on a server as well as handshake state on a client. However, whether
+ * |ssl| is a client or server is not known until explicitly configured with
+ * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an
+ * indeterminate mode and |ssl->server| is unset. */
+ if (ssl->handshake_func != NULL && !ssl->server) {
+ return ssl->s3->tmp.ca_names;
}
+
+ if (ssl->client_CA != NULL) {
+ return ssl->client_CA;
+ }
+ return ssl->ctx->client_CA;
}
static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x) {
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index 2944748..810d3fa 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -796,7 +796,29 @@
return true;
}
-int main(void) {
+// Test that |SSL_get_client_CA_list| echoes back the configured parameter even
+// before configuring as a server.
+static bool TestClientCAList() {
+ ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method()));
+ if (!ctx) {
+ return false;
+ }
+ ScopedSSL ssl(SSL_new(ctx.get()));
+ if (!ssl) {
+ return false;
+ }
+
+ STACK_OF(X509_NAME) *stack = sk_X509_NAME_new_null();
+ if (stack == nullptr) {
+ return false;
+ }
+ // |SSL_set_client_CA_list| takes ownership.
+ SSL_set_client_CA_list(ssl.get(), stack);
+
+ return SSL_get_client_CA_list(ssl.get()) == stack;
+}
+
+int main() {
SSL_library_init();
if (!TestCipherRules() ||
@@ -815,7 +837,8 @@
!TestDefaultVersion(DTLS1_VERSION, &DTLSv1_method) ||
!TestDefaultVersion(DTLS1_2_VERSION, &DTLSv1_2_method) ||
!TestCipherGetRFCName() ||
- !TestPaddingExtension()) {
+ !TestPaddingExtension() ||
+ !TestClientCAList()) {
ERR_print_errors_fp(stderr);
return 1;
}