Skip to content

Commit

Permalink
Separate ca_names handling for client and server
Browse files Browse the repository at this point in the history
SSL(_CTX)?_set_client_CA_list() was a server side only function in 1.1.0.
If it was called on the client side then it was ignored. In 1.1.1 it now
makes sense to have a CA list defined for both client and server (the
client now sends it the the TLSv1.3 certificate_authorities extension).
Unfortunately some applications were using the same SSL_CTX for both
clients and servers and this resulted in some client ClientHellos being
excessively large due to the number of certificate authorities being sent.

This commit seperates out the CA list updated by
SSL(_CTX)?_set_client_CA_list() and the more generic
SSL(_CTX)?_set0_CA_list(). This means that SSL(_CTX)?_set_client_CA_list()
still has no effect on the client side. If both CA lists are set then
SSL(_CTX)?_set_client_CA_list() takes priority.

Fixes openssl#7411

Reviewed-by: Viktor Dukhovni <[email protected]>
(Merged from openssl#7503)
  • Loading branch information
mattcaswell committed Nov 12, 2018
1 parent 24ae003 commit 9873297
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 28 deletions.
5 changes: 4 additions & 1 deletion doc/man3/SSL_CTX_set0_CA_list.pod
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ has sent.
=head1 NOTES

These functions are generalised versions of the client authentication
CA list functions such as L<SSL_CTX_set_client_CA_list(3)>.
CA list functions such as L<SSL_CTX_set_client_CA_list(3)>. If both these
and L<SSL_CTX_set_client_CA_list(3)> or similar functions are used, then the
latter functions take priority on the server side (they are ignored on the
client side).

For TLS versions before 1.3 the list of CA names is only sent from the server
to client when requesting a client certificate. So any list of CA names set
Expand Down
5 changes: 5 additions & 0 deletions doc/man3/SSL_CTX_set_client_CA_list.pod
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ the chosen B<ssl>, overriding the setting valid for B<ssl>'s SSL_CTX object.

=head1 NOTES

These functions are similar to L<SSL_CTX_set0_CA_list(3)> and similar functions
but only have an effect on the server side. These functions are present for
backwards compatibility. L<SSL_CTX_set0_CA_list(3)> and similar functions should
be used in preference.

When a TLS/SSL server requests a client certificate (see
B<SSL_CTX_set_verify(3)>), it sends a list of CAs, for which
it will accept certificates, to the client.
Expand Down
13 changes: 7 additions & 6 deletions ssl/ssl_cert.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,17 +501,17 @@ const STACK_OF(X509_NAME) *SSL_get0_CA_list(const SSL *s)

void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list)
{
SSL_CTX_set0_CA_list(ctx, name_list);
set0_CA_list(&ctx->client_ca_names, name_list);
}

STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx)
{
return ctx->ca_names;
return ctx->client_ca_names;
}

void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list)
{
SSL_set0_CA_list(s, name_list);
set0_CA_list(&s->client_ca_names, name_list);
}

const STACK_OF(X509_NAME) *SSL_get0_peer_CA_list(const SSL *s)
Expand All @@ -523,7 +523,8 @@ STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s)
{
if (!s->server)
return s->s3 != NULL ? s->s3->tmp.peer_ca_names : NULL;
return s->ca_names != NULL ? s->ca_names : s->ctx->ca_names;
return s->client_ca_names != NULL ? s->client_ca_names
: s->ctx->client_ca_names;
}

static int add_ca_name(STACK_OF(X509_NAME) **sk, const X509 *x)
Expand Down Expand Up @@ -561,12 +562,12 @@ int SSL_CTX_add1_to_CA_list(SSL_CTX *ctx, const X509 *x)
*/
int SSL_add_client_CA(SSL *ssl, X509 *x)
{
return add_ca_name(&ssl->ca_names, x);
return add_ca_name(&ssl->client_ca_names, x);
}

int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x)
{
return add_ca_name(&ctx->ca_names, x);
return add_ca_name(&ctx->client_ca_names, x);
}

static int xname_cmp(const X509_NAME *a, const X509_NAME *b)
Expand Down
51 changes: 38 additions & 13 deletions ssl/ssl_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,7 @@ void SSL_free(SSL *s)
EVP_MD_CTX_free(s->pha_dgst);

sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free);
sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free);

sk_X509_pop_free(s->verified_chain, X509_free);

Expand Down Expand Up @@ -2953,6 +2954,9 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
if ((ret->ca_names = sk_X509_NAME_new_null()) == NULL)
goto err;

if ((ret->client_ca_names = sk_X509_NAME_new_null()) == NULL)
goto err;

if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data))
goto err;

Expand Down Expand Up @@ -3110,6 +3114,7 @@ void SSL_CTX_free(SSL_CTX *a)
sk_SSL_CIPHER_free(a->tls13_ciphersuites);
ssl_cert_free(a->cert);
sk_X509_NAME_pop_free(a->ca_names, X509_NAME_free);
sk_X509_NAME_pop_free(a->client_ca_names, X509_NAME_free);
sk_X509_pop_free(a->extra_certs, X509_free);
a->comp_methods = NULL;
#ifndef OPENSSL_NO_SRTP
Expand Down Expand Up @@ -3655,10 +3660,38 @@ const char *SSL_get_version(const SSL *s)
return ssl_protocol_to_string(s->version);
}

SSL *SSL_dup(SSL *s)
static int dup_ca_names(STACK_OF(X509_NAME) **dst, STACK_OF(X509_NAME) *src)
{
STACK_OF(X509_NAME) *sk;
X509_NAME *xn;
int i;

if (src == NULL) {
*dst = NULL;
return 1;
}

if ((sk = sk_X509_NAME_new_null()) == NULL)
return 0;
for (i = 0; i < sk_X509_NAME_num(src); i++) {
xn = X509_NAME_dup(sk_X509_NAME_value(src, i));
if (xn == NULL) {
sk_X509_NAME_pop_free(sk, X509_NAME_free);
return 0;
}
if (sk_X509_NAME_insert(sk, xn, i) == 0) {
X509_NAME_free(xn);
sk_X509_NAME_pop_free(sk, X509_NAME_free);
return 0;
}
}
*dst = sk;

return 1;
}

SSL *SSL_dup(SSL *s)
{
SSL *ret;
int i;

Expand Down Expand Up @@ -3763,18 +3796,10 @@ SSL *SSL_dup(SSL *s)
goto err;

/* Dup the client_CA list */
if (s->ca_names != NULL) {
if ((sk = sk_X509_NAME_dup(s->ca_names)) == NULL)
goto err;
ret->ca_names = sk;
for (i = 0; i < sk_X509_NAME_num(sk); i++) {
xn = sk_X509_NAME_value(sk, i);
if (sk_X509_NAME_set(sk, i, X509_NAME_dup(xn)) == NULL) {
X509_NAME_free(xn);
goto err;
}
}
}
if (!dup_ca_names(&ret->ca_names, s->ca_names)
|| !dup_ca_names(&ret->client_ca_names, s->client_ca_names))
goto err;

return ret;

err:
Expand Down
12 changes: 10 additions & 2 deletions ssl/ssl_locl.h
Original file line number Diff line number Diff line change
Expand Up @@ -854,9 +854,11 @@ struct ssl_ctx_st {
/*
* What we put in certificate_authorities extension for TLS 1.3
* (ClientHello and CertificateRequest) or just client cert requests for
* earlier versions.
* earlier versions. If client_ca_names is populated then it is only used
* for client cert requests, and in preference to ca_names.
*/
STACK_OF(X509_NAME) *ca_names;
STACK_OF(X509_NAME) *client_ca_names;

/*
* Default values to use in SSL structures follow (these are copied by
Expand Down Expand Up @@ -1233,8 +1235,14 @@ struct ssl_st {
long verify_result;
/* extra application data */
CRYPTO_EX_DATA ex_data;
/* for server side, keep the list of CA_dn we can use */
/*
* What we put in certificate_authorities extension for TLS 1.3
* (ClientHello and CertificateRequest) or just client cert requests for
* earlier versions. If client_ca_names is populated then it is only used
* for client cert requests, and in preference to ca_names.
*/
STACK_OF(X509_NAME) *ca_names;
STACK_OF(X509_NAME) *client_ca_names;
CRYPTO_REF_COUNT references;
/* protocol behaviour */
uint32_t options;
Expand Down
4 changes: 2 additions & 2 deletions ssl/statem/extensions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,7 @@ static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
X509 *x,
size_t chainidx)
{
const STACK_OF(X509_NAME) *ca_sk = SSL_get0_CA_list(s);
const STACK_OF(X509_NAME) *ca_sk = get_ca_names(s);

if (ca_sk == NULL || sk_X509_NAME_num(ca_sk) == 0)
return EXT_RETURN_NOT_SENT;
Expand All @@ -1211,7 +1211,7 @@ static EXT_RETURN tls_construct_certificate_authorities(SSL *s, WPACKET *pkt,
return EXT_RETURN_FAIL;
}

if (!construct_ca_names(s, pkt)) {
if (!construct_ca_names(s, ca_sk, pkt)) {
/* SSLfatal() already called */
return EXT_RETURN_FAIL;
}
Expand Down
18 changes: 16 additions & 2 deletions ssl/statem/statem_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2287,10 +2287,24 @@ int parse_ca_names(SSL *s, PACKET *pkt)
return 0;
}

int construct_ca_names(SSL *s, WPACKET *pkt)
const STACK_OF(X509_NAME) *get_ca_names(SSL *s)
{
const STACK_OF(X509_NAME) *ca_sk = SSL_get0_CA_list(s);
const STACK_OF(X509_NAME) *ca_sk = NULL;;

if (s->server) {
ca_sk = SSL_get_client_CA_list(s);
if (ca_sk != NULL && sk_X509_NAME_num(ca_sk) == 0)
ca_sk = NULL;
}

if (ca_sk == NULL)
ca_sk = SSL_get0_CA_list(s);

return ca_sk;
}

int construct_ca_names(SSL *s, const STACK_OF(X509_NAME) *ca_sk, WPACKET *pkt)
{
/* Start sub-packet for client CA list */
if (!WPACKET_start_sub_packet_u16(pkt)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_CONSTRUCT_CA_NAMES,
Expand Down
3 changes: 2 additions & 1 deletion ssl/statem/statem_locl.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ int create_synthetic_message_hash(SSL *s, const unsigned char *hashval,
size_t hashlen, const unsigned char *hrr,
size_t hrrlen);
int parse_ca_names(SSL *s, PACKET *pkt);
int construct_ca_names(SSL *s, WPACKET *pkt);
const STACK_OF(X509_NAME) *get_ca_names(SSL *s);
int construct_ca_names(SSL *s, const STACK_OF(X509_NAME) *ca_sk, WPACKET *pkt);
size_t construct_key_exchange_tbs(SSL *s, unsigned char **ptbs,
const void *param, size_t paramlen);

Expand Down
2 changes: 1 addition & 1 deletion ssl/statem/statem_srvr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2880,7 +2880,7 @@ int tls_construct_certificate_request(SSL *s, WPACKET *pkt)
}
}

if (!construct_ca_names(s, pkt)) {
if (!construct_ca_names(s, get_ca_names(s), pkt)) {
/* SSLfatal() already called */
return 0;
}
Expand Down

0 comments on commit 9873297

Please sign in to comment.