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