1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
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.
29 #include "curl_setup.h"
33 #define WOLFSSL_OPTIONS_IGNORE_SYS
34 #include <wolfssl/version.h>
35 #include <wolfssl/options.h>
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. */
43 /* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
45 #ifdef HAVE_WOLFSSL_USEALPN
54 #include "inet_pton.h"
57 #include "parsedate.h"
58 #include "connect.h" /* for the connect timeout */
62 #include "curl_printf.h"
65 #include <wolfssl/openssl/ssl.h>
66 #include <wolfssl/ssl.h>
67 #include <wolfssl/error-ssl.h>
70 /* The last #include files should be: */
71 #include "curl_memory.h"
74 /* KEEP_PEER_CERT is a product of the presence of build time symbol
75 OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
76 in wolfSSL's settings.h, and the latter two are build time symbols in
78 #ifndef KEEP_PEER_CERT
79 #if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
80 (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
81 #define KEEP_PEER_CERT
85 struct ssl_backend_data {
90 static Curl_recv wolfssl_recv;
91 static Curl_send wolfssl_send;
96 * The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in
97 * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
98 * option is not set, then TLS 1.3 will not be logged.
99 * For TLS 1.2 and before, we use wolfSSL_get_keys().
100 * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
101 * (--enable-opensslextra or --enable-all).
103 #if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
105 wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
106 int secretSz, void *ctx)
109 unsigned char client_random[SSL3_RANDOM_SIZE];
112 if(!ssl || !Curl_tls_keylog_enabled()) {
117 case CLIENT_EARLY_TRAFFIC_SECRET:
118 label = "CLIENT_EARLY_TRAFFIC_SECRET";
120 case CLIENT_HANDSHAKE_TRAFFIC_SECRET:
121 label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET";
123 case SERVER_HANDSHAKE_TRAFFIC_SECRET:
124 label = "SERVER_HANDSHAKE_TRAFFIC_SECRET";
126 case CLIENT_TRAFFIC_SECRET:
127 label = "CLIENT_TRAFFIC_SECRET_0";
129 case SERVER_TRAFFIC_SECRET:
130 label = "SERVER_TRAFFIC_SECRET_0";
132 case EARLY_EXPORTER_SECRET:
133 label = "EARLY_EXPORTER_SECRET";
135 case EXPORTER_SECRET:
136 label = "EXPORTER_SECRET";
142 if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) {
143 /* Should never happen as wolfSSL_KeepArrays() was called before. */
147 Curl_tls_keylog_write(label, client_random, secret, secretSz);
150 #endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */
153 wolfssl_log_tls12_secret(SSL *ssl)
155 unsigned char *ms, *sr, *cr;
156 unsigned int msLen, srLen, crLen, i, x = 0;
158 #if LIBWOLFSSL_VERSION_HEX >= 0x0300d000 /* >= 3.13.0 */
159 /* wolfSSL_GetVersion is available since 3.13, we use it instead of
160 * SSL_version since the latter relies on OPENSSL_ALL (--enable-opensslall or
161 * --enable-all). Failing to perform this check could result in an unusable
162 * key log line when TLS 1.3 is actually negotiated. */
163 switch(wolfSSL_GetVersion(ssl)) {
166 case WOLFSSL_TLSV1_1:
167 case WOLFSSL_TLSV1_2:
170 /* TLS 1.3 does not use this mechanism, the "master secret" returned below
171 * is not directly usable. */
176 if(SSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) != SSL_SUCCESS) {
180 /* Check for a missing master secret and skip logging. That can happen if
181 * curl rejects the server certificate and aborts the handshake.
183 for(i = 0; i < msLen; i++) {
190 Curl_tls_keylog_write("CLIENT_RANDOM", cr, ms, msLen);
192 #endif /* OPENSSL_EXTRA */
194 static int do_file_type(const char *type)
196 if(!type || !type[0])
197 return SSL_FILETYPE_PEM;
198 if(strcasecompare(type, "PEM"))
199 return SSL_FILETYPE_PEM;
200 if(strcasecompare(type, "DER"))
201 return SSL_FILETYPE_ASN1;
206 struct group_name_map {
211 static const struct group_name_map gnm[] = {
212 { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" },
213 { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" },
214 { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" },
215 { WOLFSSL_NTRU_HPS_LEVEL1, "NTRU_HPS_LEVEL1" },
216 { WOLFSSL_NTRU_HPS_LEVEL3, "NTRU_HPS_LEVEL3" },
217 { WOLFSSL_NTRU_HPS_LEVEL5, "NTRU_HPS_LEVEL5" },
218 { WOLFSSL_NTRU_HRSS_LEVEL3, "NTRU_HRSS_LEVEL3" },
219 { WOLFSSL_SABER_LEVEL1, "SABER_LEVEL1" },
220 { WOLFSSL_SABER_LEVEL3, "SABER_LEVEL3" },
221 { WOLFSSL_SABER_LEVEL5, "SABER_LEVEL5" },
222 { WOLFSSL_KYBER_90S_LEVEL1, "KYBER_90S_LEVEL1" },
223 { WOLFSSL_KYBER_90S_LEVEL3, "KYBER_90S_LEVEL3" },
224 { WOLFSSL_KYBER_90S_LEVEL5, "KYBER_90S_LEVEL5" },
225 { WOLFSSL_P256_NTRU_HPS_LEVEL1, "P256_NTRU_HPS_LEVEL1" },
226 { WOLFSSL_P384_NTRU_HPS_LEVEL3, "P384_NTRU_HPS_LEVEL3" },
227 { WOLFSSL_P521_NTRU_HPS_LEVEL5, "P521_NTRU_HPS_LEVEL5" },
228 { WOLFSSL_P384_NTRU_HRSS_LEVEL3, "P384_NTRU_HRSS_LEVEL3" },
229 { WOLFSSL_P256_SABER_LEVEL1, "P256_SABER_LEVEL1" },
230 { WOLFSSL_P384_SABER_LEVEL3, "P384_SABER_LEVEL3" },
231 { WOLFSSL_P521_SABER_LEVEL5, "P521_SABER_LEVEL5" },
232 { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" },
233 { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" },
234 { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" },
235 { WOLFSSL_P256_KYBER_90S_LEVEL1, "P256_KYBER_90S_LEVEL1" },
236 { WOLFSSL_P384_KYBER_90S_LEVEL3, "P384_KYBER_90S_LEVEL3" },
237 { WOLFSSL_P521_KYBER_90S_LEVEL5, "P521_KYBER_90S_LEVEL5" },
243 * This function loads all the client/CA certificates and CRLs. Setup the TLS
244 * layer and do all necessary magic.
247 wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
250 char *ciphers, *curves;
251 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
252 struct ssl_backend_data *backend = connssl->backend;
253 SSL_METHOD* req_method = NULL;
254 curl_socket_t sockfd = conn->sock[sockindex];
261 #define use_sni(x) sni = (x)
263 #define use_sni(x) Curl_nop_stmt
266 DEBUGASSERT(backend);
268 if(connssl->state == ssl_connection_complete)
271 if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
272 failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
273 return CURLE_SSL_CONNECT_ERROR;
276 /* check to see if we've been told to use an explicit SSL/TLS version */
277 switch(SSL_CONN_CONFIG(version)) {
278 case CURL_SSLVERSION_DEFAULT:
279 case CURL_SSLVERSION_TLSv1:
280 #if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
281 /* minimum protocol version is set later after the CTX object is created */
282 req_method = SSLv23_client_method();
284 infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
285 "TLS 1.0 is used exclusively");
286 req_method = TLSv1_client_method();
290 case CURL_SSLVERSION_TLSv1_0:
291 #if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS)
292 req_method = TLSv1_client_method();
295 failf(data, "wolfSSL does not support TLS 1.0");
296 return CURLE_NOT_BUILT_IN;
299 case CURL_SSLVERSION_TLSv1_1:
301 req_method = TLSv1_1_client_method();
304 failf(data, "wolfSSL does not support TLS 1.1");
305 return CURLE_NOT_BUILT_IN;
308 case CURL_SSLVERSION_TLSv1_2:
309 req_method = TLSv1_2_client_method();
312 case CURL_SSLVERSION_TLSv1_3:
314 req_method = wolfTLSv1_3_client_method();
318 failf(data, "wolfSSL: TLS 1.3 is not yet supported");
319 return CURLE_SSL_CONNECT_ERROR;
322 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
323 return CURLE_SSL_CONNECT_ERROR;
327 failf(data, "SSL: couldn't create a method");
328 return CURLE_OUT_OF_MEMORY;
332 SSL_CTX_free(backend->ctx);
333 backend->ctx = SSL_CTX_new(req_method);
336 failf(data, "SSL: couldn't create a context");
337 return CURLE_OUT_OF_MEMORY;
340 switch(SSL_CONN_CONFIG(version)) {
341 case CURL_SSLVERSION_DEFAULT:
342 case CURL_SSLVERSION_TLSv1:
343 #if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
344 /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is
345 * whatever minimum version of TLS was built in and at least TLS 1.0. For
346 * later library versions that could change (eg TLS 1.0 built in but
347 * defaults to TLS 1.1) so we have this short circuit evaluation to find
348 * the minimum supported TLS version.
350 if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) &&
351 (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) &&
352 (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1)
354 && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1)
357 failf(data, "SSL: couldn't set the minimum protocol version");
358 return CURLE_SSL_CONNECT_ERROR;
364 ciphers = SSL_CONN_CONFIG(cipher_list);
366 if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
367 failf(data, "failed setting cipher list: %s", ciphers);
368 return CURLE_SSL_CIPHER;
370 infof(data, "Cipher selection: %s", ciphers);
373 curves = SSL_CONN_CONFIG(curves);
377 for(idx = 0; gnm[idx].name != NULL; idx++) {
378 if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) {
379 oqsAlg = gnm[idx].group;
387 if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
388 failf(data, "failed setting curves list: '%s'", curves);
389 return CURLE_SSL_CIPHER;
393 #ifndef NO_FILESYSTEM
394 /* load trusted cacert */
395 if(SSL_CONN_CONFIG(CAfile)) {
396 if(1 != SSL_CTX_load_verify_locations(backend->ctx,
397 SSL_CONN_CONFIG(CAfile),
398 SSL_CONN_CONFIG(CApath))) {
399 if(SSL_CONN_CONFIG(verifypeer)) {
400 /* Fail if we insist on successfully verifying the server. */
401 failf(data, "error setting certificate verify locations:"
402 " CAfile: %s CApath: %s",
403 SSL_CONN_CONFIG(CAfile)?
404 SSL_CONN_CONFIG(CAfile): "none",
405 SSL_CONN_CONFIG(CApath)?
406 SSL_CONN_CONFIG(CApath) : "none");
407 return CURLE_SSL_CACERT_BADFILE;
410 /* Just continue with a warning if no strict certificate
411 verification is required. */
412 infof(data, "error setting certificate verify locations,"
413 " continuing anyway:");
417 /* Everything is fine. */
418 infof(data, "successfully set certificate verify locations:");
420 infof(data, " CAfile: %s",
421 SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none");
422 infof(data, " CApath: %s",
423 SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none");
426 /* Load the client certificate, and private key */
427 if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) {
428 int file_type = do_file_type(SSL_SET_OPTION(cert_type));
430 if(SSL_CTX_use_certificate_file(backend->ctx,
431 SSL_SET_OPTION(primary.clientcert),
433 failf(data, "unable to use client certificate (no key or wrong pass"
435 return CURLE_SSL_CONNECT_ERROR;
438 file_type = do_file_type(SSL_SET_OPTION(key_type));
439 if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key),
441 failf(data, "unable to set private key");
442 return CURLE_SSL_CONNECT_ERROR;
445 #endif /* !NO_FILESYSTEM */
447 /* SSL always tries to verify the peer, this only says whether it should
448 * fail to connect if the verification fails, or if it should continue
449 * anyway. In the latter case the result of the verification is checked with
450 * SSL_get_verify_result() below. */
451 SSL_CTX_set_verify(backend->ctx,
452 SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
458 struct in_addr addr4;
460 struct in6_addr addr6;
462 const char * const hostname = SSL_HOST_NAME();
463 size_t hostname_len = strlen(hostname);
464 if((hostname_len < USHRT_MAX) &&
465 !Curl_inet_pton(AF_INET, hostname, &addr4)
467 && !Curl_inet_pton(AF_INET6, hostname, &addr6)
471 char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
473 wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, snihost,
474 (unsigned short)snilen) != 1) {
475 failf(data, "Failed to set SNI");
476 return CURLE_SSL_CONNECT_ERROR;
482 /* give application a chance to interfere with SSL set up. */
483 if(data->set.ssl.fsslctx) {
484 CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx,
485 data->set.ssl.fsslctxp);
487 failf(data, "error signaled by ssl ctx callback");
492 else if(SSL_CONN_CONFIG(verifypeer)) {
493 failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
494 " with \"no filesystem\". Either disable peer verification"
495 " (insecure) or if you are building an application with libcurl you"
496 " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
497 return CURLE_SSL_CONNECT_ERROR;
501 /* Let's make an SSL structure */
503 SSL_free(backend->handle);
504 backend->handle = SSL_new(backend->ctx);
505 if(!backend->handle) {
506 failf(data, "SSL: couldn't create a context");
507 return CURLE_OUT_OF_MEMORY;
512 if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) {
513 failf(data, "unable to use oqs KEM");
519 if(conn->bits.tls_enable_alpn) {
523 /* wolfSSL's ALPN protocol name list format is a comma separated string of
524 protocols in descending order of preference, eg: "h2,http/1.1" */
527 if(data->state.httpwant >= CURL_HTTP_VERSION_2) {
528 strcpy(protocols + strlen(protocols), ALPN_H2 ",");
529 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2);
533 strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
534 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1);
536 if(wolfSSL_UseALPN(backend->handle, protocols,
537 (unsigned)strlen(protocols),
538 WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
539 failf(data, "SSL: failed setting ALPN protocols");
540 return CURLE_SSL_CONNECT_ERROR;
543 #endif /* HAVE_ALPN */
546 if(Curl_tls_keylog_enabled()) {
547 /* Ensure the Client Random is preserved. */
548 wolfSSL_KeepArrays(backend->handle);
549 #if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
550 wolfSSL_set_tls13_secret_cb(backend->handle,
551 wolfssl_tls13_secret_callback, NULL);
554 #endif /* OPENSSL_EXTRA */
556 #ifdef HAVE_SECURE_RENEGOTIATION
557 if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) {
558 failf(data, "SSL: failed setting secure renegotiation");
559 return CURLE_SSL_CONNECT_ERROR;
561 #endif /* HAVE_SECURE_RENEGOTIATION */
563 /* Check if there's a cached ID we can/should use here! */
564 if(SSL_SET_OPTION(primary.sessionid)) {
565 void *ssl_sessionid = NULL;
567 Curl_ssl_sessionid_lock(data);
568 if(!Curl_ssl_getsessionid(data, conn,
569 SSL_IS_PROXY() ? TRUE : FALSE,
570 &ssl_sessionid, NULL, sockindex)) {
571 /* we got a session id, use it! */
572 if(!SSL_set_session(backend->handle, ssl_sessionid)) {
573 Curl_ssl_delsessionid(data, ssl_sessionid);
574 infof(data, "Can't use session ID, going on without");
577 infof(data, "SSL re-using session ID");
579 Curl_ssl_sessionid_unlock(data);
582 /* pass the raw socket into the SSL layer */
583 if(!SSL_set_fd(backend->handle, (int)sockfd)) {
584 failf(data, "SSL: SSL_set_fd failed");
585 return CURLE_SSL_CONNECT_ERROR;
588 connssl->connecting_state = ssl_connect_2;
594 wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
598 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
599 struct ssl_backend_data *backend = connssl->backend;
600 const char * const dispname = SSL_HOST_DISPNAME();
601 const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
603 DEBUGASSERT(backend);
607 conn->recv[sockindex] = wolfssl_recv;
608 conn->send[sockindex] = wolfssl_send;
610 /* Enable RFC2818 checks */
611 if(SSL_CONN_CONFIG(verifyhost)) {
612 char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
614 (wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE))
615 return CURLE_SSL_CONNECT_ERROR;
618 ret = SSL_connect(backend->handle);
621 if(Curl_tls_keylog_enabled()) {
622 /* If key logging is enabled, wait for the handshake to complete and then
623 * proceed with logging secrets (for TLS 1.2 or older).
625 * During the handshake (ret==-1), wolfSSL_want_read() is true as it waits
626 * for the server response. At that point the master secret is not yet
627 * available, so we must not try to read it.
628 * To log the secret on completion with a handshake failure, detect
629 * completion via the observation that there is nothing to read or write.
630 * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever
631 * changes, the worst case is that no key is logged on error.
633 if(ret == SSL_SUCCESS ||
634 (!wolfSSL_want_read(backend->handle) &&
635 !wolfSSL_want_write(backend->handle))) {
636 wolfssl_log_tls12_secret(backend->handle);
637 /* Client Random and master secrets are no longer needed, erase these.
638 * Ignored while the handshake is still in progress. */
639 wolfSSL_FreeArrays(backend->handle);
642 #endif /* OPENSSL_EXTRA */
645 char error_buffer[WOLFSSL_MAX_ERROR_SZ];
646 int detail = SSL_get_error(backend->handle, ret);
648 if(SSL_ERROR_WANT_READ == detail) {
649 connssl->connecting_state = ssl_connect_2_reading;
652 else if(SSL_ERROR_WANT_WRITE == detail) {
653 connssl->connecting_state = ssl_connect_2_writing;
656 /* There is no easy way to override only the CN matching.
657 * This will enable the override of both mismatching SubjectAltNames
658 * as also mismatching CN fields */
659 else if(DOMAIN_NAME_MISMATCH == detail) {
661 failf(data, " subject alt name(s) or common name do not match \"%s\"",
663 return CURLE_PEER_FAILED_VERIFICATION;
665 /* When the wolfssl_check_domain_name() is used and you desire to
666 * continue on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost
667 * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
668 * error. The only way to do this is currently to switch the
669 * Wolfssl_check_domain_name() in and out based on the
670 * 'conn->ssl_config.verifyhost' value. */
671 if(SSL_CONN_CONFIG(verifyhost)) {
673 " subject alt name(s) or common name do not match \"%s\"\n",
675 return CURLE_PEER_FAILED_VERIFICATION;
679 " subject alt name(s) and/or common name do not match \"%s\"",
685 #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
686 else if(ASN_NO_SIGNER_E == detail) {
687 if(SSL_CONN_CONFIG(verifypeer)) {
688 failf(data, " CA signer not available for verification");
689 return CURLE_SSL_CACERT_BADFILE;
692 /* Just continue with a warning if no strict certificate
693 verification is required. */
694 infof(data, "CA signer not available for verification, "
695 "continuing anyway");
700 failf(data, "SSL_connect failed with error %d: %s", detail,
701 ERR_error_string(detail, error_buffer));
702 return CURLE_SSL_CONNECT_ERROR;
707 #ifdef KEEP_PEER_CERT
709 const char *x509_der;
711 struct Curl_X509certificate x509_parsed;
712 struct Curl_asn1Element *pubkey;
715 x509 = SSL_get_peer_certificate(backend->handle);
717 failf(data, "SSL: failed retrieving server certificate");
718 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
721 x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
723 failf(data, "SSL: failed retrieving ASN.1 server certificate");
724 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
727 memset(&x509_parsed, 0, sizeof(x509_parsed));
728 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
729 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
731 pubkey = &x509_parsed.subjectPublicKeyInfo;
732 if(!pubkey->header || pubkey->end <= pubkey->header) {
733 failf(data, "SSL: failed retrieving public key from server certificate");
734 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
737 result = Curl_pin_peer_pubkey(data,
739 (const unsigned char *)pubkey->header,
740 (size_t)(pubkey->end - pubkey->header));
742 failf(data, "SSL: public key does not match pinned public key");
746 failf(data, "Library lacks pinning support built-in");
747 return CURLE_NOT_BUILT_IN;
752 if(conn->bits.tls_enable_alpn) {
754 char *protocol = NULL;
755 unsigned short protocol_len = 0;
757 rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
759 if(rc == SSL_SUCCESS) {
760 infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, protocol_len, protocol);
762 if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
763 !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
764 conn->negnpn = CURL_HTTP_VERSION_1_1;
766 else if(data->state.httpwant >= CURL_HTTP_VERSION_2 &&
767 protocol_len == ALPN_H2_LENGTH &&
768 !memcmp(protocol, ALPN_H2, ALPN_H2_LENGTH))
769 conn->negnpn = CURL_HTTP_VERSION_2;
772 infof(data, "ALPN, unrecognized protocol %.*s", protocol_len,
774 Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
775 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
777 else if(rc == SSL_ALPN_NOT_FOUND)
778 infof(data, VTLS_INFOF_NO_ALPN);
780 failf(data, "ALPN, failure getting protocol, error %d", rc);
781 return CURLE_SSL_CONNECT_ERROR;
784 #endif /* HAVE_ALPN */
786 connssl->connecting_state = ssl_connect_3;
787 #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
788 infof(data, "SSL connection using %s / %s",
789 wolfSSL_get_version(backend->handle),
790 wolfSSL_get_cipher_name(backend->handle));
792 infof(data, "SSL connected");
800 wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
803 CURLcode result = CURLE_OK;
804 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
805 struct ssl_backend_data *backend = connssl->backend;
807 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
808 DEBUGASSERT(backend);
810 if(SSL_SET_OPTION(primary.sessionid)) {
812 void *old_ssl_sessionid = NULL;
813 SSL_SESSION *our_ssl_sessionid = SSL_get_session(backend->handle);
814 bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
816 if(our_ssl_sessionid) {
817 Curl_ssl_sessionid_lock(data);
818 incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
819 &old_ssl_sessionid, NULL, sockindex));
821 if(old_ssl_sessionid != our_ssl_sessionid) {
822 infof(data, "old SSL session ID is stale, removing");
823 Curl_ssl_delsessionid(data, old_ssl_sessionid);
829 result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
832 Curl_ssl_sessionid_unlock(data);
833 failf(data, "failed to store ssl session");
837 Curl_ssl_sessionid_unlock(data);
841 connssl->connecting_state = ssl_connect_done;
847 static ssize_t wolfssl_send(struct Curl_easy *data,
853 struct connectdata *conn = data->conn;
854 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
855 struct ssl_backend_data *backend = connssl->backend;
856 char error_buffer[WOLFSSL_MAX_ERROR_SZ];
857 int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
860 DEBUGASSERT(backend);
864 rc = SSL_write(backend->handle, mem, memlen);
867 int err = SSL_get_error(backend->handle, rc);
870 case SSL_ERROR_WANT_READ:
871 case SSL_ERROR_WANT_WRITE:
872 /* there's data pending, re-invoke SSL_write() */
873 *curlcode = CURLE_AGAIN;
876 failf(data, "SSL write: %s, errno %d",
877 ERR_error_string(err, error_buffer),
879 *curlcode = CURLE_SEND_ERROR;
886 static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
889 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
890 struct ssl_backend_data *backend = connssl->backend;
894 DEBUGASSERT(backend);
896 if(backend->handle) {
898 /* Maybe the server has already sent a close notify alert.
899 Read it to avoid an RST on the TCP connection. */
900 (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
901 (void)SSL_shutdown(backend->handle);
902 SSL_free(backend->handle);
903 backend->handle = NULL;
906 SSL_CTX_free(backend->ctx);
911 static ssize_t wolfssl_recv(struct Curl_easy *data,
917 struct connectdata *conn = data->conn;
918 struct ssl_connect_data *connssl = &conn->ssl[num];
919 struct ssl_backend_data *backend = connssl->backend;
920 char error_buffer[WOLFSSL_MAX_ERROR_SZ];
921 int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
924 DEBUGASSERT(backend);
928 nread = SSL_read(backend->handle, buf, buffsize);
931 int err = SSL_get_error(backend->handle, nread);
934 case SSL_ERROR_ZERO_RETURN: /* no more data */
938 case SSL_ERROR_WANT_READ:
940 case SSL_ERROR_WANT_WRITE:
941 /* there's data pending, re-invoke SSL_read() */
942 *curlcode = CURLE_AGAIN;
945 failf(data, "SSL read: %s, errno %d",
946 ERR_error_string(err, error_buffer), SOCKERRNO);
947 *curlcode = CURLE_RECV_ERROR;
955 static void wolfssl_session_free(void *ptr)
958 /* wolfSSL reuses sessions on own, no free */
962 static size_t wolfssl_version(char *buffer, size_t size)
964 #if LIBWOLFSSL_VERSION_HEX >= 0x03006000
965 return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
966 #elif defined(WOLFSSL_VERSION)
967 return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
972 static int wolfssl_init(void)
975 Curl_tls_keylog_open();
977 return (wolfSSL_Init() == SSL_SUCCESS);
981 static void wolfssl_cleanup(void)
985 Curl_tls_keylog_close();
990 static bool wolfssl_data_pending(const struct connectdata *conn,
993 const struct ssl_connect_data *connssl = &conn->ssl[connindex];
994 struct ssl_backend_data *backend = connssl->backend;
995 DEBUGASSERT(backend);
996 if(backend->handle) /* SSL is in use */
997 return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE;
1004 * This function is called to shut down the SSL layer but keep the
1005 * socket open (CCC - Clear Command Channel)
1007 static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
1011 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1012 struct ssl_backend_data *backend = connssl->backend;
1016 DEBUGASSERT(backend);
1018 if(backend->handle) {
1020 SSL_free(backend->handle);
1021 backend->handle = NULL;
1028 wolfssl_connect_common(struct Curl_easy *data,
1029 struct connectdata *conn,
1035 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1036 curl_socket_t sockfd = conn->sock[sockindex];
1039 /* check if the connection has already been established */
1040 if(ssl_connection_complete == connssl->state) {
1045 if(ssl_connect_1 == connssl->connecting_state) {
1046 /* Find out how much more time we're allowed */
1047 const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
1049 if(timeout_ms < 0) {
1050 /* no need to continue if time already is up */
1051 failf(data, "SSL connection timeout");
1052 return CURLE_OPERATION_TIMEDOUT;
1055 result = wolfssl_connect_step1(data, conn, sockindex);
1060 while(ssl_connect_2 == connssl->connecting_state ||
1061 ssl_connect_2_reading == connssl->connecting_state ||
1062 ssl_connect_2_writing == connssl->connecting_state) {
1064 /* check allowed time left */
1065 const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
1067 if(timeout_ms < 0) {
1068 /* no need to continue if time already is up */
1069 failf(data, "SSL connection timeout");
1070 return CURLE_OPERATION_TIMEDOUT;
1073 /* if ssl is expecting something, check if it's available. */
1074 if(connssl->connecting_state == ssl_connect_2_reading
1075 || connssl->connecting_state == ssl_connect_2_writing) {
1077 curl_socket_t writefd = ssl_connect_2_writing ==
1078 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1079 curl_socket_t readfd = ssl_connect_2_reading ==
1080 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1082 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1083 nonblocking?0:timeout_ms);
1086 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1087 return CURLE_SSL_CONNECT_ERROR;
1089 else if(0 == what) {
1096 failf(data, "SSL connection timeout");
1097 return CURLE_OPERATION_TIMEDOUT;
1100 /* socket is readable or writable */
1103 /* Run transaction, and return to the caller if it failed or if
1104 * this connection is part of a multi handle and this loop would
1105 * execute again. This permits the owner of a multi handle to
1106 * abort a connection attempt before step2 has completed while
1107 * ensuring that a client using select() or epoll() will always
1108 * have a valid fdset to wait on.
1110 result = wolfssl_connect_step2(data, conn, sockindex);
1111 if(result || (nonblocking &&
1112 (ssl_connect_2 == connssl->connecting_state ||
1113 ssl_connect_2_reading == connssl->connecting_state ||
1114 ssl_connect_2_writing == connssl->connecting_state)))
1116 } /* repeat step2 until all transactions are done. */
1118 if(ssl_connect_3 == connssl->connecting_state) {
1119 result = wolfssl_connect_step3(data, conn, sockindex);
1124 if(ssl_connect_done == connssl->connecting_state) {
1125 connssl->state = ssl_connection_complete;
1126 conn->recv[sockindex] = wolfssl_recv;
1127 conn->send[sockindex] = wolfssl_send;
1133 /* Reset our connect state machine */
1134 connssl->connecting_state = ssl_connect_1;
1140 static CURLcode wolfssl_connect_nonblocking(struct Curl_easy *data,
1141 struct connectdata *conn,
1142 int sockindex, bool *done)
1144 return wolfssl_connect_common(data, conn, sockindex, TRUE, done);
1148 static CURLcode wolfssl_connect(struct Curl_easy *data,
1149 struct connectdata *conn, int sockindex)
1154 result = wolfssl_connect_common(data, conn, sockindex, FALSE, &done);
1163 static CURLcode wolfssl_random(struct Curl_easy *data,
1164 unsigned char *entropy, size_t length)
1168 if(wc_InitRng(&rng))
1169 return CURLE_FAILED_INIT;
1170 if(length > UINT_MAX)
1171 return CURLE_FAILED_INIT;
1172 if(wc_RNG_GenerateBlock(&rng, entropy, (unsigned)length))
1173 return CURLE_FAILED_INIT;
1174 if(wc_FreeRng(&rng))
1175 return CURLE_FAILED_INIT;
1179 static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
1181 unsigned char *sha256sum /* output */,
1186 wc_InitSha256(&SHA256pw);
1187 wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen);
1188 wc_Sha256Final(&SHA256pw, sha256sum);
1192 static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
1193 CURLINFO info UNUSED_PARAM)
1195 struct ssl_backend_data *backend = connssl->backend;
1197 DEBUGASSERT(backend);
1198 return backend->handle;
1201 const struct Curl_ssl Curl_ssl_wolfssl = {
1202 { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
1204 #ifdef KEEP_PEER_CERT
1205 SSLSUPP_PINNEDPUBKEY |
1209 sizeof(struct ssl_backend_data),
1211 wolfssl_init, /* init */
1212 wolfssl_cleanup, /* cleanup */
1213 wolfssl_version, /* version */
1214 Curl_none_check_cxn, /* check_cxn */
1215 wolfssl_shutdown, /* shutdown */
1216 wolfssl_data_pending, /* data_pending */
1217 wolfssl_random, /* random */
1218 Curl_none_cert_status_request, /* cert_status_request */
1219 wolfssl_connect, /* connect */
1220 wolfssl_connect_nonblocking, /* connect_nonblocking */
1221 Curl_ssl_getsock, /* getsock */
1222 wolfssl_get_internals, /* get_internals */
1223 wolfssl_close, /* close_one */
1224 Curl_none_close_all, /* close_all */
1225 wolfssl_session_free, /* session_free */
1226 Curl_none_set_engine, /* set_engine */
1227 Curl_none_set_engine_default, /* set_engine_default */
1228 Curl_none_engines_list, /* engines_list */
1229 Curl_none_false_start, /* false_start */
1230 wolfssl_sha256sum, /* sha256sum */
1231 NULL, /* associate_connection */
1232 NULL /* disassociate_connection */