VirtualBox

source: vbox/trunk/src/libs/curl-8.3.0/lib/vtls/wolfssl.c@ 101127

Last change on this file since 101127 was 101127, checked in by vboxsync, 19 months ago

curl-8.3.0: Applied and adjusted our curl changes to 8.0.1. bugref:10526

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette