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