1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
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 #include <limits.h>
51
52 #include "urldata.h"
53 #include "sendf.h"
54 #include "inet_pton.h"
55 #include "vtls.h"
56 #include "keylog.h"
57 #include "parsedate.h"
58 #include "connect.h" /* for the connect timeout */
59 #include "select.h"
60 #include "strcase.h"
61 #include "x509asn1.h"
62 #include "curl_printf.h"
63 #include "multiif.h"
64
65 #include <wolfssl/openssl/ssl.h>
66 #include <wolfssl/ssl.h>
67 #include <wolfssl/error-ssl.h>
68 #include "wolfssl.h"
69
70 /* The last #include files should be: */
71 #include "curl_memory.h"
72 #include "memdebug.h"
73
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
77 options.h. */
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
82 #endif
83 #endif
84
85 struct ssl_backend_data {
86 SSL_CTX* ctx;
87 SSL* handle;
88 };
89
90 static Curl_recv wolfssl_recv;
91 static Curl_send wolfssl_send;
92
93 #ifdef OPENSSL_EXTRA
94 /*
95 * Availability note:
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).
102 */
103 #if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
104 static int
wolfssl_tls13_secret_callback(SSL * ssl,int id,const unsigned char * secret,int secretSz,void * ctx)105 wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
106 int secretSz, void *ctx)
107 {
108 const char *label;
109 unsigned char client_random[SSL3_RANDOM_SIZE];
110 (void)ctx;
111
112 if(!ssl || !Curl_tls_keylog_enabled()) {
113 return 0;
114 }
115
116 switch(id) {
117 case CLIENT_EARLY_TRAFFIC_SECRET:
118 label = "CLIENT_EARLY_TRAFFIC_SECRET";
119 break;
120 case CLIENT_HANDSHAKE_TRAFFIC_SECRET:
121 label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET";
122 break;
123 case SERVER_HANDSHAKE_TRAFFIC_SECRET:
124 label = "SERVER_HANDSHAKE_TRAFFIC_SECRET";
125 break;
126 case CLIENT_TRAFFIC_SECRET:
127 label = "CLIENT_TRAFFIC_SECRET_0";
128 break;
129 case SERVER_TRAFFIC_SECRET:
130 label = "SERVER_TRAFFIC_SECRET_0";
131 break;
132 case EARLY_EXPORTER_SECRET:
133 label = "EARLY_EXPORTER_SECRET";
134 break;
135 case EXPORTER_SECRET:
136 label = "EXPORTER_SECRET";
137 break;
138 default:
139 return 0;
140 }
141
142 if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) {
143 /* Should never happen as wolfSSL_KeepArrays() was called before. */
144 return 0;
145 }
146
147 Curl_tls_keylog_write(label, client_random, secret, secretSz);
148 return 0;
149 }
150 #endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */
151
152 static void
wolfssl_log_tls12_secret(SSL * ssl)153 wolfssl_log_tls12_secret(SSL *ssl)
154 {
155 unsigned char *ms, *sr, *cr;
156 unsigned int msLen, srLen, crLen, i, x = 0;
157
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)) {
164 case WOLFSSL_SSLV3:
165 case WOLFSSL_TLSV1:
166 case WOLFSSL_TLSV1_1:
167 case WOLFSSL_TLSV1_2:
168 break;
169 default:
170 /* TLS 1.3 does not use this mechanism, the "master secret" returned below
171 * is not directly usable. */
172 return;
173 }
174 #endif
175
176 if(SSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) != SSL_SUCCESS) {
177 return;
178 }
179
180 /* Check for a missing master secret and skip logging. That can happen if
181 * curl rejects the server certificate and aborts the handshake.
182 */
183 for(i = 0; i < msLen; i++) {
184 x |= ms[i];
185 }
186 if(x == 0) {
187 return;
188 }
189
190 Curl_tls_keylog_write("CLIENT_RANDOM", cr, ms, msLen);
191 }
192 #endif /* OPENSSL_EXTRA */
193
do_file_type(const char * type)194 static int do_file_type(const char *type)
195 {
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;
202 return -1;
203 }
204
205 #ifdef HAVE_LIBOQS
206 struct group_name_map {
207 const word16 group;
208 const char *name;
209 };
210
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" },
238 { 0, NULL }
239 };
240 #endif
241
242 /*
243 * This function loads all the client/CA certificates and CRLs. Setup the TLS
244 * layer and do all necessary magic.
245 */
246 static CURLcode
wolfssl_connect_step1(struct Curl_easy * data,struct connectdata * conn,int sockindex)247 wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
248 int sockindex)
249 {
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];
255 #ifdef HAVE_LIBOQS
256 word16 oqsAlg = 0;
257 size_t idx = 0;
258 #endif
259 #ifdef HAVE_SNI
260 bool sni = FALSE;
261 #define use_sni(x) sni = (x)
262 #else
263 #define use_sni(x) Curl_nop_stmt
264 #endif
265
266 if(connssl->state == ssl_connection_complete)
267 return CURLE_OK;
268
269 if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
270 failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
271 return CURLE_SSL_CONNECT_ERROR;
272 }
273
274 /* check to see if we've been told to use an explicit SSL/TLS version */
275 switch(SSL_CONN_CONFIG(version)) {
276 case CURL_SSLVERSION_DEFAULT:
277 case CURL_SSLVERSION_TLSv1:
278 #if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
279 /* minimum protocol version is set later after the CTX object is created */
280 req_method = SSLv23_client_method();
281 #else
282 infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
283 "TLS 1.0 is used exclusively");
284 req_method = TLSv1_client_method();
285 #endif
286 use_sni(TRUE);
287 break;
288 case CURL_SSLVERSION_TLSv1_0:
289 #if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS)
290 req_method = TLSv1_client_method();
291 use_sni(TRUE);
292 #else
293 failf(data, "wolfSSL does not support TLS 1.0");
294 return CURLE_NOT_BUILT_IN;
295 #endif
296 break;
297 case CURL_SSLVERSION_TLSv1_1:
298 #ifndef NO_OLD_TLS
299 req_method = TLSv1_1_client_method();
300 use_sni(TRUE);
301 #else
302 failf(data, "wolfSSL does not support TLS 1.1");
303 return CURLE_NOT_BUILT_IN;
304 #endif
305 break;
306 case CURL_SSLVERSION_TLSv1_2:
307 req_method = TLSv1_2_client_method();
308 use_sni(TRUE);
309 break;
310 case CURL_SSLVERSION_TLSv1_3:
311 #ifdef WOLFSSL_TLS13
312 req_method = wolfTLSv1_3_client_method();
313 use_sni(TRUE);
314 break;
315 #else
316 failf(data, "wolfSSL: TLS 1.3 is not yet supported");
317 return CURLE_SSL_CONNECT_ERROR;
318 #endif
319 default:
320 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
321 return CURLE_SSL_CONNECT_ERROR;
322 }
323
324 if(!req_method) {
325 failf(data, "SSL: couldn't create a method!");
326 return CURLE_OUT_OF_MEMORY;
327 }
328
329 if(backend->ctx)
330 SSL_CTX_free(backend->ctx);
331 backend->ctx = SSL_CTX_new(req_method);
332
333 if(!backend->ctx) {
334 failf(data, "SSL: couldn't create a context!");
335 return CURLE_OUT_OF_MEMORY;
336 }
337
338 switch(SSL_CONN_CONFIG(version)) {
339 case CURL_SSLVERSION_DEFAULT:
340 case CURL_SSLVERSION_TLSv1:
341 #if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
342 /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is
343 * whatever minimum version of TLS was built in and at least TLS 1.0. For
344 * later library versions that could change (eg TLS 1.0 built in but
345 * defaults to TLS 1.1) so we have this short circuit evaluation to find
346 * the minimum supported TLS version.
347 */
348 if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) &&
349 (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) &&
350 (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1)
351 #ifdef WOLFSSL_TLS13
352 && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1)
353 #endif
354 ) {
355 failf(data, "SSL: couldn't set the minimum protocol version");
356 return CURLE_SSL_CONNECT_ERROR;
357 }
358 #endif
359 break;
360 }
361
362 ciphers = SSL_CONN_CONFIG(cipher_list);
363 if(ciphers) {
364 if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
365 failf(data, "failed setting cipher list: %s", ciphers);
366 return CURLE_SSL_CIPHER;
367 }
368 infof(data, "Cipher selection: %s", ciphers);
369 }
370
371 curves = SSL_CONN_CONFIG(curves);
372 if(curves) {
373
374 #ifdef HAVE_LIBOQS
375 for(idx = 0; gnm[idx].name != NULL; idx++) {
376 if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) {
377 oqsAlg = gnm[idx].group;
378 break;
379 }
380 }
381
382 if(oqsAlg == 0)
383 #endif
384 {
385 if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
386 failf(data, "failed setting curves list: '%s'", curves);
387 return CURLE_SSL_CIPHER;
388 }
389 }
390 }
391 #ifndef NO_FILESYSTEM
392 /* load trusted cacert */
393 if(SSL_CONN_CONFIG(CAfile)) {
394 if(1 != SSL_CTX_load_verify_locations(backend->ctx,
395 SSL_CONN_CONFIG(CAfile),
396 SSL_CONN_CONFIG(CApath))) {
397 if(SSL_CONN_CONFIG(verifypeer)) {
398 /* Fail if we insist on successfully verifying the server. */
399 failf(data, "error setting certificate verify locations:"
400 " CAfile: %s CApath: %s",
401 SSL_CONN_CONFIG(CAfile)?
402 SSL_CONN_CONFIG(CAfile): "none",
403 SSL_CONN_CONFIG(CApath)?
404 SSL_CONN_CONFIG(CApath) : "none");
405 return CURLE_SSL_CACERT_BADFILE;
406 }
407 else {
408 /* Just continue with a warning if no strict certificate
409 verification is required. */
410 infof(data, "error setting certificate verify locations,"
411 " continuing anyway:");
412 }
413 }
414 else {
415 /* Everything is fine. */
416 infof(data, "successfully set certificate verify locations:");
417 }
418 infof(data, " CAfile: %s",
419 SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none");
420 infof(data, " CApath: %s",
421 SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none");
422 }
423
424 /* Load the client certificate, and private key */
425 if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) {
426 int file_type = do_file_type(SSL_SET_OPTION(cert_type));
427
428 if(SSL_CTX_use_certificate_file(backend->ctx,
429 SSL_SET_OPTION(primary.clientcert),
430 file_type) != 1) {
431 failf(data, "unable to use client certificate (no key or wrong pass"
432 " phrase?)");
433 return CURLE_SSL_CONNECT_ERROR;
434 }
435
436 file_type = do_file_type(SSL_SET_OPTION(key_type));
437 if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key),
438 file_type) != 1) {
439 failf(data, "unable to set private key");
440 return CURLE_SSL_CONNECT_ERROR;
441 }
442 }
443 #endif /* !NO_FILESYSTEM */
444
445 /* SSL always tries to verify the peer, this only says whether it should
446 * fail to connect if the verification fails, or if it should continue
447 * anyway. In the latter case the result of the verification is checked with
448 * SSL_get_verify_result() below. */
449 SSL_CTX_set_verify(backend->ctx,
450 SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
451 SSL_VERIFY_NONE,
452 NULL);
453
454 #ifdef HAVE_SNI
455 if(sni) {
456 struct in_addr addr4;
457 #ifdef ENABLE_IPV6
458 struct in6_addr addr6;
459 #endif
460 const char * const hostname = SSL_HOST_NAME();
461 size_t hostname_len = strlen(hostname);
462 if((hostname_len < USHRT_MAX) &&
463 (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
464 #ifdef ENABLE_IPV6
465 (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
466 #endif
467 (wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, hostname,
468 (unsigned short)hostname_len) != 1)) {
469 infof(data, "WARNING: failed to configure server name indication (SNI) "
470 "TLS extension");
471 }
472 }
473 #endif
474
475 /* give application a chance to interfere with SSL set up. */
476 if(data->set.ssl.fsslctx) {
477 CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx,
478 data->set.ssl.fsslctxp);
479 if(result) {
480 failf(data, "error signaled by ssl ctx callback");
481 return result;
482 }
483 }
484 #ifdef NO_FILESYSTEM
485 else if(SSL_CONN_CONFIG(verifypeer)) {
486 failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
487 " with \"no filesystem\". Either disable peer verification"
488 " (insecure) or if you are building an application with libcurl you"
489 " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
490 return CURLE_SSL_CONNECT_ERROR;
491 }
492 #endif
493
494 /* Let's make an SSL structure */
495 if(backend->handle)
496 SSL_free(backend->handle);
497 backend->handle = SSL_new(backend->ctx);
498 if(!backend->handle) {
499 failf(data, "SSL: couldn't create a context (handle)!");
500 return CURLE_OUT_OF_MEMORY;
501 }
502
503 #ifdef HAVE_LIBOQS
504 if(oqsAlg) {
505 if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) {
506 failf(data, "unable to use oqs KEM");
507 }
508 }
509 #endif
510
511 #ifdef HAVE_ALPN
512 if(conn->bits.tls_enable_alpn) {
513 char protocols[128];
514 *protocols = '\0';
515
516 /* wolfSSL's ALPN protocol name list format is a comma separated string of
517 protocols in descending order of preference, eg: "h2,http/1.1" */
518
519 #ifdef USE_HTTP2
520 if(data->state.httpwant >= CURL_HTTP_VERSION_2) {
521 strcpy(protocols + strlen(protocols), ALPN_H2 ",");
522 infof(data, "ALPN, offering %s", ALPN_H2);
523 }
524 #endif
525
526 strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
527 infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
528
529 if(wolfSSL_UseALPN(backend->handle, protocols,
530 (unsigned)strlen(protocols),
531 WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
532 failf(data, "SSL: failed setting ALPN protocols");
533 return CURLE_SSL_CONNECT_ERROR;
534 }
535 }
536 #endif /* HAVE_ALPN */
537
538 #ifdef OPENSSL_EXTRA
539 if(Curl_tls_keylog_enabled()) {
540 /* Ensure the Client Random is preserved. */
541 wolfSSL_KeepArrays(backend->handle);
542 #if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
543 wolfSSL_set_tls13_secret_cb(backend->handle,
544 wolfssl_tls13_secret_callback, NULL);
545 #endif
546 }
547 #endif /* OPENSSL_EXTRA */
548
549 #ifdef HAVE_SECURE_RENEGOTIATION
550 if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) {
551 failf(data, "SSL: failed setting secure renegotiation");
552 return CURLE_SSL_CONNECT_ERROR;
553 }
554 #endif /* HAVE_SECURE_RENEGOTIATION */
555
556 /* Check if there's a cached ID we can/should use here! */
557 if(SSL_SET_OPTION(primary.sessionid)) {
558 void *ssl_sessionid = NULL;
559
560 Curl_ssl_sessionid_lock(data);
561 if(!Curl_ssl_getsessionid(data, conn,
562 SSL_IS_PROXY() ? TRUE : FALSE,
563 &ssl_sessionid, NULL, sockindex)) {
564 /* we got a session id, use it! */
565 if(!SSL_set_session(backend->handle, ssl_sessionid)) {
566 Curl_ssl_delsessionid(data, ssl_sessionid);
567 infof(data, "Can't use session ID, going on without");
568 }
569 else
570 infof(data, "SSL re-using session ID");
571 }
572 Curl_ssl_sessionid_unlock(data);
573 }
574
575 /* pass the raw socket into the SSL layer */
576 if(!SSL_set_fd(backend->handle, (int)sockfd)) {
577 failf(data, "SSL: SSL_set_fd failed");
578 return CURLE_SSL_CONNECT_ERROR;
579 }
580
581 connssl->connecting_state = ssl_connect_2;
582 return CURLE_OK;
583 }
584
585
586 static CURLcode
wolfssl_connect_step2(struct Curl_easy * data,struct connectdata * conn,int sockindex)587 wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
588 int sockindex)
589 {
590 int ret = -1;
591 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
592 struct ssl_backend_data *backend = connssl->backend;
593 const char * const hostname = SSL_HOST_NAME();
594 const char * const dispname = SSL_HOST_DISPNAME();
595 const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
596
597 ERR_clear_error();
598
599 conn->recv[sockindex] = wolfssl_recv;
600 conn->send[sockindex] = wolfssl_send;
601
602 /* Enable RFC2818 checks */
603 if(SSL_CONN_CONFIG(verifyhost)) {
604 ret = wolfSSL_check_domain_name(backend->handle, hostname);
605 if(ret == SSL_FAILURE)
606 return CURLE_OUT_OF_MEMORY;
607 }
608
609 ret = SSL_connect(backend->handle);
610
611 #ifdef OPENSSL_EXTRA
612 if(Curl_tls_keylog_enabled()) {
613 /* If key logging is enabled, wait for the handshake to complete and then
614 * proceed with logging secrets (for TLS 1.2 or older).
615 *
616 * During the handshake (ret==-1), wolfSSL_want_read() is true as it waits
617 * for the server response. At that point the master secret is not yet
618 * available, so we must not try to read it.
619 * To log the secret on completion with a handshake failure, detect
620 * completion via the observation that there is nothing to read or write.
621 * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever
622 * changes, the worst case is that no key is logged on error.
623 */
624 if(ret == SSL_SUCCESS ||
625 (!wolfSSL_want_read(backend->handle) &&
626 !wolfSSL_want_write(backend->handle))) {
627 wolfssl_log_tls12_secret(backend->handle);
628 /* Client Random and master secrets are no longer needed, erase these.
629 * Ignored while the handshake is still in progress. */
630 wolfSSL_FreeArrays(backend->handle);
631 }
632 }
633 #endif /* OPENSSL_EXTRA */
634
635 if(ret != 1) {
636 char error_buffer[WOLFSSL_MAX_ERROR_SZ];
637 int detail = SSL_get_error(backend->handle, ret);
638
639 if(SSL_ERROR_WANT_READ == detail) {
640 connssl->connecting_state = ssl_connect_2_reading;
641 return CURLE_OK;
642 }
643 else if(SSL_ERROR_WANT_WRITE == detail) {
644 connssl->connecting_state = ssl_connect_2_writing;
645 return CURLE_OK;
646 }
647 /* There is no easy way to override only the CN matching.
648 * This will enable the override of both mismatching SubjectAltNames
649 * as also mismatching CN fields */
650 else if(DOMAIN_NAME_MISMATCH == detail) {
651 #if 1
652 failf(data, " subject alt name(s) or common name do not match \"%s\"",
653 dispname);
654 return CURLE_PEER_FAILED_VERIFICATION;
655 #else
656 /* When the wolfssl_check_domain_name() is used and you desire to
657 * continue on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost
658 * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
659 * error. The only way to do this is currently to switch the
660 * Wolfssl_check_domain_name() in and out based on the
661 * 'conn->ssl_config.verifyhost' value. */
662 if(SSL_CONN_CONFIG(verifyhost)) {
663 failf(data,
664 " subject alt name(s) or common name do not match \"%s\"\n",
665 dispname);
666 return CURLE_PEER_FAILED_VERIFICATION;
667 }
668 else {
669 infof(data,
670 " subject alt name(s) and/or common name do not match \"%s\"",
671 dispname);
672 return CURLE_OK;
673 }
674 #endif
675 }
676 #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
677 else if(ASN_NO_SIGNER_E == detail) {
678 if(SSL_CONN_CONFIG(verifypeer)) {
679 failf(data, " CA signer not available for verification");
680 return CURLE_SSL_CACERT_BADFILE;
681 }
682 else {
683 /* Just continue with a warning if no strict certificate
684 verification is required. */
685 infof(data, "CA signer not available for verification, "
686 "continuing anyway");
687 }
688 }
689 #endif
690 else {
691 failf(data, "SSL_connect failed with error %d: %s", detail,
692 ERR_error_string(detail, error_buffer));
693 return CURLE_SSL_CONNECT_ERROR;
694 }
695 }
696
697 if(pinnedpubkey) {
698 #ifdef KEEP_PEER_CERT
699 X509 *x509;
700 const char *x509_der;
701 int x509_der_len;
702 struct Curl_X509certificate x509_parsed;
703 struct Curl_asn1Element *pubkey;
704 CURLcode result;
705
706 x509 = SSL_get_peer_certificate(backend->handle);
707 if(!x509) {
708 failf(data, "SSL: failed retrieving server certificate");
709 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
710 }
711
712 x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
713 if(!x509_der) {
714 failf(data, "SSL: failed retrieving ASN.1 server certificate");
715 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
716 }
717
718 memset(&x509_parsed, 0, sizeof(x509_parsed));
719 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
720 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
721
722 pubkey = &x509_parsed.subjectPublicKeyInfo;
723 if(!pubkey->header || pubkey->end <= pubkey->header) {
724 failf(data, "SSL: failed retrieving public key from server certificate");
725 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
726 }
727
728 result = Curl_pin_peer_pubkey(data,
729 pinnedpubkey,
730 (const unsigned char *)pubkey->header,
731 (size_t)(pubkey->end - pubkey->header));
732 if(result) {
733 failf(data, "SSL: public key does not match pinned public key!");
734 return result;
735 }
736 #else
737 failf(data, "Library lacks pinning support built-in");
738 return CURLE_NOT_BUILT_IN;
739 #endif
740 }
741
742 #ifdef HAVE_ALPN
743 if(conn->bits.tls_enable_alpn) {
744 int rc;
745 char *protocol = NULL;
746 unsigned short protocol_len = 0;
747
748 rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
749
750 if(rc == SSL_SUCCESS) {
751 infof(data, "ALPN, server accepted to use %.*s", protocol_len,
752 protocol);
753
754 if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
755 !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
756 conn->negnpn = CURL_HTTP_VERSION_1_1;
757 #ifdef USE_HTTP2
758 else if(data->state.httpwant >= CURL_HTTP_VERSION_2 &&
759 protocol_len == ALPN_H2_LENGTH &&
760 !memcmp(protocol, ALPN_H2, ALPN_H2_LENGTH))
761 conn->negnpn = CURL_HTTP_VERSION_2;
762 #endif
763 else
764 infof(data, "ALPN, unrecognized protocol %.*s", protocol_len,
765 protocol);
766 Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
767 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
768 }
769 else if(rc == SSL_ALPN_NOT_FOUND)
770 infof(data, "ALPN, server did not agree to a protocol");
771 else {
772 failf(data, "ALPN, failure getting protocol, error %d", rc);
773 return CURLE_SSL_CONNECT_ERROR;
774 }
775 }
776 #endif /* HAVE_ALPN */
777
778 connssl->connecting_state = ssl_connect_3;
779 #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
780 infof(data, "SSL connection using %s / %s",
781 wolfSSL_get_version(backend->handle),
782 wolfSSL_get_cipher_name(backend->handle));
783 #else
784 infof(data, "SSL connected");
785 #endif
786
787 return CURLE_OK;
788 }
789
790
791 static CURLcode
wolfssl_connect_step3(struct Curl_easy * data,struct connectdata * conn,int sockindex)792 wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
793 int sockindex)
794 {
795 CURLcode result = CURLE_OK;
796 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
797 struct ssl_backend_data *backend = connssl->backend;
798
799 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
800
801 if(SSL_SET_OPTION(primary.sessionid)) {
802 bool incache;
803 void *old_ssl_sessionid = NULL;
804 SSL_SESSION *our_ssl_sessionid = SSL_get_session(backend->handle);
805 bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
806
807 if(our_ssl_sessionid) {
808 Curl_ssl_sessionid_lock(data);
809 incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
810 &old_ssl_sessionid, NULL, sockindex));
811 if(incache) {
812 if(old_ssl_sessionid != our_ssl_sessionid) {
813 infof(data, "old SSL session ID is stale, removing");
814 Curl_ssl_delsessionid(data, old_ssl_sessionid);
815 incache = FALSE;
816 }
817 }
818
819 if(!incache) {
820 result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
821 0, sockindex, NULL);
822 if(result) {
823 Curl_ssl_sessionid_unlock(data);
824 failf(data, "failed to store ssl session");
825 return result;
826 }
827 }
828 Curl_ssl_sessionid_unlock(data);
829 }
830 }
831
832 connssl->connecting_state = ssl_connect_done;
833
834 return result;
835 }
836
837
wolfssl_send(struct Curl_easy * data,int sockindex,const void * mem,size_t len,CURLcode * curlcode)838 static ssize_t wolfssl_send(struct Curl_easy *data,
839 int sockindex,
840 const void *mem,
841 size_t len,
842 CURLcode *curlcode)
843 {
844 struct connectdata *conn = data->conn;
845 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
846 struct ssl_backend_data *backend = connssl->backend;
847 char error_buffer[WOLFSSL_MAX_ERROR_SZ];
848 int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
849 int rc;
850
851 ERR_clear_error();
852
853 rc = SSL_write(backend->handle, mem, memlen);
854
855 if(rc <= 0) {
856 int err = SSL_get_error(backend->handle, rc);
857
858 switch(err) {
859 case SSL_ERROR_WANT_READ:
860 case SSL_ERROR_WANT_WRITE:
861 /* there's data pending, re-invoke SSL_write() */
862 *curlcode = CURLE_AGAIN;
863 return -1;
864 default:
865 failf(data, "SSL write: %s, errno %d",
866 ERR_error_string(err, error_buffer),
867 SOCKERRNO);
868 *curlcode = CURLE_SEND_ERROR;
869 return -1;
870 }
871 }
872 return rc;
873 }
874
wolfssl_close(struct Curl_easy * data,struct connectdata * conn,int sockindex)875 static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
876 int sockindex)
877 {
878 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
879 struct ssl_backend_data *backend = connssl->backend;
880
881 (void) data;
882
883 if(backend->handle) {
884 char buf[32];
885 /* Maybe the server has already sent a close notify alert.
886 Read it to avoid an RST on the TCP connection. */
887 (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
888 (void)SSL_shutdown(backend->handle);
889 SSL_free(backend->handle);
890 backend->handle = NULL;
891 }
892 if(backend->ctx) {
893 SSL_CTX_free(backend->ctx);
894 backend->ctx = NULL;
895 }
896 }
897
wolfssl_recv(struct Curl_easy * data,int num,char * buf,size_t buffersize,CURLcode * curlcode)898 static ssize_t wolfssl_recv(struct Curl_easy *data,
899 int num,
900 char *buf,
901 size_t buffersize,
902 CURLcode *curlcode)
903 {
904 struct connectdata *conn = data->conn;
905 struct ssl_connect_data *connssl = &conn->ssl[num];
906 struct ssl_backend_data *backend = connssl->backend;
907 char error_buffer[WOLFSSL_MAX_ERROR_SZ];
908 int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
909 int nread;
910
911 ERR_clear_error();
912
913 nread = SSL_read(backend->handle, buf, buffsize);
914
915 if(nread < 0) {
916 int err = SSL_get_error(backend->handle, nread);
917
918 switch(err) {
919 case SSL_ERROR_ZERO_RETURN: /* no more data */
920 break;
921 case SSL_ERROR_WANT_READ:
922 case SSL_ERROR_WANT_WRITE:
923 /* there's data pending, re-invoke SSL_read() */
924 *curlcode = CURLE_AGAIN;
925 return -1;
926 default:
927 failf(data, "SSL read: %s, errno %d",
928 ERR_error_string(err, error_buffer), SOCKERRNO);
929 *curlcode = CURLE_RECV_ERROR;
930 return -1;
931 }
932 }
933 return nread;
934 }
935
936
wolfssl_session_free(void * ptr)937 static void wolfssl_session_free(void *ptr)
938 {
939 (void)ptr;
940 /* wolfSSL reuses sessions on own, no free */
941 }
942
943
wolfssl_version(char * buffer,size_t size)944 static size_t wolfssl_version(char *buffer, size_t size)
945 {
946 #if LIBWOLFSSL_VERSION_HEX >= 0x03006000
947 return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
948 #elif defined(WOLFSSL_VERSION)
949 return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
950 #endif
951 }
952
953
wolfssl_init(void)954 static int wolfssl_init(void)
955 {
956 #ifdef OPENSSL_EXTRA
957 Curl_tls_keylog_open();
958 #endif
959 return (wolfSSL_Init() == SSL_SUCCESS);
960 }
961
962
wolfssl_cleanup(void)963 static void wolfssl_cleanup(void)
964 {
965 wolfSSL_Cleanup();
966 #ifdef OPENSSL_EXTRA
967 Curl_tls_keylog_close();
968 #endif
969 }
970
971
wolfssl_data_pending(const struct connectdata * conn,int connindex)972 static bool wolfssl_data_pending(const struct connectdata *conn,
973 int connindex)
974 {
975 const struct ssl_connect_data *connssl = &conn->ssl[connindex];
976 struct ssl_backend_data *backend = connssl->backend;
977 if(backend->handle) /* SSL is in use */
978 return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE;
979 else
980 return FALSE;
981 }
982
983
984 /*
985 * This function is called to shut down the SSL layer but keep the
986 * socket open (CCC - Clear Command Channel)
987 */
wolfssl_shutdown(struct Curl_easy * data,struct connectdata * conn,int sockindex)988 static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
989 int sockindex)
990 {
991 int retval = 0;
992 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
993 struct ssl_backend_data *backend = connssl->backend;
994
995 (void) data;
996
997 if(backend->handle) {
998 ERR_clear_error();
999 SSL_free(backend->handle);
1000 backend->handle = NULL;
1001 }
1002 return retval;
1003 }
1004
1005
1006 static CURLcode
wolfssl_connect_common(struct Curl_easy * data,struct connectdata * conn,int sockindex,bool nonblocking,bool * done)1007 wolfssl_connect_common(struct Curl_easy *data,
1008 struct connectdata *conn,
1009 int sockindex,
1010 bool nonblocking,
1011 bool *done)
1012 {
1013 CURLcode result;
1014 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1015 curl_socket_t sockfd = conn->sock[sockindex];
1016 int what;
1017
1018 /* check if the connection has already been established */
1019 if(ssl_connection_complete == connssl->state) {
1020 *done = TRUE;
1021 return CURLE_OK;
1022 }
1023
1024 if(ssl_connect_1 == connssl->connecting_state) {
1025 /* Find out how much more time we're allowed */
1026 const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
1027
1028 if(timeout_ms < 0) {
1029 /* no need to continue if time already is up */
1030 failf(data, "SSL connection timeout");
1031 return CURLE_OPERATION_TIMEDOUT;
1032 }
1033
1034 result = wolfssl_connect_step1(data, conn, sockindex);
1035 if(result)
1036 return result;
1037 }
1038
1039 while(ssl_connect_2 == connssl->connecting_state ||
1040 ssl_connect_2_reading == connssl->connecting_state ||
1041 ssl_connect_2_writing == connssl->connecting_state) {
1042
1043 /* check allowed time left */
1044 const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
1045
1046 if(timeout_ms < 0) {
1047 /* no need to continue if time already is up */
1048 failf(data, "SSL connection timeout");
1049 return CURLE_OPERATION_TIMEDOUT;
1050 }
1051
1052 /* if ssl is expecting something, check if it's available. */
1053 if(connssl->connecting_state == ssl_connect_2_reading
1054 || connssl->connecting_state == ssl_connect_2_writing) {
1055
1056 curl_socket_t writefd = ssl_connect_2_writing ==
1057 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1058 curl_socket_t readfd = ssl_connect_2_reading ==
1059 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
1060
1061 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1062 nonblocking?0:timeout_ms);
1063 if(what < 0) {
1064 /* fatal error */
1065 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1066 return CURLE_SSL_CONNECT_ERROR;
1067 }
1068 else if(0 == what) {
1069 if(nonblocking) {
1070 *done = FALSE;
1071 return CURLE_OK;
1072 }
1073 else {
1074 /* timeout */
1075 failf(data, "SSL connection timeout");
1076 return CURLE_OPERATION_TIMEDOUT;
1077 }
1078 }
1079 /* socket is readable or writable */
1080 }
1081
1082 /* Run transaction, and return to the caller if it failed or if
1083 * this connection is part of a multi handle and this loop would
1084 * execute again. This permits the owner of a multi handle to
1085 * abort a connection attempt before step2 has completed while
1086 * ensuring that a client using select() or epoll() will always
1087 * have a valid fdset to wait on.
1088 */
1089 result = wolfssl_connect_step2(data, conn, sockindex);
1090 if(result || (nonblocking &&
1091 (ssl_connect_2 == connssl->connecting_state ||
1092 ssl_connect_2_reading == connssl->connecting_state ||
1093 ssl_connect_2_writing == connssl->connecting_state)))
1094 return result;
1095 } /* repeat step2 until all transactions are done. */
1096
1097 if(ssl_connect_3 == connssl->connecting_state) {
1098 result = wolfssl_connect_step3(data, conn, sockindex);
1099 if(result)
1100 return result;
1101 }
1102
1103 if(ssl_connect_done == connssl->connecting_state) {
1104 connssl->state = ssl_connection_complete;
1105 conn->recv[sockindex] = wolfssl_recv;
1106 conn->send[sockindex] = wolfssl_send;
1107 *done = TRUE;
1108 }
1109 else
1110 *done = FALSE;
1111
1112 /* Reset our connect state machine */
1113 connssl->connecting_state = ssl_connect_1;
1114
1115 return CURLE_OK;
1116 }
1117
1118
wolfssl_connect_nonblocking(struct Curl_easy * data,struct connectdata * conn,int sockindex,bool * done)1119 static CURLcode wolfssl_connect_nonblocking(struct Curl_easy *data,
1120 struct connectdata *conn,
1121 int sockindex, bool *done)
1122 {
1123 return wolfssl_connect_common(data, conn, sockindex, TRUE, done);
1124 }
1125
1126
wolfssl_connect(struct Curl_easy * data,struct connectdata * conn,int sockindex)1127 static CURLcode wolfssl_connect(struct Curl_easy *data,
1128 struct connectdata *conn, int sockindex)
1129 {
1130 CURLcode result;
1131 bool done = FALSE;
1132
1133 result = wolfssl_connect_common(data, conn, sockindex, FALSE, &done);
1134 if(result)
1135 return result;
1136
1137 DEBUGASSERT(done);
1138
1139 return CURLE_OK;
1140 }
1141
wolfssl_random(struct Curl_easy * data,unsigned char * entropy,size_t length)1142 static CURLcode wolfssl_random(struct Curl_easy *data,
1143 unsigned char *entropy, size_t length)
1144 {
1145 WC_RNG rng;
1146 (void)data;
1147 if(wc_InitRng(&rng))
1148 return CURLE_FAILED_INIT;
1149 if(length > UINT_MAX)
1150 return CURLE_FAILED_INIT;
1151 if(wc_RNG_GenerateBlock(&rng, entropy, (unsigned)length))
1152 return CURLE_FAILED_INIT;
1153 if(wc_FreeRng(&rng))
1154 return CURLE_FAILED_INIT;
1155 return CURLE_OK;
1156 }
1157
wolfssl_sha256sum(const unsigned char * tmp,size_t tmplen,unsigned char * sha256sum,size_t unused)1158 static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
1159 size_t tmplen,
1160 unsigned char *sha256sum /* output */,
1161 size_t unused)
1162 {
1163 wc_Sha256 SHA256pw;
1164 (void)unused;
1165 wc_InitSha256(&SHA256pw);
1166 wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen);
1167 wc_Sha256Final(&SHA256pw, sha256sum);
1168 return CURLE_OK;
1169 }
1170
wolfssl_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)1171 static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
1172 CURLINFO info UNUSED_PARAM)
1173 {
1174 struct ssl_backend_data *backend = connssl->backend;
1175 (void)info;
1176 return backend->handle;
1177 }
1178
1179 const struct Curl_ssl Curl_ssl_wolfssl = {
1180 { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
1181
1182 #ifdef KEEP_PEER_CERT
1183 SSLSUPP_PINNEDPUBKEY |
1184 #endif
1185 SSLSUPP_SSL_CTX,
1186
1187 sizeof(struct ssl_backend_data),
1188
1189 wolfssl_init, /* init */
1190 wolfssl_cleanup, /* cleanup */
1191 wolfssl_version, /* version */
1192 Curl_none_check_cxn, /* check_cxn */
1193 wolfssl_shutdown, /* shutdown */
1194 wolfssl_data_pending, /* data_pending */
1195 wolfssl_random, /* random */
1196 Curl_none_cert_status_request, /* cert_status_request */
1197 wolfssl_connect, /* connect */
1198 wolfssl_connect_nonblocking, /* connect_nonblocking */
1199 Curl_ssl_getsock, /* getsock */
1200 wolfssl_get_internals, /* get_internals */
1201 wolfssl_close, /* close_one */
1202 Curl_none_close_all, /* close_all */
1203 wolfssl_session_free, /* session_free */
1204 Curl_none_set_engine, /* set_engine */
1205 Curl_none_set_engine_default, /* set_engine_default */
1206 Curl_none_engines_list, /* engines_list */
1207 Curl_none_false_start, /* false_start */
1208 wolfssl_sha256sum, /* sha256sum */
1209 NULL, /* associate_connection */
1210 NULL /* disassociate_connection */
1211 };
1212
1213 #endif
1214