Skip to content

Commit 42d2b81

Browse files
authored
Merge pull request #9209 from mattia-moffa/20250910-certauth-clienthello
Add support for certificate_authorities extension in ClientHello
2 parents f869daa + 26c9908 commit 42d2b81

File tree

11 files changed

+746
-83
lines changed

11 files changed

+746
-83
lines changed

doc/dox_comments/header_files/ssl.h

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15257,6 +15257,239 @@ RFC 9146 and RFC 9147.
1525715257
const unsigned char* wolfSSL_dtls_cid_parse(const unsigned char* msg,
1525815258
unsigned int msgSz, unsigned int cidSz);
1525915259

15260+
/*!
15261+
\ingroup TLS
15262+
\brief On the server, this sets a list of CA names to be sent to clients in
15263+
certificate requests as a hint for which CA's are supported by the server.
15264+
15265+
On the client, this function has no effect.
15266+
15267+
\param [in] ctx Pointer to the wolfSSL context
15268+
\param [in] names List of names to be set
15269+
15270+
\sa wolfSSL_set_client_CA_list
15271+
\sa wolfSSL_CTX_get_client_CA_list
15272+
\sa wolfSSL_get_client_CA_list
15273+
\sa wolfSSL_CTX_set0_CA_list
15274+
\sa wolfSSL_set0_CA_list
15275+
\sa wolfSSL_CTX_get0_CA_list
15276+
\sa wolfSSL_get0_CA_list
15277+
\sa wolfSSL_get0_peer_CA_list
15278+
*/
15279+
void wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX* ctx,
15280+
WOLF_STACK_OF(WOLFSSL_X509_NAME)* names);
15281+
15282+
/*!
15283+
\ingroup TLS
15284+
\brief This retrieves the list previously set via
15285+
wolfSSL_CTX_set_client_CA_list, or NULL if no list has been set.
15286+
15287+
\param [in] ctx Pointer to the wolfSSL context
15288+
\return A stack of WOLFSSL_X509_NAMEs containing the CA names
15289+
15290+
\sa wolfSSL_set_client_CA_list
15291+
\sa wolfSSL_CTX_set_client_CA_list
15292+
\sa wolfSSL_get_client_CA_list
15293+
\sa wolfSSL_CTX_set0_CA_list
15294+
\sa wolfSSL_set0_CA_list
15295+
\sa wolfSSL_CTX_get0_CA_list
15296+
\sa wolfSSL_get0_CA_list
15297+
\sa wolfSSL_get0_peer_CA_list
15298+
*/
15299+
WOLFSSL_STACK *wolfSSL_CTX_get_client_CA_list(
15300+
const WOLFSSL_CTX *ctx);
15301+
15302+
/*!
15303+
\ingroup TLS
15304+
\brief Same as wolfSSL_CTX_set_client_CA_list, but specific to a session.
15305+
If a CA list is set on both the context and the session, the list on the
15306+
session is used.
15307+
15308+
\param [in] ssl Pointer to the WOLFSSL object
15309+
\param [in] names List of names to be set.
15310+
15311+
\sa wolfSSL_CTX_set_client_CA_list
15312+
\sa wolfSSL_CTX_get_client_CA_list
15313+
\sa wolfSSL_get_client_CA_list
15314+
\sa wolfSSL_CTX_set0_CA_list
15315+
\sa wolfSSL_set0_CA_list
15316+
\sa wolfSSL_CTX_get0_CA_list
15317+
\sa wolfSSL_get0_CA_list
15318+
\sa wolfSSL_get0_peer_CA_list
15319+
*/
15320+
void wolfSSL_set_client_CA_list(WOLFSSL* ssl,
15321+
WOLF_STACK_OF(WOLFSSL_X509_NAME)* names);
15322+
15323+
/*!
15324+
\ingroup TLS
15325+
\brief On the server, this retrieves the list previously set via
15326+
wolfSSL_set_client_CA_list. If none was set, returns the list previously
15327+
set via wolfSSL_CTX_set_client_CA_list. If no list at all was set, returns
15328+
NULL.
15329+
15330+
On the client, this retrieves the list that was received from the server,
15331+
or NULL if none was received. wolfSSL_CTX_set_cert_cb can be used to
15332+
register a callback to dynamically load certificates when a certificate
15333+
request is received from the server.
15334+
15335+
\param [in] ssl Pointer to the WOLFSSL object
15336+
\return A stack of WOLFSSL_X509_NAMEs containing the CA names
15337+
15338+
\sa wolfSSL_CTX_set_cert_cb
15339+
\sa wolfSSL_CTX_set_client_CA_list
15340+
\sa wolfSSL_CTX_get_client_CA_list
15341+
\sa wolfSSL_get_client_CA_list
15342+
\sa wolfSSL_CTX_set0_CA_list
15343+
\sa wolfSSL_set0_CA_list
15344+
\sa wolfSSL_CTX_get0_CA_list
15345+
\sa wolfSSL_get0_CA_list
15346+
\sa wolfSSL_get0_peer_CA_list
15347+
*/
15348+
WOLFSSL_STACK* wolfSSL_get_client_CA_list(
15349+
const WOLFSSL* ssl);
15350+
15351+
/*!
15352+
\ingroup TLS
15353+
\brief This function sets a list of CA names to be sent to the peer as a
15354+
hint for which CA's are supported for its authentication.
15355+
15356+
In TLS >= 1.3, this is supported in both directions between the client and
15357+
the server. On the server, the CA names will be sent as part of a
15358+
CertificateRequest, making this function an equivalent of *_set_client_CA_list;
15359+
on the client, these are sent as part of ClientHello.
15360+
15361+
In TLS < 1.3, sending CA names from the client to the server is not
15362+
supported, therefore this function is equivalent to
15363+
wolfSSL_CTX_set_client_CA_list.
15364+
15365+
Note that the lists set via *_set_client_CA_list and *_set0_CA_list are
15366+
separate internally, i.e. calling *_get_client_CA_list will not retrieve a
15367+
list set via *_set0_CA_list and vice versa. If both are set, the server will
15368+
ignore *_set0_CA_list when sending CA names to the client.
15369+
15370+
\param [in] ctx Pointer to the wolfSSL context
15371+
\param [in] names List of names to be set
15372+
15373+
\sa wolfSSL_CTX_set_client_CA_list
15374+
\sa wolfSSL_set_client_CA_list
15375+
\sa wolfSSL_CTX_get_client_CA_list
15376+
\sa wolfSSL_get_client_CA_list
15377+
\sa wolfSSL_set0_CA_list
15378+
\sa wolfSSL_CTX_get0_CA_list
15379+
\sa wolfSSL_get0_CA_list
15380+
\sa wolfSSL_get0_peer_CA_list
15381+
*/
15382+
void wolfSSL_CTX_set0_CA_list(WOLFSSL_CTX *ctx,
15383+
WOLF_STACK_OF(WOLFSSL_X509_NAME)* names);
15384+
15385+
/*!
15386+
\ingroup TLS
15387+
\brief This retrieves the list previously set via
15388+
wolfSSL_CTX_set0_CA_list, or NULL if no list has been set.
15389+
15390+
\param [in] ctx Pointer to the wolfSSL context
15391+
\return A stack of WOLFSSL_X509_NAMEs containing the CA names
15392+
15393+
\sa wolfSSL_CTX_set_client_CA_list
15394+
\sa wolfSSL_set_client_CA_list
15395+
\sa wolfSSL_CTX_get_client_CA_list
15396+
\sa wolfSSL_get_client_CA_list
15397+
\sa wolfSSL_CTX_set0_CA_list
15398+
\sa wolfSSL_set0_CA_list
15399+
\sa wolfSSL_get0_CA_list
15400+
\sa wolfSSL_get0_peer_CA_list
15401+
*/
15402+
WOLFSSL_STACK *wolfSSL_CTX_get0_CA_list(
15403+
const WOLFSSL_CTX *ctx);
15404+
15405+
/*!
15406+
\ingroup TLS
15407+
\brief Same as wolfSSL_CTX_set0_CA_list, but specific to a session.
15408+
If a CA list is set on both the context and the session, the list on the
15409+
session is used.
15410+
15411+
\param [in] ssl Pointer to the WOLFSSL object
15412+
\param [in] names List of names to be set.
15413+
15414+
\sa wolfSSL_CTX_set_client_CA_list
15415+
\sa wolfSSL_set_client_CA_list
15416+
\sa wolfSSL_CTX_get_client_CA_list
15417+
\sa wolfSSL_get_client_CA_list
15418+
\sa wolfSSL_CTX_set0_CA_list
15419+
\sa wolfSSL_CTX_get0_CA_list
15420+
\sa wolfSSL_get0_CA_list
15421+
\sa wolfSSL_get0_peer_CA_list
15422+
*/
15423+
void wolfSSL_set0_CA_list(WOLFSSL *ssl,
15424+
WOLF_STACK_OF(WOLFSSL_X509_NAME) *names);
15425+
15426+
/*!
15427+
\ingroup TLS
15428+
\brief This retrieves the list previously set via wolfSSL_set0_CA_list. If
15429+
none was set, returns the list previously set via
15430+
wolfSSL_CTX_set0_CA_list. If no list at all was set, returns NULL.
15431+
15432+
\param [in] ssl Pointer to the WOLFSSL object
15433+
\return A stack of WOLFSSL_X509_NAMEs containing the CA names
15434+
15435+
\sa wolfSSL_CTX_set_client_CA_list
15436+
\sa wolfSSL_set_client_CA_list
15437+
\sa wolfSSL_CTX_get_client_CA_list
15438+
\sa wolfSSL_get_client_CA_list
15439+
\sa wolfSSL_CTX_set0_CA_list
15440+
\sa wolfSSL_set0_CA_list
15441+
\sa wolfSSL_CTX_get0_CA_list
15442+
\sa wolfSSL_get0_peer_CA_list
15443+
*/
15444+
WOLFSSL_STACK *wolfSSL_get0_CA_list(
15445+
const WOLFSSL *ssl);
15446+
15447+
/*!
15448+
\ingroup TLS
15449+
\brief This returns the CA list received from the peer.
15450+
15451+
On the client, this is the list sent by the server in a CertificateRequest,
15452+
and this function is equivalent to wolfSSL_get_client_CA_list.
15453+
15454+
On the server, this is the list sent by the client in the ClientHello message
15455+
in TLS >= 1.3; in TLS < 1.3, the function always returns NULL on the server
15456+
side.
15457+
15458+
wolfSSL_CTX_set_cert_cb can be used to register a callback to dynamically
15459+
load certificates when a CA list is received from the peer.
15460+
15461+
\param [in] ssl Pointer to the WOLFSSL object
15462+
\return A stack of WOLFSSL_X509_NAMEs containing the CA names
15463+
15464+
\sa wolfSSL_CTX_set_cert_cb
15465+
\sa wolfSSL_CTX_set_client_CA_list
15466+
\sa wolfSSL_set_client_CA_list
15467+
\sa wolfSSL_CTX_get_client_CA_list
15468+
\sa wolfSSL_get_client_CA_list
15469+
\sa wolfSSL_CTX_set0_CA_list
15470+
\sa wolfSSL_set0_CA_list
15471+
\sa wolfSSL_CTX_get0_CA_list
15472+
\sa wolfSSL_get0_CA_list
15473+
*/
15474+
WOLFSSL_STACK *wolfSSL_get0_peer_CA_list(const WOLFSSL *ssl);
15475+
15476+
/*!
15477+
\ingroup TLS
15478+
\brief This function sets a callback that will be called whenever a
15479+
certificate is about to be used, to allow the application to inspect, set
15480+
or clear any certificates, for example to react to a CA list sent from the
15481+
peer.
15482+
15483+
\param [in] ctx Pointer to the wolfSSL context
15484+
\param [in] cb Function pointer to the callback
15485+
\param [in] arg Pointer that will be passed to the callback
15486+
15487+
\sa wolfSSL_get0_peer_CA_list
15488+
\sa wolfSSL_get_client_CA_list
15489+
*/
15490+
void wolfSSL_CTX_set_cert_cb(WOLFSSL_CTX* ctx,
15491+
int (*cb)(WOLFSSL *, void *), void *arg);
15492+
1526015493
/*!
1526115494
\ingroup TLS
1526215495

src/internal.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2877,6 +2877,8 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
28772877
#ifndef WOLFSSL_NO_CA_NAMES
28782878
wolfSSL_sk_X509_NAME_pop_free(ctx->client_ca_names, NULL);
28792879
ctx->client_ca_names = NULL;
2880+
wolfSSL_sk_X509_NAME_pop_free(ctx->ca_names, NULL);
2881+
ctx->ca_names = NULL;
28802882
#endif
28812883
#ifdef OPENSSL_EXTRA
28822884
if (ctx->x509Chain) {
@@ -6671,9 +6673,11 @@ int InitSSL_Suites(WOLFSSL* ssl)
66716673
byte haveAnon = 0;
66726674
byte haveRSA = 0;
66736675
byte haveMcast = 0;
6676+
byte haveCertSetupCb = 0;
66746677

66756678
(void)haveAnon; /* Squash unused var warnings */
66766679
(void)haveMcast;
6680+
(void)haveCertSetupCb;
66776681

66786682
if (!ssl)
66796683
return BAD_FUNC_ARG;
@@ -6692,6 +6696,10 @@ int InitSSL_Suites(WOLFSSL* ssl)
66926696
haveMcast = (byte)ssl->options.haveMcast;
66936697
#endif /* WOLFSSL_MULTICAST */
66946698
#endif /* !NO_CERTS && !WOLFSSL_SESSION_EXPORT */
6699+
#if defined(WOLFSSL_TLS13) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA)
6700+
if (ssl->ctx->certSetupCb != NULL)
6701+
haveCertSetupCb = 1;
6702+
#endif /* WOLFSSL_TLS13 && !NO_CERTS && OPENSSL_EXTRA */
66956703

66966704
#ifdef WOLFSSL_EARLY_DATA
66976705
if (ssl->options.side == WOLFSSL_SERVER_END)
@@ -6719,10 +6727,11 @@ int InitSSL_Suites(WOLFSSL* ssl)
67196727
}
67206728

67216729
#if !defined(NO_CERTS) && !defined(WOLFSSL_SESSION_EXPORT)
6722-
/* make sure server has cert and key unless using PSK, Anon, or
6723-
* Multicast. This should be true even if just switching ssl ctx */
6730+
/* make sure server has cert and key unless using PSK, Anon,
6731+
* Multicast or cert setup callback. This should be true even if just
6732+
* switching ssl ctx */
67246733
if (ssl->options.side == WOLFSSL_SERVER_END &&
6725-
!havePSK && !haveAnon && !haveMcast) {
6734+
!havePSK && !haveAnon && !haveMcast && !haveCertSetupCb) {
67266735

67276736
/* server certificate must be loaded */
67286737
if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer) {
@@ -8794,6 +8803,10 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
87948803
#ifndef WOLFSSL_NO_CA_NAMES
87958804
wolfSSL_sk_X509_NAME_pop_free(ssl->client_ca_names, NULL);
87968805
ssl->client_ca_names = NULL;
8806+
wolfSSL_sk_X509_NAME_pop_free(ssl->ca_names, NULL);
8807+
ssl->ca_names = NULL;
8808+
wolfSSL_sk_X509_NAME_pop_free(ssl->peer_ca_names, NULL);
8809+
ssl->peer_ca_names = NULL;
87978810
#endif
87988811
#ifdef WOLFSSL_DTLS13
87998812
Dtls13FreeFsmResources(ssl);
@@ -24830,7 +24843,7 @@ int SendCertificateRequest(WOLFSSL* ssl)
2483024843

2483124844
#ifndef WOLFSSL_NO_CA_NAMES
2483224845
/* Certificate Authorities */
24833-
names = SSL_CA_NAMES(ssl);
24846+
names = SSL_PRIORITY_CA_NAMES(ssl);
2483424847
while (names != NULL) {
2483524848
byte seq[MAX_SEQ_SZ];
2483624849
WOLFSSL_X509_NAME* name = names->data.name;
@@ -24922,7 +24935,7 @@ int SendCertificateRequest(WOLFSSL* ssl)
2492224935
c16toa((word16)dnLen, &output[i]); /* auth's */
2492324936
i += REQ_HEADER_SZ;
2492424937
#ifndef WOLFSSL_NO_CA_NAMES
24925-
names = SSL_CA_NAMES(ssl);
24938+
names = SSL_PRIORITY_CA_NAMES(ssl);
2492624939
while (names != NULL) {
2492724940
byte seq[MAX_SEQ_SZ];
2492824941
WOLFSSL_X509_NAME* name = names->data.name;
@@ -31752,10 +31765,9 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType,
3175231765
return BUFFER_ERROR;
3175331766

3175431767
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(HAVE_LIGHTY)
31755-
if (ssl->client_ca_names != ssl->ctx->client_ca_names)
31756-
wolfSSL_sk_X509_NAME_pop_free(ssl->client_ca_names, NULL);
31757-
ssl->client_ca_names = wolfSSL_sk_X509_NAME_new(NULL);
31758-
if (ssl->client_ca_names == NULL) {
31768+
wolfSSL_sk_X509_NAME_pop_free(ssl->peer_ca_names, NULL);
31769+
ssl->peer_ca_names = wolfSSL_sk_X509_NAME_new(NULL);
31770+
if (ssl->peer_ca_names == NULL) {
3175931771
return MEMORY_ERROR;
3176031772
}
3176131773
#endif
@@ -31800,7 +31812,7 @@ static int HashSkeData(WOLFSSL* ssl, enum wc_HashType hashType,
3180031812
}
3180131813

3180231814
if (ret == 0) {
31803-
if (wolfSSL_sk_X509_NAME_push(ssl->client_ca_names, name)
31815+
if (wolfSSL_sk_X509_NAME_push(ssl->peer_ca_names, name)
3180431816
<= 0)
3180531817
{
3180631818
ret = MEMORY_ERROR;

0 commit comments

Comments
 (0)