xref: /curl/lib/vtls/wolfssl.c (revision fb22459d)
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