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
94struct ssl_backend_data {
95 SSL_CTX* ctx;
96 SSL* handle;
97};
98
99#define BACKEND connssl->backend
100
101static Curl_recv wolfssl_recv;
102static Curl_send wolfssl_send;
103
104
105static 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 */
120static CURLcode
121wolfssl_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
422static CURLcode
423wolfssl_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
605static CURLcode
606wolfssl_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
651static 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
682static 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
697static 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
731static void Curl_wolfssl_session_free(void *ptr)
732{
733 (void)ptr;
734 /* wolfSSL reuses sessions on own, no free */
735}
736
737
738static 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
748static int Curl_wolfssl_init(void)
749{
750 return (wolfSSL_Init() == SSL_SUCCESS);
751}
752
753
754static void Curl_wolfssl_cleanup(void)
755{
756 wolfSSL_Cleanup();
757}
758
759
760static 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 */
775static 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
788static CURLcode
789wolfssl_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
902static 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
909static 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
923static 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
939static 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
952static 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
959const 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