1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25 /*
26 * Source file for all wolfSSL specific code for the TLS/SSL layer. No code
27 * but vtls.c should ever call or use these functions.
28 *
29 */
30
31 #include "curl_setup.h"
32
33 #ifdef USE_WOLFSSL
34
35 #define WOLFSSL_OPTIONS_IGNORE_SYS
36 #include <wolfssl/version.h>
37 #include <wolfssl/options.h>
38
39 /* To determine what functions are available we rely on one or both of:
40 - the user's options.h generated by wolfSSL
41 - the symbols detected by curl's configure
42 Since they are markedly different from one another, and one or the other may
43 not be available, we do some checking below to bring things in sync. */
44
45 /* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
46 #ifndef HAVE_ALPN
47 #ifdef HAVE_WOLFSSL_USEALPN
48 #define HAVE_ALPN
49 #endif
50 #endif
51
52 #include <limits.h>
53
54 #include "urldata.h"
55 #include "sendf.h"
56 #include "inet_pton.h"
57 #include "vtls.h"
58 #include "vtls_int.h"
59 #include "keylog.h"
60 #include "parsedate.h"
61 #include "connect.h" /* for the connect timeout */
62 #include "select.h"
63 #include "strcase.h"
64 #include "x509asn1.h"
65 #include "curl_printf.h"
66 #include "multiif.h"
67
68 #include <wolfssl/openssl/ssl.h>
69 #include <wolfssl/ssl.h>
70 #include <wolfssl/error-ssl.h>
71 #include "wolfssl.h"
72
73 /* The last #include files should be: */
74 #include "curl_memory.h"
75 #include "memdebug.h"
76
77 #ifdef USE_ECH
78 # include "curl_base64.h"
79 # define ECH_ENABLED(__data__) \
80 (__data__->set.tls_ech && \
81 !(__data__->set.tls_ech & CURLECH_DISABLE)\
82 )
83 #endif /* USE_ECH */
84
85 /* KEEP_PEER_CERT is a product of the presence of build time symbol
86 OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
87 in wolfSSL's settings.h, and the latter two are build time symbols in
88 options.h. */
89 #ifndef KEEP_PEER_CERT
90 #if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
91 (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
92 #define KEEP_PEER_CERT
93 #endif
94 #endif
95
96 #if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO
97 #define USE_BIO_CHAIN
98 #else
99 #undef USE_BIO_CHAIN
100 #endif
101
102 struct wolfssl_ssl_backend_data {
103 WOLFSSL_CTX *ctx;
104 WOLFSSL *handle;
105 CURLcode io_result; /* result of last BIO cfilter operation */
106 };
107
108 #ifdef OPENSSL_EXTRA
109 /*
110 * Availability note:
111 * The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in
112 * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
113 * option is not set, then TLS 1.3 will not be logged.
114 * For TLS 1.2 and before, we use wolfSSL_get_keys().
115 * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
116 * (--enable-opensslextra or --enable-all).
117 */
118 #if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
119 static int
wolfssl_tls13_secret_callback(SSL * ssl,int id,const unsigned char * secret,int secretSz,void * ctx)120 wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
121 int secretSz, void *ctx)
122 {
123 const char *label;
124 unsigned char client_random[SSL3_RANDOM_SIZE];
125 (void)ctx;
126
127 if(!ssl || !Curl_tls_keylog_enabled()) {
128 return 0;
129 }
130
131 switch(id) {
132 case CLIENT_EARLY_TRAFFIC_SECRET:
133 label = "CLIENT_EARLY_TRAFFIC_SECRET";
134 break;
135 case CLIENT_HANDSHAKE_TRAFFIC_SECRET:
136 label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET";
137 break;
138 case SERVER_HANDSHAKE_TRAFFIC_SECRET:
139 label = "SERVER_HANDSHAKE_TRAFFIC_SECRET";
140 break;
141 case CLIENT_TRAFFIC_SECRET:
142 label = "CLIENT_TRAFFIC_SECRET_0";
143 break;
144 case SERVER_TRAFFIC_SECRET:
145 label = "SERVER_TRAFFIC_SECRET_0";
146 break;
147 case EARLY_EXPORTER_SECRET:
148 label = "EARLY_EXPORTER_SECRET";
149 break;
150 case EXPORTER_SECRET:
151 label = "EXPORTER_SECRET";
152 break;
153 default:
154 return 0;
155 }
156
157 if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) {
158 /* Should never happen as wolfSSL_KeepArrays() was called before. */
159 return 0;
160 }
161
162 Curl_tls_keylog_write(label, client_random, secret, secretSz);
163 return 0;
164 }
165 #endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */
166
167 static void
wolfssl_log_tls12_secret(SSL * ssl)168 wolfssl_log_tls12_secret(SSL *ssl)
169 {
170 unsigned char *ms, *sr, *cr;
171 unsigned int msLen, srLen, crLen, i, x = 0;
172
173 #if LIBWOLFSSL_VERSION_HEX >= 0x0300d000 /* >= 3.13.0 */
174 /* wolfSSL_GetVersion is available since 3.13, we use it instead of
175 * SSL_version since the latter relies on OPENSSL_ALL (--enable-opensslall or
176 * --enable-all). Failing to perform this check could result in an unusable
177 * key log line when TLS 1.3 is actually negotiated. */
178 switch(wolfSSL_GetVersion(ssl)) {
179 case WOLFSSL_SSLV3:
180 case WOLFSSL_TLSV1:
181 case WOLFSSL_TLSV1_1:
182 case WOLFSSL_TLSV1_2:
183 break;
184 default:
185 /* TLS 1.3 does not use this mechanism, the "master secret" returned below
186 * is not directly usable. */
187 return;
188 }
189 #endif
190
191 if(wolfSSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) !=
192 SSL_SUCCESS) {
193 return;
194 }
195
196 /* Check for a missing master secret and skip logging. That can happen if
197 * curl rejects the server certificate and aborts the handshake.
198 */
199 for(i = 0; i < msLen; i++) {
200 x |= ms[i];
201 }
202 if(x == 0) {
203 return;
204 }
205
206 Curl_tls_keylog_write("CLIENT_RANDOM", cr, ms, msLen);
207 }
208 #endif /* OPENSSL_EXTRA */
209
do_file_type(const char * type)210 static int do_file_type(const char *type)
211 {
212 if(!type || !type[0])
213 return SSL_FILETYPE_PEM;
214 if(strcasecompare(type, "PEM"))
215 return SSL_FILETYPE_PEM;
216 if(strcasecompare(type, "DER"))
217 return SSL_FILETYPE_ASN1;
218 return -1;
219 }
220
221 #ifdef HAVE_LIBOQS
222 struct group_name_map {
223 const word16 group;
224 const char *name;
225 };
226
227 static const struct group_name_map gnm[] = {
228 { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" },
229 { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" },
230 { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" },
231 { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" },
232 { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" },
233 { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" },
234 { 0, NULL }
235 };
236 #endif
237
238 #ifdef USE_BIO_CHAIN
239
wolfssl_bio_cf_create(WOLFSSL_BIO * bio)240 static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
241 {
242 wolfSSL_BIO_set_shutdown(bio, 1);
243 wolfSSL_BIO_set_data(bio, NULL);
244 return 1;
245 }
246
wolfssl_bio_cf_destroy(WOLFSSL_BIO * bio)247 static int wolfssl_bio_cf_destroy(WOLFSSL_BIO *bio)
248 {
249 if(!bio)
250 return 0;
251 return 1;
252 }
253
wolfssl_bio_cf_ctrl(WOLFSSL_BIO * bio,int cmd,long num,void * ptr)254 static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
255 {
256 struct Curl_cfilter *cf = BIO_get_data(bio);
257 long ret = 1;
258
259 (void)cf;
260 (void)ptr;
261 switch(cmd) {
262 case BIO_CTRL_GET_CLOSE:
263 ret = (long)wolfSSL_BIO_get_shutdown(bio);
264 break;
265 case BIO_CTRL_SET_CLOSE:
266 wolfSSL_BIO_set_shutdown(bio, (int)num);
267 break;
268 case BIO_CTRL_FLUSH:
269 /* we do no delayed writes, but if we ever would, this
270 * needs to trigger it. */
271 ret = 1;
272 break;
273 case BIO_CTRL_DUP:
274 ret = 1;
275 break;
276 #ifdef BIO_CTRL_EOF
277 case BIO_CTRL_EOF:
278 /* EOF has been reached on input? */
279 return (!cf->next || !cf->next->connected);
280 #endif
281 default:
282 ret = 0;
283 break;
284 }
285 return ret;
286 }
287
wolfssl_bio_cf_out_write(WOLFSSL_BIO * bio,const char * buf,int blen)288 static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
289 const char *buf, int blen)
290 {
291 struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
292 struct ssl_connect_data *connssl = cf->ctx;
293 struct wolfssl_ssl_backend_data *backend =
294 (struct wolfssl_ssl_backend_data *)connssl->backend;
295 struct Curl_easy *data = CF_DATA_CURRENT(cf);
296 ssize_t nwritten;
297 CURLcode result = CURLE_OK;
298
299 DEBUGASSERT(data);
300 nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
301 backend->io_result = result;
302 CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
303 blen, nwritten, result);
304 wolfSSL_BIO_clear_retry_flags(bio);
305 if(nwritten < 0 && CURLE_AGAIN == result)
306 BIO_set_retry_write(bio);
307 return (int)nwritten;
308 }
309
wolfssl_bio_cf_in_read(WOLFSSL_BIO * bio,char * buf,int blen)310 static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
311 {
312 struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
313 struct ssl_connect_data *connssl = cf->ctx;
314 struct wolfssl_ssl_backend_data *backend =
315 (struct wolfssl_ssl_backend_data *)connssl->backend;
316 struct Curl_easy *data = CF_DATA_CURRENT(cf);
317 ssize_t nread;
318 CURLcode result = CURLE_OK;
319
320 DEBUGASSERT(data);
321 /* OpenSSL catches this case, so should we. */
322 if(!buf)
323 return 0;
324
325 nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
326 backend->io_result = result;
327 CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result);
328 wolfSSL_BIO_clear_retry_flags(bio);
329 if(nread < 0 && CURLE_AGAIN == result)
330 BIO_set_retry_read(bio);
331 else if(nread == 0)
332 connssl->peer_closed = TRUE;
333 return (int)nread;
334 }
335
336 static WOLFSSL_BIO_METHOD *wolfssl_bio_cf_method = NULL;
337
wolfssl_bio_cf_init_methods(void)338 static void wolfssl_bio_cf_init_methods(void)
339 {
340 wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO");
341 wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write);
342 wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read);
343 wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl);
344 wolfSSL_BIO_meth_set_create(wolfssl_bio_cf_method, &wolfssl_bio_cf_create);
345 wolfSSL_BIO_meth_set_destroy(wolfssl_bio_cf_method, &wolfssl_bio_cf_destroy);
346 }
347
wolfssl_bio_cf_free_methods(void)348 static void wolfssl_bio_cf_free_methods(void)
349 {
350 wolfSSL_BIO_meth_free(wolfssl_bio_cf_method);
351 }
352
353 #else /* USE_BIO_CHAIN */
354
355 #define wolfssl_bio_cf_init_methods() Curl_nop_stmt
356 #define wolfssl_bio_cf_free_methods() Curl_nop_stmt
357
358 #endif /* !USE_BIO_CHAIN */
359
360 /*
361 * This function loads all the client/CA certificates and CRLs. Setup the TLS
362 * layer and do all necessary magic.
363 */
364 static CURLcode
wolfssl_connect_step1(struct Curl_cfilter * cf,struct Curl_easy * data)365 wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
366 {
367 char *ciphers, *curves;
368 struct ssl_connect_data *connssl = cf->ctx;
369 struct wolfssl_ssl_backend_data *backend =
370 (struct wolfssl_ssl_backend_data *)connssl->backend;
371 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
372 const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
373 const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
374 const char * const ssl_cafile =
375 /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
376 (ca_info_blob ? NULL : conn_config->CAfile);
377 const char * const ssl_capath = conn_config->CApath;
378 WOLFSSL_METHOD* req_method = NULL;
379 #ifdef HAVE_LIBOQS
380 word16 oqsAlg = 0;
381 size_t idx = 0;
382 #endif
383 #ifdef HAVE_SNI
384 bool sni = FALSE;
385 #define use_sni(x) sni = (x)
386 #else
387 #define use_sni(x) Curl_nop_stmt
388 #endif
389 bool imported_native_ca = false;
390 bool imported_ca_info_blob = false;
391
392 DEBUGASSERT(backend);
393
394 if(connssl->state == ssl_connection_complete)
395 return CURLE_OK;
396
397 if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
398 failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
399 return CURLE_SSL_CONNECT_ERROR;
400 }
401
402 /* check to see if we've been told to use an explicit SSL/TLS version */
403 switch(conn_config->version) {
404 case CURL_SSLVERSION_DEFAULT:
405 case CURL_SSLVERSION_TLSv1:
406 #if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
407 /* minimum protocol version is set later after the CTX object is created */
408 req_method = SSLv23_client_method();
409 #else
410 infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
411 "TLS 1.0 is used exclusively");
412 req_method = TLSv1_client_method();
413 #endif
414 use_sni(TRUE);
415 break;
416 case CURL_SSLVERSION_TLSv1_0:
417 #if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS)
418 req_method = TLSv1_client_method();
419 use_sni(TRUE);
420 break;
421 #else
422 failf(data, "wolfSSL does not support TLS 1.0");
423 return CURLE_NOT_BUILT_IN;
424 #endif
425 case CURL_SSLVERSION_TLSv1_1:
426 #ifndef NO_OLD_TLS
427 req_method = TLSv1_1_client_method();
428 use_sni(TRUE);
429 #else
430 failf(data, "wolfSSL does not support TLS 1.1");
431 return CURLE_NOT_BUILT_IN;
432 #endif
433 break;
434 case CURL_SSLVERSION_TLSv1_2:
435 #ifndef WOLFSSL_NO_TLS12
436 req_method = TLSv1_2_client_method();
437 use_sni(TRUE);
438 #else
439 failf(data, "wolfSSL does not support TLS 1.2");
440 return CURLE_NOT_BUILT_IN;
441 #endif
442 break;
443 case CURL_SSLVERSION_TLSv1_3:
444 #ifdef WOLFSSL_TLS13
445 req_method = wolfTLSv1_3_client_method();
446 use_sni(TRUE);
447 break;
448 #else
449 failf(data, "wolfSSL: TLS 1.3 is not yet supported");
450 return CURLE_SSL_CONNECT_ERROR;
451 #endif
452 default:
453 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
454 return CURLE_SSL_CONNECT_ERROR;
455 }
456
457 if(!req_method) {
458 failf(data, "SSL: couldn't create a method");
459 return CURLE_OUT_OF_MEMORY;
460 }
461
462 if(backend->ctx)
463 wolfSSL_CTX_free(backend->ctx);
464 backend->ctx = wolfSSL_CTX_new(req_method);
465
466 if(!backend->ctx) {
467 failf(data, "SSL: couldn't create a context");
468 return CURLE_OUT_OF_MEMORY;
469 }
470
471 switch(conn_config->version) {
472 case CURL_SSLVERSION_DEFAULT:
473 case CURL_SSLVERSION_TLSv1:
474 #if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
475 /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is
476 * whatever minimum version of TLS was built in and at least TLS 1.0. For
477 * later library versions that could change (eg TLS 1.0 built in but
478 * defaults to TLS 1.1) so we have this short circuit evaluation to find
479 * the minimum supported TLS version.
480 */
481 if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) &&
482 (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) &&
483 (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1)
484 #ifdef WOLFSSL_TLS13
485 && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1)
486 #endif
487 ) {
488 failf(data, "SSL: couldn't set the minimum protocol version");
489 return CURLE_SSL_CONNECT_ERROR;
490 }
491 #endif
492 FALLTHROUGH();
493 default:
494 break;
495 }
496
497 ciphers = conn_config->cipher_list;
498 if(ciphers) {
499 if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
500 failf(data, "failed setting cipher list: %s", ciphers);
501 return CURLE_SSL_CIPHER;
502 }
503 infof(data, "Cipher selection: %s", ciphers);
504 }
505
506 curves = conn_config->curves;
507 if(curves) {
508
509 #ifdef HAVE_LIBOQS
510 for(idx = 0; gnm[idx].name != NULL; idx++) {
511 if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) {
512 oqsAlg = gnm[idx].group;
513 break;
514 }
515 }
516
517 if(oqsAlg == 0)
518 #endif
519 {
520 if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
521 failf(data, "failed setting curves list: '%s'", curves);
522 return CURLE_SSL_CIPHER;
523 }
524 }
525 }
526
527 #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
528 /* load native CA certificates */
529 if(ssl_config->native_ca_store) {
530 if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) {
531 infof(data, "error importing native CA store, continuing anyway");
532 }
533 else {
534 imported_native_ca = true;
535 infof(data, "successfully imported native CA store");
536 }
537 }
538 #endif /* !NO_FILESYSTEM */
539
540 /* load certificate blob */
541 if(ca_info_blob) {
542 if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data,
543 ca_info_blob->len,
544 SSL_FILETYPE_PEM) != SSL_SUCCESS) {
545 if(imported_native_ca) {
546 infof(data, "error importing CA certificate blob, continuing anyway");
547 }
548 else {
549 failf(data, "error importing CA certificate blob");
550 return CURLE_SSL_CACERT_BADFILE;
551 }
552 }
553 else {
554 imported_ca_info_blob = true;
555 infof(data, "successfully imported CA certificate blob");
556 }
557 }
558
559 #ifndef NO_FILESYSTEM
560 /* load trusted cacert from file if not blob */
561 if(ssl_cafile || ssl_capath) {
562 int rc =
563 wolfSSL_CTX_load_verify_locations_ex(backend->ctx,
564 ssl_cafile,
565 ssl_capath,
566 WOLFSSL_LOAD_FLAG_IGNORE_ERR);
567 if(SSL_SUCCESS != rc) {
568 if(conn_config->verifypeer && !imported_ca_info_blob &&
569 !imported_native_ca) {
570 /* Fail if we insist on successfully verifying the server. */
571 failf(data, "error setting certificate verify locations:"
572 " CAfile: %s CApath: %s",
573 ssl_cafile ? ssl_cafile : "none",
574 ssl_capath ? ssl_capath : "none");
575 return CURLE_SSL_CACERT_BADFILE;
576 }
577 else {
578 /* Just continue with a warning if no strict certificate
579 verification is required. */
580 infof(data, "error setting certificate verify locations,"
581 " continuing anyway:");
582 }
583 }
584 else {
585 /* Everything is fine. */
586 infof(data, "successfully set certificate verify locations:");
587 }
588 infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
589 infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
590 }
591
592 /* Load the client certificate, and private key */
593 if(ssl_config->primary.clientcert && ssl_config->key) {
594 int file_type = do_file_type(ssl_config->cert_type);
595
596 if(file_type == WOLFSSL_FILETYPE_PEM) {
597 if(wolfSSL_CTX_use_certificate_chain_file(backend->ctx,
598 ssl_config->primary.clientcert)
599 != 1) {
600 failf(data, "unable to use client certificate");
601 return CURLE_SSL_CONNECT_ERROR;
602 }
603 }
604 else if(file_type == WOLFSSL_FILETYPE_ASN1) {
605 if(wolfSSL_CTX_use_certificate_file(backend->ctx,
606 ssl_config->primary.clientcert,
607 file_type) != 1) {
608 failf(data, "unable to use client certificate");
609 return CURLE_SSL_CONNECT_ERROR;
610 }
611 }
612 else {
613 failf(data, "unknown cert type");
614 return CURLE_BAD_FUNCTION_ARGUMENT;
615 }
616
617 file_type = do_file_type(ssl_config->key_type);
618 if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key,
619 file_type) != 1) {
620 failf(data, "unable to set private key");
621 return CURLE_SSL_CONNECT_ERROR;
622 }
623 }
624 #endif /* !NO_FILESYSTEM */
625
626 /* SSL always tries to verify the peer, this only says whether it should
627 * fail to connect if the verification fails, or if it should continue
628 * anyway. In the latter case the result of the verification is checked with
629 * SSL_get_verify_result() below. */
630 wolfSSL_CTX_set_verify(backend->ctx,
631 conn_config->verifypeer?SSL_VERIFY_PEER:
632 SSL_VERIFY_NONE, NULL);
633
634 #ifdef HAVE_SNI
635 if(sni && connssl->peer.sni) {
636 size_t sni_len = strlen(connssl->peer.sni);
637 if((sni_len < USHRT_MAX)) {
638 if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME,
639 connssl->peer.sni,
640 (unsigned short)sni_len) != 1) {
641 failf(data, "Failed to set SNI");
642 return CURLE_SSL_CONNECT_ERROR;
643 }
644 }
645 }
646 #endif
647
648 /* give application a chance to interfere with SSL set up. */
649 if(data->set.ssl.fsslctx) {
650 CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx,
651 data->set.ssl.fsslctxp);
652 if(result) {
653 failf(data, "error signaled by ssl ctx callback");
654 return result;
655 }
656 }
657 #ifdef NO_FILESYSTEM
658 else if(conn_config->verifypeer) {
659 failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
660 " with \"no filesystem\". Either disable peer verification"
661 " (insecure) or if you are building an application with libcurl you"
662 " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
663 return CURLE_SSL_CONNECT_ERROR;
664 }
665 #endif
666
667 /* Let's make an SSL structure */
668 if(backend->handle)
669 wolfSSL_free(backend->handle);
670 backend->handle = wolfSSL_new(backend->ctx);
671 if(!backend->handle) {
672 failf(data, "SSL: couldn't create a handle");
673 return CURLE_OUT_OF_MEMORY;
674 }
675
676 #ifdef HAVE_LIBOQS
677 if(oqsAlg) {
678 if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) {
679 failf(data, "unable to use oqs KEM");
680 }
681 }
682 #endif
683
684 #ifdef HAVE_ALPN
685 if(connssl->alpn) {
686 struct alpn_proto_buf proto;
687 CURLcode result;
688
689 result = Curl_alpn_to_proto_str(&proto, connssl->alpn);
690 if(result ||
691 wolfSSL_UseALPN(backend->handle, (char *)proto.data, proto.len,
692 WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
693 failf(data, "SSL: failed setting ALPN protocols");
694 return CURLE_SSL_CONNECT_ERROR;
695 }
696 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
697 }
698 #endif /* HAVE_ALPN */
699
700 #ifdef OPENSSL_EXTRA
701 if(Curl_tls_keylog_enabled()) {
702 /* Ensure the Client Random is preserved. */
703 wolfSSL_KeepArrays(backend->handle);
704 #if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
705 wolfSSL_set_tls13_secret_cb(backend->handle,
706 wolfssl_tls13_secret_callback, NULL);
707 #endif
708 }
709 #endif /* OPENSSL_EXTRA */
710
711 #ifdef HAVE_SECURE_RENEGOTIATION
712 if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) {
713 failf(data, "SSL: failed setting secure renegotiation");
714 return CURLE_SSL_CONNECT_ERROR;
715 }
716 #endif /* HAVE_SECURE_RENEGOTIATION */
717
718 /* Check if there's a cached ID we can/should use here! */
719 if(ssl_config->primary.sessionid) {
720 void *ssl_sessionid = NULL;
721
722 Curl_ssl_sessionid_lock(data);
723 if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
724 &ssl_sessionid, NULL)) {
725 /* we got a session id, use it! */
726 if(!SSL_set_session(backend->handle, ssl_sessionid)) {
727 Curl_ssl_delsessionid(data, ssl_sessionid);
728 infof(data, "Can't use session ID, going on without");
729 }
730 else
731 infof(data, "SSL reusing session ID");
732 }
733 Curl_ssl_sessionid_unlock(data);
734 }
735
736 #ifdef USE_ECH
737 if(ECH_ENABLED(data)) {
738 int trying_ech_now = 0;
739
740 if(data->set.str[STRING_ECH_PUBLIC]) {
741 infof(data, "ECH: outername not (yet) supported with WolfSSL");
742 return CURLE_SSL_CONNECT_ERROR;
743 }
744 if(data->set.tls_ech == CURLECH_GREASE) {
745 infof(data, "ECH: GREASE'd ECH not yet supported for wolfSSL");
746 return CURLE_SSL_CONNECT_ERROR;
747 }
748 if(data->set.tls_ech & CURLECH_CLA_CFG
749 && data->set.str[STRING_ECH_CONFIG]) {
750 char *b64val = data->set.str[STRING_ECH_CONFIG];
751 word32 b64len = 0;
752
753 b64len = (word32) strlen(b64val);
754 if(b64len
755 && wolfSSL_SetEchConfigsBase64(backend->handle, b64val, b64len)
756 != WOLFSSL_SUCCESS) {
757 if(data->set.tls_ech & CURLECH_HARD)
758 return CURLE_SSL_CONNECT_ERROR;
759 }
760 else {
761 trying_ech_now = 1;
762 infof(data, "ECH: ECHConfig from command line");
763 }
764 }
765 else {
766 struct Curl_dns_entry *dns = NULL;
767
768 dns = Curl_fetch_addr(data, connssl->peer.hostname, connssl->peer.port);
769 if(!dns) {
770 infof(data, "ECH: requested but no DNS info available");
771 if(data->set.tls_ech & CURLECH_HARD)
772 return CURLE_SSL_CONNECT_ERROR;
773 }
774 else {
775 struct Curl_https_rrinfo *rinfo = NULL;
776
777 rinfo = dns->hinfo;
778 if(rinfo && rinfo->echconfiglist) {
779 unsigned char *ecl = rinfo->echconfiglist;
780 size_t elen = rinfo->echconfiglist_len;
781
782 infof(data, "ECH: ECHConfig from DoH HTTPS RR");
783 if(wolfSSL_SetEchConfigs(backend->handle, ecl, (word32) elen) !=
784 WOLFSSL_SUCCESS) {
785 infof(data, "ECH: wolfSSL_SetEchConfigs failed");
786 if(data->set.tls_ech & CURLECH_HARD)
787 return CURLE_SSL_CONNECT_ERROR;
788 }
789 else {
790 trying_ech_now = 1;
791 infof(data, "ECH: imported ECHConfigList of length %ld", elen);
792 }
793 }
794 else {
795 infof(data, "ECH: requested but no ECHConfig available");
796 if(data->set.tls_ech & CURLECH_HARD)
797 return CURLE_SSL_CONNECT_ERROR;
798 }
799 Curl_resolv_unlock(data, dns);
800 }
801 }
802
803 if(trying_ech_now
804 && SSL_set_min_proto_version(backend->handle, TLS1_3_VERSION) != 1) {
805 infof(data, "ECH: Can't force TLSv1.3 [ERROR]");
806 return CURLE_SSL_CONNECT_ERROR;
807 }
808
809 }
810 #endif /* USE_ECH */
811
812 #ifdef USE_BIO_CHAIN
813 {
814 WOLFSSL_BIO *bio;
815
816 bio = BIO_new(wolfssl_bio_cf_method);
817 if(!bio)
818 return CURLE_OUT_OF_MEMORY;
819
820 wolfSSL_BIO_set_data(bio, cf);
821 wolfSSL_set_bio(backend->handle, bio, bio);
822 }
823 #else /* USE_BIO_CHAIN */
824 /* pass the raw socket into the SSL layer */
825 if(!wolfSSL_set_fd(backend->handle,
826 (int)Curl_conn_cf_get_socket(cf, data))) {
827 failf(data, "SSL: SSL_set_fd failed");
828 return CURLE_SSL_CONNECT_ERROR;
829 }
830 #endif /* !USE_BIO_CHAIN */
831
832 connssl->connecting_state = ssl_connect_2;
833 return CURLE_OK;
834 }
835
836
837 static CURLcode
wolfssl_connect_step2(struct Curl_cfilter * cf,struct Curl_easy * data)838 wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
839 {
840 int ret = -1;
841 struct ssl_connect_data *connssl = cf->ctx;
842 struct wolfssl_ssl_backend_data *backend =
843 (struct wolfssl_ssl_backend_data *)connssl->backend;
844 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
845 #ifndef CURL_DISABLE_PROXY
846 const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
847 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
848 data->set.str[STRING_SSL_PINNEDPUBLICKEY];
849 #else
850 const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
851 #endif
852
853 DEBUGASSERT(backend);
854
855 wolfSSL_ERR_clear_error();
856
857 /* Enable RFC2818 checks */
858 if(conn_config->verifyhost) {
859 char *snihost = connssl->peer.sni?
860 connssl->peer.sni : connssl->peer.hostname;
861 if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)
862 return CURLE_SSL_CONNECT_ERROR;
863 }
864
865 ret = wolfSSL_connect(backend->handle);
866
867 #ifdef OPENSSL_EXTRA
868 if(Curl_tls_keylog_enabled()) {
869 /* If key logging is enabled, wait for the handshake to complete and then
870 * proceed with logging secrets (for TLS 1.2 or older).
871 *
872 * During the handshake (ret==-1), wolfSSL_want_read() is true as it waits
873 * for the server response. At that point the master secret is not yet
874 * available, so we must not try to read it.
875 * To log the secret on completion with a handshake failure, detect
876 * completion via the observation that there is nothing to read or write.
877 * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever
878 * changes, the worst case is that no key is logged on error.
879 */
880 if(ret == SSL_SUCCESS ||
881 (!wolfSSL_want_read(backend->handle) &&
882 !wolfSSL_want_write(backend->handle))) {
883 wolfssl_log_tls12_secret(backend->handle);
884 /* Client Random and master secrets are no longer needed, erase these.
885 * Ignored while the handshake is still in progress. */
886 wolfSSL_FreeArrays(backend->handle);
887 }
888 }
889 #endif /* OPENSSL_EXTRA */
890
891 if(ret != 1) {
892 char error_buffer[WOLFSSL_MAX_ERROR_SZ];
893 int detail = wolfSSL_get_error(backend->handle, ret);
894
895 if(SSL_ERROR_WANT_READ == detail) {
896 connssl->connecting_state = ssl_connect_2_reading;
897 return CURLE_OK;
898 }
899 else if(SSL_ERROR_WANT_WRITE == detail) {
900 connssl->connecting_state = ssl_connect_2_writing;
901 return CURLE_OK;
902 }
903 /* There is no easy way to override only the CN matching.
904 * This will enable the override of both mismatching SubjectAltNames
905 * as also mismatching CN fields */
906 else if(DOMAIN_NAME_MISMATCH == detail) {
907 #if 1
908 failf(data, " subject alt name(s) or common name do not match \"%s\"",
909 connssl->peer.dispname);
910 return CURLE_PEER_FAILED_VERIFICATION;
911 #else
912 /* When the wolfssl_check_domain_name() is used and you desire to
913 * continue on a DOMAIN_NAME_MISMATCH, i.e. 'ssl_config.verifyhost
914 * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
915 * error. The only way to do this is currently to switch the
916 * Wolfssl_check_domain_name() in and out based on the
917 * 'ssl_config.verifyhost' value. */
918 if(conn_config->verifyhost) {
919 failf(data,
920 " subject alt name(s) or common name do not match \"%s\"\n",
921 connssl->dispname);
922 return CURLE_PEER_FAILED_VERIFICATION;
923 }
924 else {
925 infof(data,
926 " subject alt name(s) and/or common name do not match \"%s\"",
927 connssl->dispname);
928 return CURLE_OK;
929 }
930 #endif
931 }
932 #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
933 else if(ASN_NO_SIGNER_E == detail) {
934 if(conn_config->verifypeer) {
935 failf(data, " CA signer not available for verification");
936 return CURLE_SSL_CACERT_BADFILE;
937 }
938 else {
939 /* Just continue with a warning if no strict certificate
940 verification is required. */
941 infof(data, "CA signer not available for verification, "
942 "continuing anyway");
943 }
944 }
945 #endif
946 #ifdef USE_ECH
947 else if(-1 == detail) {
948 /* try access a retry_config ECHConfigList for tracing */
949 byte echConfigs[1000];
950 word32 echConfigsLen = 1000;
951 int rv = 0;
952
953 /* this currently doesn't produce the retry_configs */
954 rv = wolfSSL_GetEchConfigs(backend->handle, echConfigs,
955 &echConfigsLen);
956 if(rv != WOLFSSL_SUCCESS) {
957 infof(data, "Failed to get ECHConfigs");
958 }
959 else {
960 char *b64str = NULL;
961 size_t blen = 0;
962
963 rv = Curl_base64_encode((const char *)echConfigs, echConfigsLen,
964 &b64str, &blen);
965 if(!rv && b64str)
966 infof(data, "ECH: (not yet) retry_configs %s", b64str);
967 free(b64str);
968 }
969 }
970 #endif
971 else if(backend->io_result == CURLE_AGAIN) {
972 return CURLE_OK;
973 }
974 else {
975 failf(data, "SSL_connect failed with error %d: %s", detail,
976 wolfSSL_ERR_error_string(detail, error_buffer));
977 return CURLE_SSL_CONNECT_ERROR;
978 }
979 }
980
981 if(pinnedpubkey) {
982 #ifdef KEEP_PEER_CERT
983 X509 *x509;
984 const char *x509_der;
985 int x509_der_len;
986 struct Curl_X509certificate x509_parsed;
987 struct Curl_asn1Element *pubkey;
988 CURLcode result;
989
990 x509 = wolfSSL_get_peer_certificate(backend->handle);
991 if(!x509) {
992 failf(data, "SSL: failed retrieving server certificate");
993 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
994 }
995
996 x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
997 if(!x509_der) {
998 failf(data, "SSL: failed retrieving ASN.1 server certificate");
999 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1000 }
1001
1002 memset(&x509_parsed, 0, sizeof(x509_parsed));
1003 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
1004 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1005
1006 pubkey = &x509_parsed.subjectPublicKeyInfo;
1007 if(!pubkey->header || pubkey->end <= pubkey->header) {
1008 failf(data, "SSL: failed retrieving public key from server certificate");
1009 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1010 }
1011
1012 result = Curl_pin_peer_pubkey(data,
1013 pinnedpubkey,
1014 (const unsigned char *)pubkey->header,
1015 (size_t)(pubkey->end - pubkey->header));
1016 wolfSSL_FreeX509(x509);
1017 if(result) {
1018 failf(data, "SSL: public key does not match pinned public key");
1019 return result;
1020 }
1021 #else
1022 failf(data, "Library lacks pinning support built-in");
1023 return CURLE_NOT_BUILT_IN;
1024 #endif
1025 }
1026
1027 #ifdef HAVE_ALPN
1028 if(connssl->alpn) {
1029 int rc;
1030 char *protocol = NULL;
1031 unsigned short protocol_len = 0;
1032
1033 rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
1034
1035 if(rc == SSL_SUCCESS) {
1036 Curl_alpn_set_negotiated(cf, data, (const unsigned char *)protocol,
1037 protocol_len);
1038 }
1039 else if(rc == SSL_ALPN_NOT_FOUND)
1040 Curl_alpn_set_negotiated(cf, data, NULL, 0);
1041 else {
1042 failf(data, "ALPN, failure getting protocol, error %d", rc);
1043 return CURLE_SSL_CONNECT_ERROR;
1044 }
1045 }
1046 #endif /* HAVE_ALPN */
1047
1048 connssl->connecting_state = ssl_connect_3;
1049 #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
1050 infof(data, "SSL connection using %s / %s",
1051 wolfSSL_get_version(backend->handle),
1052 wolfSSL_get_cipher_name(backend->handle));
1053 #else
1054 infof(data, "SSL connected");
1055 #endif
1056
1057 return CURLE_OK;
1058 }
1059
1060
wolfssl_session_free(void * sessionid,size_t idsize)1061 static void wolfssl_session_free(void *sessionid, size_t idsize)
1062 {
1063 (void)idsize;
1064 wolfSSL_SESSION_free(sessionid);
1065 }
1066
1067
1068 static CURLcode
wolfssl_connect_step3(struct Curl_cfilter * cf,struct Curl_easy * data)1069 wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
1070 {
1071 CURLcode result = CURLE_OK;
1072 struct ssl_connect_data *connssl = cf->ctx;
1073 struct wolfssl_ssl_backend_data *backend =
1074 (struct wolfssl_ssl_backend_data *)connssl->backend;
1075 const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
1076
1077 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1078 DEBUGASSERT(backend);
1079
1080 if(ssl_config->primary.sessionid) {
1081 /* wolfSSL_get1_session allocates memory that has to be freed. */
1082 WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);
1083
1084 if(our_ssl_sessionid) {
1085 void *old_ssl_sessionid = NULL;
1086 bool incache;
1087 Curl_ssl_sessionid_lock(data);
1088 incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
1089 &old_ssl_sessionid, NULL));
1090 if(incache) {
1091 Curl_ssl_delsessionid(data, old_ssl_sessionid);
1092 }
1093
1094 /* call takes ownership of `our_ssl_sessionid` */
1095 result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
1096 our_ssl_sessionid, 0,
1097 wolfssl_session_free);
1098 Curl_ssl_sessionid_unlock(data);
1099 if(result) {
1100 failf(data, "failed to store ssl session");
1101 return result;
1102 }
1103 }
1104 }
1105
1106 connssl->connecting_state = ssl_connect_done;
1107
1108 return result;
1109 }
1110
1111
wolfssl_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * mem,size_t len,CURLcode * curlcode)1112 static ssize_t wolfssl_send(struct Curl_cfilter *cf,
1113 struct Curl_easy *data,
1114 const void *mem,
1115 size_t len,
1116 CURLcode *curlcode)
1117 {
1118 struct ssl_connect_data *connssl = cf->ctx;
1119 struct wolfssl_ssl_backend_data *backend =
1120 (struct wolfssl_ssl_backend_data *)connssl->backend;
1121 char error_buffer[WOLFSSL_MAX_ERROR_SZ];
1122 int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
1123 int rc;
1124
1125 DEBUGASSERT(backend);
1126
1127 wolfSSL_ERR_clear_error();
1128
1129 rc = wolfSSL_write(backend->handle, mem, memlen);
1130 if(rc <= 0) {
1131 int err = wolfSSL_get_error(backend->handle, rc);
1132
1133 switch(err) {
1134 case SSL_ERROR_WANT_READ:
1135 case SSL_ERROR_WANT_WRITE:
1136 /* there's data pending, re-invoke SSL_write() */
1137 CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
1138 *curlcode = CURLE_AGAIN;
1139 return -1;
1140 default:
1141 if(backend->io_result == CURLE_AGAIN) {
1142 CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
1143 *curlcode = CURLE_AGAIN;
1144 return -1;
1145 }
1146 CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err);
1147 failf(data, "SSL write: %s, errno %d",
1148 wolfSSL_ERR_error_string(err, error_buffer),
1149 SOCKERRNO);
1150 *curlcode = CURLE_SEND_ERROR;
1151 return -1;
1152 }
1153 }
1154 CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc);
1155 return rc;
1156 }
1157
wolfssl_close(struct Curl_cfilter * cf,struct Curl_easy * data)1158 static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1159 {
1160 struct ssl_connect_data *connssl = cf->ctx;
1161 struct wolfssl_ssl_backend_data *backend =
1162 (struct wolfssl_ssl_backend_data *)connssl->backend;
1163
1164 (void) data;
1165
1166 DEBUGASSERT(backend);
1167
1168 if(backend->handle) {
1169 char buf[32];
1170 /* Maybe the server has already sent a close notify alert.
1171 Read it to avoid an RST on the TCP connection. */
1172 (void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf));
1173 if(!connssl->peer_closed)
1174 (void)wolfSSL_shutdown(backend->handle);
1175 wolfSSL_free(backend->handle);
1176 backend->handle = NULL;
1177 }
1178 if(backend->ctx) {
1179 wolfSSL_CTX_free(backend->ctx);
1180 backend->ctx = NULL;
1181 }
1182 }
1183
wolfssl_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t blen,CURLcode * curlcode)1184 static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
1185 struct Curl_easy *data,
1186 char *buf, size_t blen,
1187 CURLcode *curlcode)
1188 {
1189 struct ssl_connect_data *connssl = cf->ctx;
1190 struct wolfssl_ssl_backend_data *backend =
1191 (struct wolfssl_ssl_backend_data *)connssl->backend;
1192 char error_buffer[WOLFSSL_MAX_ERROR_SZ];
1193 int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
1194 int nread;
1195
1196 DEBUGASSERT(backend);
1197
1198 wolfSSL_ERR_clear_error();
1199 *curlcode = CURLE_OK;
1200
1201 nread = wolfSSL_read(backend->handle, buf, buffsize);
1202
1203 if(nread <= 0) {
1204 int err = wolfSSL_get_error(backend->handle, nread);
1205
1206 switch(err) {
1207 case SSL_ERROR_ZERO_RETURN: /* no more data */
1208 CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
1209 *curlcode = CURLE_OK;
1210 return 0;
1211 case SSL_ERROR_NONE:
1212 case SSL_ERROR_WANT_READ:
1213 case SSL_ERROR_WANT_WRITE:
1214 /* there's data pending, re-invoke wolfSSL_read() */
1215 CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
1216 *curlcode = CURLE_AGAIN;
1217 return -1;
1218 default:
1219 if(backend->io_result == CURLE_AGAIN) {
1220 CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
1221 *curlcode = CURLE_AGAIN;
1222 return -1;
1223 }
1224 failf(data, "SSL read: %s, errno %d",
1225 wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO);
1226 *curlcode = CURLE_RECV_ERROR;
1227 return -1;
1228 }
1229 }
1230 CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread);
1231 return nread;
1232 }
1233
1234
wolfssl_version(char * buffer,size_t size)1235 static size_t wolfssl_version(char *buffer, size_t size)
1236 {
1237 #if LIBWOLFSSL_VERSION_HEX >= 0x03006000
1238 return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
1239 #elif defined(WOLFSSL_VERSION)
1240 return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
1241 #endif
1242 }
1243
1244
wolfssl_init(void)1245 static int wolfssl_init(void)
1246 {
1247 int ret;
1248
1249 #ifdef OPENSSL_EXTRA
1250 Curl_tls_keylog_open();
1251 #endif
1252 ret = (wolfSSL_Init() == SSL_SUCCESS);
1253 wolfssl_bio_cf_init_methods();
1254 return ret;
1255 }
1256
1257
wolfssl_cleanup(void)1258 static void wolfssl_cleanup(void)
1259 {
1260 wolfssl_bio_cf_free_methods();
1261 wolfSSL_Cleanup();
1262 #ifdef OPENSSL_EXTRA
1263 Curl_tls_keylog_close();
1264 #endif
1265 }
1266
1267
wolfssl_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)1268 static bool wolfssl_data_pending(struct Curl_cfilter *cf,
1269 const struct Curl_easy *data)
1270 {
1271 struct ssl_connect_data *ctx = cf->ctx;
1272 struct wolfssl_ssl_backend_data *backend;
1273
1274 (void)data;
1275 DEBUGASSERT(ctx && ctx->backend);
1276
1277 backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
1278 if(backend->handle) /* SSL is in use */
1279 return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
1280 else
1281 return FALSE;
1282 }
1283
1284
1285 /*
1286 * This function is called to shut down the SSL layer but keep the
1287 * socket open (CCC - Clear Command Channel)
1288 */
wolfssl_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data)1289 static int wolfssl_shutdown(struct Curl_cfilter *cf,
1290 struct Curl_easy *data)
1291 {
1292 struct ssl_connect_data *ctx = cf->ctx;
1293 struct wolfssl_ssl_backend_data *backend;
1294 int retval = 0;
1295
1296 (void)data;
1297 DEBUGASSERT(ctx && ctx->backend);
1298
1299 backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
1300 if(backend->handle) {
1301 wolfSSL_ERR_clear_error();
1302 wolfSSL_free(backend->handle);
1303 backend->handle = NULL;
1304 }
1305 return retval;
1306 }
1307
1308
1309 static CURLcode
wolfssl_connect_common(struct Curl_cfilter * cf,struct Curl_easy * data,bool nonblocking,bool * done)1310 wolfssl_connect_common(struct Curl_cfilter *cf,
1311 struct Curl_easy *data,
1312 bool nonblocking,
1313 bool *done)
1314 {
1315 CURLcode result;
1316 struct ssl_connect_data *connssl = cf->ctx;
1317 curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
1318 int what;
1319
1320 /* check if the connection has already been established */
1321 if(ssl_connection_complete == connssl->state) {
1322 *done = TRUE;
1323 return CURLE_OK;
1324 }
1325
1326 if(ssl_connect_1 == connssl->connecting_state) {
1327 /* Find out how much more time we're allowed */
1328 const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
1329
1330 if(timeout_ms < 0) {
1331 /* no need to continue if time already is up */
1332 failf(data, "SSL connection timeout");
1333 return CURLE_OPERATION_TIMEDOUT;
1334 }
1335
1336 result = wolfssl_connect_step1(cf, data);
1337 if(result)
1338 return result;
1339 }
1340
1341 while(ssl_connect_2 == connssl->connecting_state ||
1342 ssl_connect_2_reading == connssl->connecting_state ||
1343 ssl_connect_2_writing == connssl->connecting_state) {
1344
1345 /* check allowed time left */
1346 const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
1347
1348 if(timeout_ms < 0) {
1349 /* no need to continue if time already is up */
1350 failf(data, "SSL connection timeout");
1351 return CURLE_OPERATION_TIMEDOUT;
1352 }
1353
1354 /* if ssl is expecting something, check if it's available. */
1355 if(connssl->connecting_state == ssl_connect_2_reading
1356 || connssl->connecting_state == ssl_connect_2_writing) {
1357
1358 curl_socket_t writefd = ssl_connect_2_writing ==
1359 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1360 curl_socket_t readfd = ssl_connect_2_reading ==
1361 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1362
1363 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1364 nonblocking?0:timeout_ms);
1365 if(what < 0) {
1366 /* fatal error */
1367 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1368 return CURLE_SSL_CONNECT_ERROR;
1369 }
1370 else if(0 == what) {
1371 if(nonblocking) {
1372 *done = FALSE;
1373 return CURLE_OK;
1374 }
1375 else {
1376 /* timeout */
1377 failf(data, "SSL connection timeout");
1378 return CURLE_OPERATION_TIMEDOUT;
1379 }
1380 }
1381 /* socket is readable or writable */
1382 }
1383
1384 /* Run transaction, and return to the caller if it failed or if
1385 * this connection is part of a multi handle and this loop would
1386 * execute again. This permits the owner of a multi handle to
1387 * abort a connection attempt before step2 has completed while
1388 * ensuring that a client using select() or epoll() will always
1389 * have a valid fdset to wait on.
1390 */
1391 result = wolfssl_connect_step2(cf, data);
1392 if(result || (nonblocking &&
1393 (ssl_connect_2 == connssl->connecting_state ||
1394 ssl_connect_2_reading == connssl->connecting_state ||
1395 ssl_connect_2_writing == connssl->connecting_state)))
1396 return result;
1397 } /* repeat step2 until all transactions are done. */
1398
1399 if(ssl_connect_3 == connssl->connecting_state) {
1400 result = wolfssl_connect_step3(cf, data);
1401 if(result)
1402 return result;
1403 }
1404
1405 if(ssl_connect_done == connssl->connecting_state) {
1406 connssl->state = ssl_connection_complete;
1407 *done = TRUE;
1408 }
1409 else
1410 *done = FALSE;
1411
1412 /* Reset our connect state machine */
1413 connssl->connecting_state = ssl_connect_1;
1414
1415 return CURLE_OK;
1416 }
1417
1418
wolfssl_connect_nonblocking(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)1419 static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf,
1420 struct Curl_easy *data,
1421 bool *done)
1422 {
1423 return wolfssl_connect_common(cf, data, TRUE, done);
1424 }
1425
1426
wolfssl_connect(struct Curl_cfilter * cf,struct Curl_easy * data)1427 static CURLcode wolfssl_connect(struct Curl_cfilter *cf,
1428 struct Curl_easy *data)
1429 {
1430 CURLcode result;
1431 bool done = FALSE;
1432
1433 result = wolfssl_connect_common(cf, data, FALSE, &done);
1434 if(result)
1435 return result;
1436
1437 DEBUGASSERT(done);
1438
1439 return CURLE_OK;
1440 }
1441
wolfssl_random(struct Curl_easy * data,unsigned char * entropy,size_t length)1442 static CURLcode wolfssl_random(struct Curl_easy *data,
1443 unsigned char *entropy, size_t length)
1444 {
1445 WC_RNG rng;
1446 (void)data;
1447 if(wc_InitRng(&rng))
1448 return CURLE_FAILED_INIT;
1449 if(length > UINT_MAX)
1450 return CURLE_FAILED_INIT;
1451 if(wc_RNG_GenerateBlock(&rng, entropy, (unsigned)length))
1452 return CURLE_FAILED_INIT;
1453 if(wc_FreeRng(&rng))
1454 return CURLE_FAILED_INIT;
1455 return CURLE_OK;
1456 }
1457
wolfssl_sha256sum(const unsigned char * tmp,size_t tmplen,unsigned char * sha256sum,size_t unused)1458 static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
1459 size_t tmplen,
1460 unsigned char *sha256sum /* output */,
1461 size_t unused)
1462 {
1463 wc_Sha256 SHA256pw;
1464 (void)unused;
1465 if(wc_InitSha256(&SHA256pw))
1466 return CURLE_FAILED_INIT;
1467 wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen);
1468 wc_Sha256Final(&SHA256pw, sha256sum);
1469 return CURLE_OK;
1470 }
1471
wolfssl_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)1472 static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
1473 CURLINFO info UNUSED_PARAM)
1474 {
1475 struct wolfssl_ssl_backend_data *backend =
1476 (struct wolfssl_ssl_backend_data *)connssl->backend;
1477 (void)info;
1478 DEBUGASSERT(backend);
1479 return backend->handle;
1480 }
1481
1482 const struct Curl_ssl Curl_ssl_wolfssl = {
1483 { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
1484
1485 #ifdef KEEP_PEER_CERT
1486 SSLSUPP_PINNEDPUBKEY |
1487 #endif
1488 #ifdef USE_BIO_CHAIN
1489 SSLSUPP_HTTPS_PROXY |
1490 #endif
1491 SSLSUPP_CA_PATH |
1492 SSLSUPP_CAINFO_BLOB |
1493 #ifdef USE_ECH
1494 SSLSUPP_ECH |
1495 #endif
1496 SSLSUPP_SSL_CTX,
1497
1498 sizeof(struct wolfssl_ssl_backend_data),
1499
1500 wolfssl_init, /* init */
1501 wolfssl_cleanup, /* cleanup */
1502 wolfssl_version, /* version */
1503 Curl_none_check_cxn, /* check_cxn */
1504 wolfssl_shutdown, /* shutdown */
1505 wolfssl_data_pending, /* data_pending */
1506 wolfssl_random, /* random */
1507 Curl_none_cert_status_request, /* cert_status_request */
1508 wolfssl_connect, /* connect */
1509 wolfssl_connect_nonblocking, /* connect_nonblocking */
1510 Curl_ssl_adjust_pollset, /* adjust_pollset */
1511 wolfssl_get_internals, /* get_internals */
1512 wolfssl_close, /* close_one */
1513 Curl_none_close_all, /* close_all */
1514 Curl_none_set_engine, /* set_engine */
1515 Curl_none_set_engine_default, /* set_engine_default */
1516 Curl_none_engines_list, /* engines_list */
1517 Curl_none_false_start, /* false_start */
1518 wolfssl_sha256sum, /* sha256sum */
1519 NULL, /* associate_connection */
1520 NULL, /* disassociate_connection */
1521 NULL, /* free_multi_ssl_backend_data */
1522 wolfssl_recv, /* recv decrypted data */
1523 wolfssl_send, /* send data to encrypt */
1524 };
1525
1526 #endif
1527