• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2019, 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.haxx.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  ***************************************************************************/
22 
23 /*
24  * Source file for all wolfSSL specific code for the TLS/SSL layer. No code
25  * but vtls.c should ever call or use these functions.
26  *
27  */
28 
29 #include "curl_setup.h"
30 
31 #ifdef USE_WOLFSSL
32 
33 #define WOLFSSL_OPTIONS_IGNORE_SYS
34 #include <wolfssl/version.h>
35 #include <wolfssl/options.h>
36 
37 /* To determine what functions are available we rely on one or both of:
38    - the user's options.h generated by wolfSSL
39    - the symbols detected by curl's configure
40    Since they are markedly different from one another, and one or the other may
41    not be available, we do some checking below to bring things in sync. */
42 
43 /* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
44 #ifndef HAVE_ALPN
45 #ifdef HAVE_WOLFSSL_USEALPN
46 #define HAVE_ALPN
47 #endif
48 #endif
49 
50 /* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in
51    options.h, but is only seen in >= 3.6.6 since that's when they started
52    disabling SSLv3 by default. */
53 #ifndef WOLFSSL_ALLOW_SSLV3
54 #if (LIBWOLFSSL_VERSION_HEX < 0x03006006) || \
55   defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
56 #define WOLFSSL_ALLOW_SSLV3
57 #endif
58 #endif
59 
60 #include <limits.h>
61 
62 #include "urldata.h"
63 #include "sendf.h"
64 #include "inet_pton.h"
65 #include "vtls.h"
66 #include "parsedate.h"
67 #include "connect.h" /* for the connect timeout */
68 #include "select.h"
69 #include "strcase.h"
70 #include "x509asn1.h"
71 #include "curl_printf.h"
72 #include "multiif.h"
73 
74 #include <wolfssl/openssl/ssl.h>
75 #include <wolfssl/ssl.h>
76 #include <wolfssl/error-ssl.h>
77 #include "wolfssl.h"
78 
79 /* The last #include files should be: */
80 #include "curl_memory.h"
81 #include "memdebug.h"
82 
83 /* KEEP_PEER_CERT is a product of the presence of build time symbol
84    OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
85    in wolfSSL's settings.h, and the latter two are build time symbols in
86    options.h. */
87 #ifndef KEEP_PEER_CERT
88 #if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
89     (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
90 #define KEEP_PEER_CERT
91 #endif
92 #endif
93 
94 struct ssl_backend_data {
95   SSL_CTX* ctx;
96   SSL*     handle;
97 };
98 
99 #define BACKEND connssl->backend
100 
101 static Curl_recv wolfssl_recv;
102 static Curl_send wolfssl_send;
103 
104 
do_file_type(const char * type)105 static int do_file_type(const char *type)
106 {
107   if(!type || !type[0])
108     return SSL_FILETYPE_PEM;
109   if(strcasecompare(type, "PEM"))
110     return SSL_FILETYPE_PEM;
111   if(strcasecompare(type, "DER"))
112     return SSL_FILETYPE_ASN1;
113   return -1;
114 }
115 
116 /*
117  * This function loads all the client/CA certificates and CRLs. Setup the TLS
118  * layer and do all necessary magic.
119  */
120 static CURLcode
wolfssl_connect_step1(struct connectdata * conn,int sockindex)121 wolfssl_connect_step1(struct connectdata *conn,
122                      int sockindex)
123 {
124   char *ciphers;
125   struct Curl_easy *data = conn->data;
126   struct ssl_connect_data* connssl = &conn->ssl[sockindex];
127   SSL_METHOD* req_method = NULL;
128   curl_socket_t sockfd = conn->sock[sockindex];
129 #ifdef HAVE_SNI
130   bool sni = FALSE;
131 #define use_sni(x)  sni = (x)
132 #else
133 #define use_sni(x)  Curl_nop_stmt
134 #endif
135 
136   if(connssl->state == ssl_connection_complete)
137     return CURLE_OK;
138 
139   if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
140     failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
141     return CURLE_SSL_CONNECT_ERROR;
142   }
143 
144   /* check to see if we've been told to use an explicit SSL/TLS version */
145   switch(SSL_CONN_CONFIG(version)) {
146   case CURL_SSLVERSION_DEFAULT:
147   case CURL_SSLVERSION_TLSv1:
148 #if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
149     /* minimum protocol version is set later after the CTX object is created */
150     req_method = SSLv23_client_method();
151 #else
152     infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
153           "TLS 1.0 is used exclusively\n");
154     req_method = TLSv1_client_method();
155 #endif
156     use_sni(TRUE);
157     break;
158   case CURL_SSLVERSION_TLSv1_0:
159 #ifdef WOLFSSL_ALLOW_TLSV10
160     req_method = TLSv1_client_method();
161     use_sni(TRUE);
162 #else
163     failf(data, "wolfSSL does not support TLS 1.0");
164     return CURLE_NOT_BUILT_IN;
165 #endif
166     break;
167   case CURL_SSLVERSION_TLSv1_1:
168     req_method = TLSv1_1_client_method();
169     use_sni(TRUE);
170     break;
171   case CURL_SSLVERSION_TLSv1_2:
172     req_method = TLSv1_2_client_method();
173     use_sni(TRUE);
174     break;
175   case CURL_SSLVERSION_TLSv1_3:
176 #ifdef WOLFSSL_TLS13
177     req_method = wolfTLSv1_3_client_method();
178     use_sni(TRUE);
179     break;
180 #else
181     failf(data, "wolfSSL: TLS 1.3 is not yet supported");
182     return CURLE_SSL_CONNECT_ERROR;
183 #endif
184   case CURL_SSLVERSION_SSLv3:
185 #ifdef WOLFSSL_ALLOW_SSLV3
186     req_method = SSLv3_client_method();
187     use_sni(FALSE);
188 #else
189     failf(data, "wolfSSL does not support SSLv3");
190     return CURLE_NOT_BUILT_IN;
191 #endif
192     break;
193   case CURL_SSLVERSION_SSLv2:
194     failf(data, "wolfSSL does not support SSLv2");
195     return CURLE_SSL_CONNECT_ERROR;
196   default:
197     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
198     return CURLE_SSL_CONNECT_ERROR;
199   }
200 
201   if(!req_method) {
202     failf(data, "SSL: couldn't create a method!");
203     return CURLE_OUT_OF_MEMORY;
204   }
205 
206   if(BACKEND->ctx)
207     SSL_CTX_free(BACKEND->ctx);
208   BACKEND->ctx = SSL_CTX_new(req_method);
209 
210   if(!BACKEND->ctx) {
211     failf(data, "SSL: couldn't create a context!");
212     return CURLE_OUT_OF_MEMORY;
213   }
214 
215   switch(SSL_CONN_CONFIG(version)) {
216   case CURL_SSLVERSION_DEFAULT:
217   case CURL_SSLVERSION_TLSv1:
218 #if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
219     /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is
220      * whatever minimum version of TLS was built in and at least TLS 1.0. For
221      * later library versions that could change (eg TLS 1.0 built in but
222      * defaults to TLS 1.1) so we have this short circuit evaluation to find
223      * the minimum supported TLS version.
224     */
225     if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) &&
226        (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) &&
227        (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1)
228 #ifdef WOLFSSL_TLS13
229        && (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_3) != 1)
230 #endif
231       ) {
232       failf(data, "SSL: couldn't set the minimum protocol version");
233       return CURLE_SSL_CONNECT_ERROR;
234     }
235 #endif
236     break;
237   }
238 
239   ciphers = SSL_CONN_CONFIG(cipher_list);
240   if(ciphers) {
241     if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
242       failf(data, "failed setting cipher list: %s", ciphers);
243       return CURLE_SSL_CIPHER;
244     }
245     infof(data, "Cipher selection: %s\n", ciphers);
246   }
247 
248 #ifndef NO_FILESYSTEM
249   /* load trusted cacert */
250   if(SSL_CONN_CONFIG(CAfile)) {
251     if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx,
252                                       SSL_CONN_CONFIG(CAfile),
253                                       SSL_CONN_CONFIG(CApath))) {
254       if(SSL_CONN_CONFIG(verifypeer)) {
255         /* Fail if we insist on successfully verifying the server. */
256         failf(data, "error setting certificate verify locations:\n"
257               "  CAfile: %s\n  CApath: %s",
258               SSL_CONN_CONFIG(CAfile)?
259               SSL_CONN_CONFIG(CAfile): "none",
260               SSL_CONN_CONFIG(CApath)?
261               SSL_CONN_CONFIG(CApath) : "none");
262         return CURLE_SSL_CACERT_BADFILE;
263       }
264       else {
265         /* Just continue with a warning if no strict certificate
266            verification is required. */
267         infof(data, "error setting certificate verify locations,"
268               " continuing anyway:\n");
269       }
270     }
271     else {
272       /* Everything is fine. */
273       infof(data, "successfully set certificate verify locations:\n");
274     }
275     infof(data,
276           "  CAfile: %s\n"
277           "  CApath: %s\n",
278           SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
279           "none",
280           SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath):
281           "none");
282   }
283 
284   /* Load the client certificate, and private key */
285   if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
286     int file_type = do_file_type(SSL_SET_OPTION(cert_type));
287 
288     if(SSL_CTX_use_certificate_file(BACKEND->ctx, SSL_SET_OPTION(cert),
289                                      file_type) != 1) {
290       failf(data, "unable to use client certificate (no key or wrong pass"
291             " phrase?)");
292       return CURLE_SSL_CONNECT_ERROR;
293     }
294 
295     file_type = do_file_type(SSL_SET_OPTION(key_type));
296     if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key),
297                                     file_type) != 1) {
298       failf(data, "unable to set private key");
299       return CURLE_SSL_CONNECT_ERROR;
300     }
301   }
302 #endif /* !NO_FILESYSTEM */
303 
304   /* SSL always tries to verify the peer, this only says whether it should
305    * fail to connect if the verification fails, or if it should continue
306    * anyway. In the latter case the result of the verification is checked with
307    * SSL_get_verify_result() below. */
308   SSL_CTX_set_verify(BACKEND->ctx,
309                      SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
310                                                  SSL_VERIFY_NONE,
311                      NULL);
312 
313 #ifdef HAVE_SNI
314   if(sni) {
315     struct in_addr addr4;
316 #ifdef ENABLE_IPV6
317     struct in6_addr addr6;
318 #endif
319     const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
320       conn->host.name;
321     size_t hostname_len = strlen(hostname);
322     if((hostname_len < USHRT_MAX) &&
323        (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
324 #ifdef ENABLE_IPV6
325        (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
326 #endif
327        (wolfSSL_CTX_UseSNI(BACKEND->ctx, WOLFSSL_SNI_HOST_NAME, hostname,
328                           (unsigned short)hostname_len) != 1)) {
329       infof(data, "WARNING: failed to configure server name indication (SNI) "
330             "TLS extension\n");
331     }
332   }
333 #endif
334 
335   /* give application a chance to interfere with SSL set up. */
336   if(data->set.ssl.fsslctx) {
337     CURLcode result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx,
338                                                data->set.ssl.fsslctxp);
339     if(result) {
340       failf(data, "error signaled by ssl ctx callback");
341       return result;
342     }
343   }
344 #ifdef NO_FILESYSTEM
345   else if(SSL_CONN_CONFIG(verifypeer)) {
346     failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
347           " with \"no filesystem\". Either disable peer verification"
348           " (insecure) or if you are building an application with libcurl you"
349           " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
350     return CURLE_SSL_CONNECT_ERROR;
351   }
352 #endif
353 
354   /* Let's make an SSL structure */
355   if(BACKEND->handle)
356     SSL_free(BACKEND->handle);
357   BACKEND->handle = SSL_new(BACKEND->ctx);
358   if(!BACKEND->handle) {
359     failf(data, "SSL: couldn't create a context (handle)!");
360     return CURLE_OUT_OF_MEMORY;
361   }
362 
363 #ifdef HAVE_ALPN
364   if(conn->bits.tls_enable_alpn) {
365     char protocols[128];
366     *protocols = '\0';
367 
368     /* wolfSSL's ALPN protocol name list format is a comma separated string of
369        protocols in descending order of preference, eg: "h2,http/1.1" */
370 
371 #ifdef USE_NGHTTP2
372     if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
373       strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
374       infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
375     }
376 #endif
377 
378     strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
379     infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
380 
381     if(wolfSSL_UseALPN(BACKEND->handle, protocols,
382                        (unsigned)strlen(protocols),
383                        WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
384       failf(data, "SSL: failed setting ALPN protocols");
385       return CURLE_SSL_CONNECT_ERROR;
386     }
387   }
388 #endif /* HAVE_ALPN */
389 
390   /* Check if there's a cached ID we can/should use here! */
391   if(SSL_SET_OPTION(primary.sessionid)) {
392     void *ssl_sessionid = NULL;
393 
394     Curl_ssl_sessionid_lock(conn);
395     if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
396       /* we got a session id, use it! */
397       if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
398         char error_buffer[WOLFSSL_MAX_ERROR_SZ];
399         Curl_ssl_sessionid_unlock(conn);
400         failf(data, "SSL: SSL_set_session failed: %s",
401               ERR_error_string(SSL_get_error(BACKEND->handle, 0),
402                                error_buffer));
403         return CURLE_SSL_CONNECT_ERROR;
404       }
405       /* Informational message */
406       infof(data, "SSL re-using session ID\n");
407     }
408     Curl_ssl_sessionid_unlock(conn);
409   }
410 
411   /* pass the raw socket into the SSL layer */
412   if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) {
413     failf(data, "SSL: SSL_set_fd failed");
414     return CURLE_SSL_CONNECT_ERROR;
415   }
416 
417   connssl->connecting_state = ssl_connect_2;
418   return CURLE_OK;
419 }
420 
421 
422 static CURLcode
wolfssl_connect_step2(struct connectdata * conn,int sockindex)423 wolfssl_connect_step2(struct connectdata *conn,
424                      int sockindex)
425 {
426   int ret = -1;
427   struct Curl_easy *data = conn->data;
428   struct ssl_connect_data* connssl = &conn->ssl[sockindex];
429   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
430     conn->host.name;
431   const char * const dispname = SSL_IS_PROXY() ?
432     conn->http_proxy.host.dispname : conn->host.dispname;
433   const char * const pinnedpubkey = SSL_IS_PROXY() ?
434                         data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
435                         data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
436 
437   conn->recv[sockindex] = wolfssl_recv;
438   conn->send[sockindex] = wolfssl_send;
439 
440   /* Enable RFC2818 checks */
441   if(SSL_CONN_CONFIG(verifyhost)) {
442     ret = wolfSSL_check_domain_name(BACKEND->handle, hostname);
443     if(ret == SSL_FAILURE)
444       return CURLE_OUT_OF_MEMORY;
445   }
446 
447   ret = SSL_connect(BACKEND->handle);
448   if(ret != 1) {
449     char error_buffer[WOLFSSL_MAX_ERROR_SZ];
450     int  detail = SSL_get_error(BACKEND->handle, ret);
451 
452     if(SSL_ERROR_WANT_READ == detail) {
453       connssl->connecting_state = ssl_connect_2_reading;
454       return CURLE_OK;
455     }
456     else if(SSL_ERROR_WANT_WRITE == detail) {
457       connssl->connecting_state = ssl_connect_2_writing;
458       return CURLE_OK;
459     }
460     /* There is no easy way to override only the CN matching.
461      * This will enable the override of both mismatching SubjectAltNames
462      * as also mismatching CN fields */
463     else if(DOMAIN_NAME_MISMATCH == detail) {
464 #if 1
465       failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
466             dispname);
467       return CURLE_PEER_FAILED_VERIFICATION;
468 #else
469       /* When the wolfssl_check_domain_name() is used and you desire to
470        * continue on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost
471        * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
472        * error. The only way to do this is currently to switch the
473        * Wolfssl_check_domain_name() in and out based on the
474        * 'conn->ssl_config.verifyhost' value. */
475       if(SSL_CONN_CONFIG(verifyhost)) {
476         failf(data,
477               "\tsubject alt name(s) or common name do not match \"%s\"\n",
478               dispname);
479         return CURLE_PEER_FAILED_VERIFICATION;
480       }
481       else {
482         infof(data,
483               "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
484               dispname);
485         return CURLE_OK;
486       }
487 #endif
488     }
489 #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
490     else if(ASN_NO_SIGNER_E == detail) {
491       if(SSL_CONN_CONFIG(verifypeer)) {
492         failf(data, "\tCA signer not available for verification\n");
493         return CURLE_SSL_CACERT_BADFILE;
494       }
495       else {
496         /* Just continue with a warning if no strict certificate
497            verification is required. */
498         infof(data, "CA signer not available for verification, "
499                     "continuing anyway\n");
500       }
501     }
502 #endif
503     else {
504       failf(data, "SSL_connect failed with error %d: %s", detail,
505           ERR_error_string(detail, error_buffer));
506       return CURLE_SSL_CONNECT_ERROR;
507     }
508   }
509 
510   if(pinnedpubkey) {
511 #ifdef KEEP_PEER_CERT
512     X509 *x509;
513     const char *x509_der;
514     int x509_der_len;
515     curl_X509certificate x509_parsed;
516     curl_asn1Element *pubkey;
517     CURLcode result;
518 
519     x509 = SSL_get_peer_certificate(BACKEND->handle);
520     if(!x509) {
521       failf(data, "SSL: failed retrieving server certificate");
522       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
523     }
524 
525     x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
526     if(!x509_der) {
527       failf(data, "SSL: failed retrieving ASN.1 server certificate");
528       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
529     }
530 
531     memset(&x509_parsed, 0, sizeof(x509_parsed));
532     if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
533       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
534 
535     pubkey = &x509_parsed.subjectPublicKeyInfo;
536     if(!pubkey->header || pubkey->end <= pubkey->header) {
537       failf(data, "SSL: failed retrieving public key from server certificate");
538       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
539     }
540 
541     result = Curl_pin_peer_pubkey(data,
542                                   pinnedpubkey,
543                                   (const unsigned char *)pubkey->header,
544                                   (size_t)(pubkey->end - pubkey->header));
545     if(result) {
546       failf(data, "SSL: public key does not match pinned public key!");
547       return result;
548     }
549 #else
550     failf(data, "Library lacks pinning support built-in");
551     return CURLE_NOT_BUILT_IN;
552 #endif
553   }
554 
555 #ifdef HAVE_ALPN
556   if(conn->bits.tls_enable_alpn) {
557     int rc;
558     char *protocol = NULL;
559     unsigned short protocol_len = 0;
560 
561     rc = wolfSSL_ALPN_GetProtocol(BACKEND->handle, &protocol, &protocol_len);
562 
563     if(rc == SSL_SUCCESS) {
564       infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
565             protocol);
566 
567       if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
568          !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
569         conn->negnpn = CURL_HTTP_VERSION_1_1;
570 #ifdef USE_NGHTTP2
571       else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
572               protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
573               !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
574                       NGHTTP2_PROTO_VERSION_ID_LEN))
575         conn->negnpn = CURL_HTTP_VERSION_2;
576 #endif
577       else
578         infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
579               protocol);
580       Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
581                           BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
582     }
583     else if(rc == SSL_ALPN_NOT_FOUND)
584       infof(data, "ALPN, server did not agree to a protocol\n");
585     else {
586       failf(data, "ALPN, failure getting protocol, error %d", rc);
587       return CURLE_SSL_CONNECT_ERROR;
588     }
589   }
590 #endif /* HAVE_ALPN */
591 
592   connssl->connecting_state = ssl_connect_3;
593 #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
594   infof(data, "SSL connection using %s / %s\n",
595         wolfSSL_get_version(BACKEND->handle),
596         wolfSSL_get_cipher_name(BACKEND->handle));
597 #else
598   infof(data, "SSL connected\n");
599 #endif
600 
601   return CURLE_OK;
602 }
603 
604 
605 static CURLcode
wolfssl_connect_step3(struct connectdata * conn,int sockindex)606 wolfssl_connect_step3(struct connectdata *conn,
607                      int sockindex)
608 {
609   CURLcode result = CURLE_OK;
610   struct Curl_easy *data = conn->data;
611   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
612 
613   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
614 
615   if(SSL_SET_OPTION(primary.sessionid)) {
616     bool incache;
617     SSL_SESSION *our_ssl_sessionid;
618     void *old_ssl_sessionid = NULL;
619 
620     our_ssl_sessionid = SSL_get_session(BACKEND->handle);
621 
622     Curl_ssl_sessionid_lock(conn);
623     incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
624                                       sockindex));
625     if(incache) {
626       if(old_ssl_sessionid != our_ssl_sessionid) {
627         infof(data, "old SSL session ID is stale, removing\n");
628         Curl_ssl_delsessionid(conn, old_ssl_sessionid);
629         incache = FALSE;
630       }
631     }
632 
633     if(!incache) {
634       result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
635                                      0 /* unknown size */, sockindex);
636       if(result) {
637         Curl_ssl_sessionid_unlock(conn);
638         failf(data, "failed to store ssl session");
639         return result;
640       }
641     }
642     Curl_ssl_sessionid_unlock(conn);
643   }
644 
645   connssl->connecting_state = ssl_connect_done;
646 
647   return result;
648 }
649 
650 
wolfssl_send(struct connectdata * conn,int sockindex,const void * mem,size_t len,CURLcode * curlcode)651 static ssize_t wolfssl_send(struct connectdata *conn,
652                            int sockindex,
653                            const void *mem,
654                            size_t len,
655                            CURLcode *curlcode)
656 {
657   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
658   char error_buffer[WOLFSSL_MAX_ERROR_SZ];
659   int  memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
660   int  rc     = SSL_write(BACKEND->handle, mem, memlen);
661 
662   if(rc < 0) {
663     int err = SSL_get_error(BACKEND->handle, rc);
664 
665     switch(err) {
666     case SSL_ERROR_WANT_READ:
667     case SSL_ERROR_WANT_WRITE:
668       /* there's data pending, re-invoke SSL_write() */
669       *curlcode = CURLE_AGAIN;
670       return -1;
671     default:
672       failf(conn->data, "SSL write: %s, errno %d",
673             ERR_error_string(err, error_buffer),
674             SOCKERRNO);
675       *curlcode = CURLE_SEND_ERROR;
676       return -1;
677     }
678   }
679   return rc;
680 }
681 
Curl_wolfssl_close(struct connectdata * conn,int sockindex)682 static void Curl_wolfssl_close(struct connectdata *conn, int sockindex)
683 {
684   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
685 
686   if(BACKEND->handle) {
687     (void)SSL_shutdown(BACKEND->handle);
688     SSL_free(BACKEND->handle);
689     BACKEND->handle = NULL;
690   }
691   if(BACKEND->ctx) {
692     SSL_CTX_free(BACKEND->ctx);
693     BACKEND->ctx = NULL;
694   }
695 }
696 
wolfssl_recv(struct connectdata * conn,int num,char * buf,size_t buffersize,CURLcode * curlcode)697 static ssize_t wolfssl_recv(struct connectdata *conn,
698                            int num,
699                            char *buf,
700                            size_t buffersize,
701                            CURLcode *curlcode)
702 {
703   struct ssl_connect_data *connssl = &conn->ssl[num];
704   char error_buffer[WOLFSSL_MAX_ERROR_SZ];
705   int  buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
706   int  nread    = SSL_read(BACKEND->handle, buf, buffsize);
707 
708   if(nread < 0) {
709     int err = SSL_get_error(BACKEND->handle, nread);
710 
711     switch(err) {
712     case SSL_ERROR_ZERO_RETURN: /* no more data */
713       break;
714     case SSL_ERROR_WANT_READ:
715     case SSL_ERROR_WANT_WRITE:
716       /* there's data pending, re-invoke SSL_read() */
717       *curlcode = CURLE_AGAIN;
718       return -1;
719     default:
720       failf(conn->data, "SSL read: %s, errno %d",
721             ERR_error_string(err, error_buffer),
722             SOCKERRNO);
723       *curlcode = CURLE_RECV_ERROR;
724       return -1;
725     }
726   }
727   return nread;
728 }
729 
730 
Curl_wolfssl_session_free(void * ptr)731 static void Curl_wolfssl_session_free(void *ptr)
732 {
733   (void)ptr;
734   /* wolfSSL reuses sessions on own, no free */
735 }
736 
737 
Curl_wolfssl_version(char * buffer,size_t size)738 static size_t Curl_wolfssl_version(char *buffer, size_t size)
739 {
740 #if LIBWOLFSSL_VERSION_HEX >= 0x03006000
741   return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
742 #elif defined(WOLFSSL_VERSION)
743   return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
744 #endif
745 }
746 
747 
Curl_wolfssl_init(void)748 static int Curl_wolfssl_init(void)
749 {
750   return (wolfSSL_Init() == SSL_SUCCESS);
751 }
752 
753 
Curl_wolfssl_cleanup(void)754 static void Curl_wolfssl_cleanup(void)
755 {
756   wolfSSL_Cleanup();
757 }
758 
759 
Curl_wolfssl_data_pending(const struct connectdata * conn,int connindex)760 static bool Curl_wolfssl_data_pending(const struct connectdata* conn,
761                                      int connindex)
762 {
763   const struct ssl_connect_data *connssl = &conn->ssl[connindex];
764   if(BACKEND->handle)   /* SSL is in use */
765     return (0 != SSL_pending(BACKEND->handle)) ? TRUE : FALSE;
766   else
767     return FALSE;
768 }
769 
770 
771 /*
772  * This function is called to shut down the SSL layer but keep the
773  * socket open (CCC - Clear Command Channel)
774  */
Curl_wolfssl_shutdown(struct connectdata * conn,int sockindex)775 static int Curl_wolfssl_shutdown(struct connectdata *conn, int sockindex)
776 {
777   int retval = 0;
778   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
779 
780   if(BACKEND->handle) {
781     SSL_free(BACKEND->handle);
782     BACKEND->handle = NULL;
783   }
784   return retval;
785 }
786 
787 
788 static CURLcode
wolfssl_connect_common(struct connectdata * conn,int sockindex,bool nonblocking,bool * done)789 wolfssl_connect_common(struct connectdata *conn,
790                       int sockindex,
791                       bool nonblocking,
792                       bool *done)
793 {
794   CURLcode result;
795   struct Curl_easy *data = conn->data;
796   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
797   curl_socket_t sockfd = conn->sock[sockindex];
798   time_t timeout_ms;
799   int what;
800 
801   /* check if the connection has already been established */
802   if(ssl_connection_complete == connssl->state) {
803     *done = TRUE;
804     return CURLE_OK;
805   }
806 
807   if(ssl_connect_1 == connssl->connecting_state) {
808     /* Find out how much more time we're allowed */
809     timeout_ms = Curl_timeleft(data, NULL, TRUE);
810 
811     if(timeout_ms < 0) {
812       /* no need to continue if time already is up */
813       failf(data, "SSL connection timeout");
814       return CURLE_OPERATION_TIMEDOUT;
815     }
816 
817     result = wolfssl_connect_step1(conn, sockindex);
818     if(result)
819       return result;
820   }
821 
822   while(ssl_connect_2 == connssl->connecting_state ||
823         ssl_connect_2_reading == connssl->connecting_state ||
824         ssl_connect_2_writing == connssl->connecting_state) {
825 
826     /* check allowed time left */
827     timeout_ms = Curl_timeleft(data, NULL, TRUE);
828 
829     if(timeout_ms < 0) {
830       /* no need to continue if time already is up */
831       failf(data, "SSL connection timeout");
832       return CURLE_OPERATION_TIMEDOUT;
833     }
834 
835     /* if ssl is expecting something, check if it's available. */
836     if(connssl->connecting_state == ssl_connect_2_reading
837        || connssl->connecting_state == ssl_connect_2_writing) {
838 
839       curl_socket_t writefd = ssl_connect_2_writing ==
840         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
841       curl_socket_t readfd = ssl_connect_2_reading ==
842         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
843 
844       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
845                                nonblocking?0:timeout_ms);
846       if(what < 0) {
847         /* fatal error */
848         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
849         return CURLE_SSL_CONNECT_ERROR;
850       }
851       else if(0 == what) {
852         if(nonblocking) {
853           *done = FALSE;
854           return CURLE_OK;
855         }
856         else {
857           /* timeout */
858           failf(data, "SSL connection timeout");
859           return CURLE_OPERATION_TIMEDOUT;
860         }
861       }
862       /* socket is readable or writable */
863     }
864 
865     /* Run transaction, and return to the caller if it failed or if
866      * this connection is part of a multi handle and this loop would
867      * execute again. This permits the owner of a multi handle to
868      * abort a connection attempt before step2 has completed while
869      * ensuring that a client using select() or epoll() will always
870      * have a valid fdset to wait on.
871      */
872     result = wolfssl_connect_step2(conn, sockindex);
873     if(result || (nonblocking &&
874                   (ssl_connect_2 == connssl->connecting_state ||
875                    ssl_connect_2_reading == connssl->connecting_state ||
876                    ssl_connect_2_writing == connssl->connecting_state)))
877       return result;
878   } /* repeat step2 until all transactions are done. */
879 
880   if(ssl_connect_3 == connssl->connecting_state) {
881     result = wolfssl_connect_step3(conn, sockindex);
882     if(result)
883       return result;
884   }
885 
886   if(ssl_connect_done == connssl->connecting_state) {
887     connssl->state = ssl_connection_complete;
888     conn->recv[sockindex] = wolfssl_recv;
889     conn->send[sockindex] = wolfssl_send;
890     *done = TRUE;
891   }
892   else
893     *done = FALSE;
894 
895   /* Reset our connect state machine */
896   connssl->connecting_state = ssl_connect_1;
897 
898   return CURLE_OK;
899 }
900 
901 
Curl_wolfssl_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)902 static CURLcode Curl_wolfssl_connect_nonblocking(struct connectdata *conn,
903                                                 int sockindex, bool *done)
904 {
905   return wolfssl_connect_common(conn, sockindex, TRUE, done);
906 }
907 
908 
Curl_wolfssl_connect(struct connectdata * conn,int sockindex)909 static CURLcode Curl_wolfssl_connect(struct connectdata *conn, int sockindex)
910 {
911   CURLcode result;
912   bool done = FALSE;
913 
914   result = wolfssl_connect_common(conn, sockindex, FALSE, &done);
915   if(result)
916     return result;
917 
918   DEBUGASSERT(done);
919 
920   return CURLE_OK;
921 }
922 
Curl_wolfssl_random(struct Curl_easy * data,unsigned char * entropy,size_t length)923 static CURLcode Curl_wolfssl_random(struct Curl_easy *data,
924                                    unsigned char *entropy, size_t length)
925 {
926   RNG rng;
927   (void)data;
928   if(wc_InitRng(&rng))
929     return CURLE_FAILED_INIT;
930   if(length > UINT_MAX)
931     return CURLE_FAILED_INIT;
932   if(wc_RNG_GenerateBlock(&rng, entropy, (unsigned)length))
933     return CURLE_FAILED_INIT;
934   if(wc_FreeRng(&rng))
935     return CURLE_FAILED_INIT;
936   return CURLE_OK;
937 }
938 
Curl_wolfssl_sha256sum(const unsigned char * tmp,size_t tmplen,unsigned char * sha256sum,size_t unused)939 static CURLcode Curl_wolfssl_sha256sum(const unsigned char *tmp, /* input */
940                                   size_t tmplen,
941                                   unsigned char *sha256sum /* output */,
942                                   size_t unused)
943 {
944   Sha256 SHA256pw;
945   (void)unused;
946   wc_InitSha256(&SHA256pw);
947   wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen);
948   wc_Sha256Final(&SHA256pw, sha256sum);
949   return CURLE_OK;
950 }
951 
Curl_wolfssl_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)952 static void *Curl_wolfssl_get_internals(struct ssl_connect_data *connssl,
953                                        CURLINFO info UNUSED_PARAM)
954 {
955   (void)info;
956   return BACKEND->handle;
957 }
958 
959 const struct Curl_ssl Curl_ssl_wolfssl = {
960   { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
961 
962 #ifdef KEEP_PEER_CERT
963   SSLSUPP_PINNEDPUBKEY |
964 #endif
965   SSLSUPP_SSL_CTX,
966 
967   sizeof(struct ssl_backend_data),
968 
969   Curl_wolfssl_init,                /* init */
970   Curl_wolfssl_cleanup,             /* cleanup */
971   Curl_wolfssl_version,             /* version */
972   Curl_none_check_cxn,             /* check_cxn */
973   Curl_wolfssl_shutdown,            /* shutdown */
974   Curl_wolfssl_data_pending,        /* data_pending */
975   Curl_wolfssl_random,              /* random */
976   Curl_none_cert_status_request,   /* cert_status_request */
977   Curl_wolfssl_connect,             /* connect */
978   Curl_wolfssl_connect_nonblocking, /* connect_nonblocking */
979   Curl_wolfssl_get_internals,       /* get_internals */
980   Curl_wolfssl_close,               /* close_one */
981   Curl_none_close_all,             /* close_all */
982   Curl_wolfssl_session_free,        /* session_free */
983   Curl_none_set_engine,            /* set_engine */
984   Curl_none_set_engine_default,    /* set_engine_default */
985   Curl_none_engines_list,          /* engines_list */
986   Curl_none_false_start,           /* false_start */
987   Curl_none_md5sum,                /* md5sum */
988   Curl_wolfssl_sha256sum            /* sha256sum */
989 };
990 
991 #endif
992