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