Skip to content

Commit adef0a2

Browse files
committed
Add example for TLS 1.3 certificate_authorities extension in ClientHello
1 parent 2d37f38 commit adef0a2

File tree

3 files changed

+733
-0
lines changed

3 files changed

+733
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ android/wolfssljni-ndk-sample/proguard-project.txt
115115
/tls/server-tls-uart
116116
/tls/server-tls-verifycallback
117117
/tls/server-tls-writedup
118+
/tls/client-tls13-certauth-c2s
119+
/tls/server-tls13-certauth-c2s
118120
/tls/client-ech
119121
/tls/client-ech-local
120122
/tls/server-ech-local

tls/client-tls13-certauth-c2s.c

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
/* client-tls13-certauth-c2s.c
2+
*
3+
* Copyright (C) 2006-2025 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL. (formerly known as CyaSSL)
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20+
*/
21+
22+
/* This example showcases the usage of the TLS 1.3 certificate_authorities
23+
* extension in the ClientHello message, to indicate to the server which
24+
* certificate authorities the client supports, guiding certificate selection.
25+
*/
26+
27+
/* the usual suspects */
28+
#include <stdlib.h>
29+
#include <stdio.h>
30+
#include <string.h>
31+
32+
/* socket includes */
33+
#include <sys/socket.h>
34+
#include <arpa/inet.h>
35+
#include <netinet/in.h>
36+
#include <unistd.h>
37+
38+
/* wolfSSL */
39+
#ifndef WOLFSSL_USER_SETTINGS
40+
#include <wolfssl/options.h>
41+
#endif
42+
#include <wolfssl/ssl.h>
43+
#include <wolfssl/wolfio.h>
44+
#include <wolfssl/wolfcrypt/error-crypt.h>
45+
46+
#define DEFAULT_PORT 11111
47+
48+
#define CERT_FILE "../certs/client-cert.pem"
49+
#define KEY_FILE "../certs/client-key.pem"
50+
#define CA_FILE "../certs/ca-cert.pem"
51+
52+
#if defined(WOLFSSL_TLS13) && defined(HAVE_SECRET_CALLBACK)
53+
54+
#ifndef WOLFSSL_SSLKEYLOGFILE_OUTPUT
55+
#define WOLFSSL_SSLKEYLOGFILE_OUTPUT "sslkeylog.log"
56+
#endif
57+
58+
/* Callback function for TLS v1.3 secrets for use with Wireshark */
59+
static int Tls13SecretCallback(WOLFSSL* ssl, int id, const unsigned char* secret,
60+
int secretSz, void* ctx)
61+
{
62+
int i;
63+
const char* str = NULL;
64+
unsigned char clientRandom[32];
65+
int clientRandomSz;
66+
XFILE fp = stderr;
67+
if (ctx) {
68+
fp = XFOPEN((const char*)ctx, "ab");
69+
if (fp == XBADFILE) {
70+
return BAD_FUNC_ARG;
71+
}
72+
}
73+
74+
clientRandomSz = (int)wolfSSL_get_client_random(ssl, clientRandom,
75+
sizeof(clientRandom));
76+
77+
if (clientRandomSz <= 0) {
78+
printf("Error getting client random %d\n", clientRandomSz);
79+
}
80+
81+
#if 0
82+
printf("TLS Client Secret CB: Rand %d, Secret %d\n",
83+
clientRandomSz, secretSz);
84+
#endif
85+
86+
switch (id) {
87+
case CLIENT_EARLY_TRAFFIC_SECRET:
88+
str = "CLIENT_EARLY_TRAFFIC_SECRET"; break;
89+
case EARLY_EXPORTER_SECRET:
90+
str = "EARLY_EXPORTER_SECRET"; break;
91+
case CLIENT_HANDSHAKE_TRAFFIC_SECRET:
92+
str = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"; break;
93+
case SERVER_HANDSHAKE_TRAFFIC_SECRET:
94+
str = "SERVER_HANDSHAKE_TRAFFIC_SECRET"; break;
95+
case CLIENT_TRAFFIC_SECRET:
96+
str = "CLIENT_TRAFFIC_SECRET_0"; break;
97+
case SERVER_TRAFFIC_SECRET:
98+
str = "SERVER_TRAFFIC_SECRET_0"; break;
99+
case EXPORTER_SECRET:
100+
str = "EXPORTER_SECRET"; break;
101+
}
102+
103+
fprintf(fp, "%s ", str);
104+
for (i = 0; i < clientRandomSz; i++) {
105+
fprintf(fp, "%02x", clientRandom[i]);
106+
}
107+
fprintf(fp, " ");
108+
for (i = 0; i < secretSz; i++) {
109+
fprintf(fp, "%02x", secret[i]);
110+
}
111+
fprintf(fp, "\n");
112+
113+
if (fp != stderr) {
114+
XFCLOSE(fp);
115+
}
116+
117+
return 0;
118+
}
119+
#endif /* WOLFSSL_TLS13 && HAVE_SECRET_CALLBACK */
120+
121+
int main(int argc, char** argv)
122+
{
123+
int ret = 0;
124+
#ifdef WOLFSSL_TLS13
125+
int sockfd = SOCKET_INVALID;
126+
struct sockaddr_in servAddr;
127+
char buff[256];
128+
size_t len;
129+
130+
/* declare wolfSSL objects */
131+
WOLFSSL_CTX* ctx = NULL;
132+
WOLFSSL* ssl = NULL;
133+
134+
/* Declare CA name object */
135+
WOLF_STACK_OF(WOLFSSL_X509_NAME)* caName = NULL;
136+
137+
/* Check for proper calling convention */
138+
if (argc != 2) {
139+
printf("usage: %s <IPv4 address>\n", argv[0]);
140+
return 0;
141+
}
142+
143+
/* Create a socket that uses an internet IPv4 address,
144+
* Sets the socket to be stream based (TCP),
145+
* 0 means choose the default protocol. */
146+
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
147+
fprintf(stderr, "ERROR: failed to create the socket\n");
148+
ret = -1; goto exit;
149+
}
150+
151+
/* Initialize the server address struct with zeros */
152+
memset(&servAddr, 0, sizeof(servAddr));
153+
154+
/* Fill in the server address */
155+
servAddr.sin_family = AF_INET; /* using IPv4 */
156+
servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */
157+
158+
/* Get the server IPv4 address from the command line call */
159+
if (inet_pton(AF_INET, argv[1], &servAddr.sin_addr) != 1) {
160+
fprintf(stderr, "ERROR: invalid address\n");
161+
ret = -1; goto exit;
162+
}
163+
164+
/* Connect to the server */
165+
if ((ret = connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr)))
166+
== -1) {
167+
fprintf(stderr, "ERROR: failed to connect\n");
168+
goto exit;
169+
}
170+
171+
/*---------------------------------*/
172+
/* Start of wolfSSL initialization and configuration */
173+
/*---------------------------------*/
174+
#if 0
175+
wolfSSL_Debugging_ON();
176+
#endif
177+
178+
/* Initialize wolfSSL */
179+
if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) {
180+
fprintf(stderr, "ERROR: Failed to initialize the library\n");
181+
goto exit;
182+
}
183+
184+
/* Create and initialize WOLFSSL_CTX */
185+
if ((ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method())) == NULL) {
186+
fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n");
187+
ret = -1; goto exit;
188+
}
189+
190+
/* Load client certificate into WOLFSSL_CTX */
191+
if ((ret = wolfSSL_CTX_use_certificate_file(ctx, CERT_FILE, WOLFSSL_FILETYPE_PEM))
192+
!= WOLFSSL_SUCCESS) {
193+
fprintf(stderr, "ERROR: failed to load %s, please check the file.\n",
194+
CERT_FILE);
195+
goto exit;
196+
}
197+
198+
/* Load client key into WOLFSSL_CTX */
199+
if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, WOLFSSL_FILETYPE_PEM))
200+
!= WOLFSSL_SUCCESS) {
201+
fprintf(stderr, "ERROR: failed to load %s, please check the file.\n",
202+
KEY_FILE);
203+
goto exit;
204+
}
205+
206+
/* Load CA certificate into WOLFSSL_CTX */
207+
if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CA_FILE, NULL))
208+
!= WOLFSSL_SUCCESS) {
209+
fprintf(stderr, "ERROR: failed to load %s, please check the file.\n",
210+
CA_FILE);
211+
goto exit;
212+
}
213+
214+
/* Load the CA certificate name to send in certificate_authorities extension
215+
*/
216+
if ((caName = wolfSSL_load_client_CA_file(CA_FILE)) == NULL) {
217+
fprintf(stderr, "ERROR: failed to load CA name from %s, please check "
218+
"the file.\n", CA_FILE);
219+
goto exit;
220+
}
221+
222+
/* Set CA name to send in certificate_authorities extension */
223+
wolfSSL_CTX_set0_CA_list(ctx, caName);
224+
225+
/* Create a WOLFSSL object */
226+
if ((ssl = wolfSSL_new(ctx)) == NULL) {
227+
fprintf(stderr, "ERROR: failed to create WOLFSSL object\n");
228+
ret = -1; goto exit;
229+
}
230+
231+
/* Attach wolfSSL to the socket */
232+
if ((ret = wolfSSL_set_fd(ssl, sockfd)) != WOLFSSL_SUCCESS) {
233+
fprintf(stderr, "ERROR: Failed to set the file descriptor\n");
234+
goto exit;
235+
}
236+
237+
#ifdef HAVE_SECRET_CALLBACK
238+
/* required for getting random used */
239+
wolfSSL_KeepArrays(ssl);
240+
241+
/* optional logging for wireshark */
242+
wolfSSL_set_tls13_secret_cb(ssl, Tls13SecretCallback,
243+
(void*)WOLFSSL_SSLKEYLOGFILE_OUTPUT);
244+
#endif
245+
246+
/* Connect to wolfSSL on the server side */
247+
if ((ret = wolfSSL_connect(ssl)) != WOLFSSL_SUCCESS) {
248+
fprintf(stderr, "ERROR: failed to connect to wolfSSL\n");
249+
goto exit;
250+
}
251+
252+
#ifdef HAVE_SECRET_CALLBACK
253+
wolfSSL_FreeArrays(ssl);
254+
#endif
255+
256+
/* Get a message for the server from stdin */
257+
printf("Message for server: ");
258+
memset(buff, 0, sizeof(buff));
259+
if (fgets(buff, sizeof(buff), stdin) == NULL) {
260+
fprintf(stderr, "ERROR: failed to get message for server\n");
261+
ret = -1; goto exit;
262+
}
263+
len = strnlen(buff, sizeof(buff));
264+
265+
/* Send the message to the server */
266+
if ((ret = wolfSSL_write(ssl, buff, len)) != len) {
267+
fprintf(stderr, "ERROR: failed to write entire message\n");
268+
fprintf(stderr, "%d bytes of %d bytes were sent", ret, (int) len);
269+
goto exit;
270+
}
271+
272+
/* Read the server data into our buff array */
273+
memset(buff, 0, sizeof(buff));
274+
if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) < 0) {
275+
fprintf(stderr, "ERROR: failed to read\n");
276+
goto exit;
277+
}
278+
279+
/* Print to stdout any data the server sends */
280+
printf("Server: %s\n", buff);
281+
282+
/* Return reporting a success */
283+
ret = 0;
284+
285+
exit:
286+
/* Cleanup and return */
287+
if (sockfd != SOCKET_INVALID)
288+
close(sockfd); /* Close the connection to the server */
289+
if (ssl)
290+
wolfSSL_free(ssl); /* Free the wolfSSL object */
291+
if (ctx)
292+
wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */
293+
wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */
294+
#else
295+
printf("Example requires TLS v1.3\n");
296+
#endif
297+
(void)argc;
298+
(void)argv;
299+
300+
return ret;
301+
}

0 commit comments

Comments
 (0)