1 | /*************************************************************************** |
2 | * _ _ ____ _ |
3 | * Project ___| | | | _ \| | |
4 | * / __| | | | |_) | | |
5 | * | (__| |_| | _ <| |___ |
6 | * \___|\___/|_| \_\_____| |
7 | * |
8 | * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. |
9 | * |
10 | * This software is licensed as described in the file COPYING, which |
11 | * you should have received as part of this distribution. The terms |
12 | * are also available at https://curl.se/docs/copyright.html. |
13 | * |
14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
15 | * copies of the Software, and permit persons to whom the Software is |
16 | * furnished to do so, under the terms of the COPYING file. |
17 | * |
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
19 | * KIND, either express or implied. |
20 | * |
21 | * SPDX-License-Identifier: curl |
22 | * |
23 | ***************************************************************************/ |
24 | |
25 | /* |
26 | * Source file for all wolfSSL specific code for the TLS/SSL layer. No code |
27 | * but vtls.c should ever call or use these functions. |
28 | * |
29 | */ |
30 | |
31 | #include "curl_setup.h" |
32 | |
33 | #ifdef USE_WOLFSSL |
34 | |
35 | #define WOLFSSL_OPTIONS_IGNORE_SYS |
36 | #include <wolfssl/version.h> |
37 | #include <wolfssl/options.h> |
38 | |
39 | /* To determine what functions are available we rely on one or both of: |
40 | - the user's options.h generated by wolfSSL |
41 | - the symbols detected by curl's configure |
42 | Since they are markedly different from one another, and one or the other may |
43 | not be available, we do some checking below to bring things in sync. */ |
44 | |
45 | /* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */ |
46 | #ifndef HAVE_ALPN |
47 | #ifdef HAVE_WOLFSSL_USEALPN |
48 | #define HAVE_ALPN |
49 | #endif |
50 | #endif |
51 | |
52 | #include <limits.h> |
53 | |
54 | #include "urldata.h" |
55 | #include "sendf.h" |
56 | #include "inet_pton.h" |
57 | #include "vtls.h" |
58 | #include "vtls_int.h" |
59 | #include "keylog.h" |
60 | #include "parsedate.h" |
61 | #include "connect.h" /* for the connect timeout */ |
62 | #include "select.h" |
63 | #include "strcase.h" |
64 | #include "x509asn1.h" |
65 | #include "curl_printf.h" |
66 | #include "multiif.h" |
67 | |
68 | #include <wolfssl/openssl/ssl.h> |
69 | #include <wolfssl/ssl.h> |
70 | #include <wolfssl/error-ssl.h> |
71 | #include "wolfssl.h" |
72 | |
73 | /* The last #include files should be: */ |
74 | #include "curl_memory.h" |
75 | #include "memdebug.h" |
76 | |
77 | /* KEEP_PEER_CERT is a product of the presence of build time symbol |
78 | OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is |
79 | in wolfSSL's settings.h, and the latter two are build time symbols in |
80 | options.h. */ |
81 | #ifndef KEEP_PEER_CERT |
82 | #if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ |
83 | (defined(OPENSSL_EXTRA) && !defined(NO_CERTS)) |
84 | #define KEEP_PEER_CERT |
85 | #endif |
86 | #endif |
87 | |
88 | #if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO |
89 | #define USE_BIO_CHAIN |
90 | #else |
91 | #undef USE_BIO_CHAIN |
92 | #endif |
93 | |
94 | struct wolfssl_ssl_backend_data { |
95 | WOLFSSL_CTX *ctx; |
96 | WOLFSSL *handle; |
97 | CURLcode io_result; /* result of last BIO cfilter operation */ |
98 | }; |
99 | |
100 | #ifdef OPENSSL_EXTRA |
101 | /* |
102 | * Availability note: |
103 | * The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in |
104 | * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that |
105 | * option is not set, then TLS 1.3 will not be logged. |
106 | * For TLS 1.2 and before, we use wolfSSL_get_keys(). |
107 | * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA |
108 | * (--enable-opensslextra or --enable-all). |
109 | */ |
110 | #if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) |
111 | static int |
112 | wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret, |
113 | int secretSz, void *ctx) |
114 | { |
115 | const char *label; |
116 | unsigned char client_random[SSL3_RANDOM_SIZE]; |
117 | (void)ctx; |
118 | |
119 | if(!ssl || !Curl_tls_keylog_enabled()) { |
120 | return 0; |
121 | } |
122 | |
123 | switch(id) { |
124 | case CLIENT_EARLY_TRAFFIC_SECRET: |
125 | label = "CLIENT_EARLY_TRAFFIC_SECRET" ; |
126 | break; |
127 | case CLIENT_HANDSHAKE_TRAFFIC_SECRET: |
128 | label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET" ; |
129 | break; |
130 | case SERVER_HANDSHAKE_TRAFFIC_SECRET: |
131 | label = "SERVER_HANDSHAKE_TRAFFIC_SECRET" ; |
132 | break; |
133 | case CLIENT_TRAFFIC_SECRET: |
134 | label = "CLIENT_TRAFFIC_SECRET_0" ; |
135 | break; |
136 | case SERVER_TRAFFIC_SECRET: |
137 | label = "SERVER_TRAFFIC_SECRET_0" ; |
138 | break; |
139 | case EARLY_EXPORTER_SECRET: |
140 | label = "EARLY_EXPORTER_SECRET" ; |
141 | break; |
142 | case EXPORTER_SECRET: |
143 | label = "EXPORTER_SECRET" ; |
144 | break; |
145 | default: |
146 | return 0; |
147 | } |
148 | |
149 | if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) { |
150 | /* Should never happen as wolfSSL_KeepArrays() was called before. */ |
151 | return 0; |
152 | } |
153 | |
154 | Curl_tls_keylog_write(label, client_random, secret, secretSz); |
155 | return 0; |
156 | } |
157 | #endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */ |
158 | |
159 | static void |
160 | wolfssl_log_tls12_secret(SSL *ssl) |
161 | { |
162 | unsigned char *ms, *sr, *cr; |
163 | unsigned int msLen, srLen, crLen, i, x = 0; |
164 | |
165 | #if LIBWOLFSSL_VERSION_HEX >= 0x0300d000 /* >= 3.13.0 */ |
166 | /* wolfSSL_GetVersion is available since 3.13, we use it instead of |
167 | * SSL_version since the latter relies on OPENSSL_ALL (--enable-opensslall or |
168 | * --enable-all). Failing to perform this check could result in an unusable |
169 | * key log line when TLS 1.3 is actually negotiated. */ |
170 | switch(wolfSSL_GetVersion(ssl)) { |
171 | case WOLFSSL_SSLV3: |
172 | case WOLFSSL_TLSV1: |
173 | case WOLFSSL_TLSV1_1: |
174 | case WOLFSSL_TLSV1_2: |
175 | break; |
176 | default: |
177 | /* TLS 1.3 does not use this mechanism, the "master secret" returned below |
178 | * is not directly usable. */ |
179 | return; |
180 | } |
181 | #endif |
182 | |
183 | if(wolfSSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) != |
184 | SSL_SUCCESS) { |
185 | return; |
186 | } |
187 | |
188 | /* Check for a missing master secret and skip logging. That can happen if |
189 | * curl rejects the server certificate and aborts the handshake. |
190 | */ |
191 | for(i = 0; i < msLen; i++) { |
192 | x |= ms[i]; |
193 | } |
194 | if(x == 0) { |
195 | return; |
196 | } |
197 | |
198 | Curl_tls_keylog_write("CLIENT_RANDOM" , cr, ms, msLen); |
199 | } |
200 | #endif /* OPENSSL_EXTRA */ |
201 | |
202 | static int do_file_type(const char *type) |
203 | { |
204 | if(!type || !type[0]) |
205 | return SSL_FILETYPE_PEM; |
206 | if(strcasecompare(type, "PEM" )) |
207 | return SSL_FILETYPE_PEM; |
208 | if(strcasecompare(type, "DER" )) |
209 | return SSL_FILETYPE_ASN1; |
210 | return -1; |
211 | } |
212 | |
213 | #ifdef HAVE_LIBOQS |
214 | struct group_name_map { |
215 | const word16 group; |
216 | const char *name; |
217 | }; |
218 | |
219 | static const struct group_name_map gnm[] = { |
220 | { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" }, |
221 | { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" }, |
222 | { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" }, |
223 | { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" }, |
224 | { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" }, |
225 | { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" }, |
226 | { 0, NULL } |
227 | }; |
228 | #endif |
229 | |
230 | #ifdef USE_BIO_CHAIN |
231 | |
232 | static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio) |
233 | { |
234 | wolfSSL_BIO_set_shutdown(bio, 1); |
235 | wolfSSL_BIO_set_init(bio, 1); |
236 | wolfSSL_BIO_set_data(bio, NULL); |
237 | return 1; |
238 | } |
239 | |
240 | static int wolfssl_bio_cf_destroy(WOLFSSL_BIO *bio) |
241 | { |
242 | if(!bio) |
243 | return 0; |
244 | return 1; |
245 | } |
246 | |
247 | static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr) |
248 | { |
249 | struct Curl_cfilter *cf = BIO_get_data(bio); |
250 | long ret = 1; |
251 | |
252 | (void)cf; |
253 | (void)ptr; |
254 | switch(cmd) { |
255 | case BIO_CTRL_GET_CLOSE: |
256 | ret = (long)wolfSSL_BIO_get_shutdown(bio); |
257 | break; |
258 | case BIO_CTRL_SET_CLOSE: |
259 | wolfSSL_BIO_set_shutdown(bio, (int)num); |
260 | break; |
261 | case BIO_CTRL_FLUSH: |
262 | /* we do no delayed writes, but if we ever would, this |
263 | * needs to trigger it. */ |
264 | ret = 1; |
265 | break; |
266 | case BIO_CTRL_DUP: |
267 | ret = 1; |
268 | break; |
269 | #ifdef BIO_CTRL_EOF |
270 | case BIO_CTRL_EOF: |
271 | /* EOF has been reached on input? */ |
272 | return (!cf->next || !cf->next->connected); |
273 | #endif |
274 | default: |
275 | ret = 0; |
276 | break; |
277 | } |
278 | return ret; |
279 | } |
280 | |
281 | static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio, |
282 | const char *buf, int blen) |
283 | { |
284 | struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); |
285 | struct ssl_connect_data *connssl = cf->ctx; |
286 | struct wolfssl_ssl_backend_data *backend = |
287 | (struct wolfssl_ssl_backend_data *)connssl->backend; |
288 | struct Curl_easy *data = CF_DATA_CURRENT(cf); |
289 | ssize_t nwritten; |
290 | CURLcode result = CURLE_OK; |
291 | |
292 | DEBUGASSERT(data); |
293 | nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); |
294 | backend->io_result = result; |
295 | CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d" , |
296 | blen, nwritten, result); |
297 | wolfSSL_BIO_clear_retry_flags(bio); |
298 | if(nwritten < 0 && CURLE_AGAIN == result) |
299 | BIO_set_retry_write(bio); |
300 | return (int)nwritten; |
301 | } |
302 | |
303 | static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) |
304 | { |
305 | struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); |
306 | struct ssl_connect_data *connssl = cf->ctx; |
307 | struct wolfssl_ssl_backend_data *backend = |
308 | (struct wolfssl_ssl_backend_data *)connssl->backend; |
309 | struct Curl_easy *data = CF_DATA_CURRENT(cf); |
310 | ssize_t nread; |
311 | CURLcode result = CURLE_OK; |
312 | |
313 | DEBUGASSERT(data); |
314 | /* OpenSSL catches this case, so should we. */ |
315 | if(!buf) |
316 | return 0; |
317 | |
318 | nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); |
319 | backend->io_result = result; |
320 | CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d" , blen, nread, result); |
321 | wolfSSL_BIO_clear_retry_flags(bio); |
322 | if(nread < 0 && CURLE_AGAIN == result) |
323 | BIO_set_retry_read(bio); |
324 | return (int)nread; |
325 | } |
326 | |
327 | static WOLFSSL_BIO_METHOD *wolfssl_bio_cf_method = NULL; |
328 | |
329 | static void wolfssl_bio_cf_init_methods(void) |
330 | { |
331 | wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO" ); |
332 | wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write); |
333 | wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read); |
334 | wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl); |
335 | wolfSSL_BIO_meth_set_create(wolfssl_bio_cf_method, &wolfssl_bio_cf_create); |
336 | wolfSSL_BIO_meth_set_destroy(wolfssl_bio_cf_method, &wolfssl_bio_cf_destroy); |
337 | } |
338 | |
339 | static void wolfssl_bio_cf_free_methods(void) |
340 | { |
341 | wolfSSL_BIO_meth_free(wolfssl_bio_cf_method); |
342 | } |
343 | |
344 | #else /* USE_BIO_CHAIN */ |
345 | |
346 | #define wolfssl_bio_cf_init_methods() Curl_nop_stmt |
347 | #define wolfssl_bio_cf_free_methods() Curl_nop_stmt |
348 | |
349 | #endif /* !USE_BIO_CHAIN */ |
350 | |
351 | /* |
352 | * This function loads all the client/CA certificates and CRLs. Setup the TLS |
353 | * layer and do all necessary magic. |
354 | */ |
355 | static CURLcode |
356 | wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) |
357 | { |
358 | char *ciphers, *curves; |
359 | struct ssl_connect_data *connssl = cf->ctx; |
360 | struct wolfssl_ssl_backend_data *backend = |
361 | (struct wolfssl_ssl_backend_data *)connssl->backend; |
362 | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
363 | const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; |
364 | const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); |
365 | const char * const ssl_cafile = |
366 | /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ |
367 | (ca_info_blob ? NULL : conn_config->CAfile); |
368 | const char * const ssl_capath = conn_config->CApath; |
369 | WOLFSSL_METHOD* req_method = NULL; |
370 | #ifdef HAVE_LIBOQS |
371 | word16 oqsAlg = 0; |
372 | size_t idx = 0; |
373 | #endif |
374 | #ifdef HAVE_SNI |
375 | bool sni = FALSE; |
376 | #define use_sni(x) sni = (x) |
377 | #else |
378 | #define use_sni(x) Curl_nop_stmt |
379 | #endif |
380 | bool imported_native_ca = false; |
381 | bool imported_ca_info_blob = false; |
382 | |
383 | DEBUGASSERT(backend); |
384 | |
385 | if(connssl->state == ssl_connection_complete) |
386 | return CURLE_OK; |
387 | |
388 | if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) { |
389 | failf(data, "wolfSSL does not support to set maximum SSL/TLS version" ); |
390 | return CURLE_SSL_CONNECT_ERROR; |
391 | } |
392 | |
393 | /* check to see if we've been told to use an explicit SSL/TLS version */ |
394 | switch(conn_config->version) { |
395 | case CURL_SSLVERSION_DEFAULT: |
396 | case CURL_SSLVERSION_TLSv1: |
397 | #if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ |
398 | /* minimum protocol version is set later after the CTX object is created */ |
399 | req_method = SSLv23_client_method(); |
400 | #else |
401 | infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " |
402 | "TLS 1.0 is used exclusively" ); |
403 | req_method = TLSv1_client_method(); |
404 | #endif |
405 | use_sni(TRUE); |
406 | break; |
407 | case CURL_SSLVERSION_TLSv1_0: |
408 | #if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS) |
409 | req_method = TLSv1_client_method(); |
410 | use_sni(TRUE); |
411 | #else |
412 | failf(data, "wolfSSL does not support TLS 1.0" ); |
413 | return CURLE_NOT_BUILT_IN; |
414 | #endif |
415 | break; |
416 | case CURL_SSLVERSION_TLSv1_1: |
417 | #ifndef NO_OLD_TLS |
418 | req_method = TLSv1_1_client_method(); |
419 | use_sni(TRUE); |
420 | #else |
421 | failf(data, "wolfSSL does not support TLS 1.1" ); |
422 | return CURLE_NOT_BUILT_IN; |
423 | #endif |
424 | break; |
425 | case CURL_SSLVERSION_TLSv1_2: |
426 | #ifndef WOLFSSL_NO_TLS12 |
427 | req_method = TLSv1_2_client_method(); |
428 | use_sni(TRUE); |
429 | #else |
430 | failf(data, "wolfSSL does not support TLS 1.2" ); |
431 | return CURLE_NOT_BUILT_IN; |
432 | #endif |
433 | break; |
434 | case CURL_SSLVERSION_TLSv1_3: |
435 | #ifdef WOLFSSL_TLS13 |
436 | req_method = wolfTLSv1_3_client_method(); |
437 | use_sni(TRUE); |
438 | break; |
439 | #else |
440 | failf(data, "wolfSSL: TLS 1.3 is not yet supported" ); |
441 | return CURLE_SSL_CONNECT_ERROR; |
442 | #endif |
443 | default: |
444 | failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION" ); |
445 | return CURLE_SSL_CONNECT_ERROR; |
446 | } |
447 | |
448 | if(!req_method) { |
449 | failf(data, "SSL: couldn't create a method" ); |
450 | return CURLE_OUT_OF_MEMORY; |
451 | } |
452 | |
453 | if(backend->ctx) |
454 | wolfSSL_CTX_free(backend->ctx); |
455 | backend->ctx = wolfSSL_CTX_new(req_method); |
456 | |
457 | if(!backend->ctx) { |
458 | failf(data, "SSL: couldn't create a context" ); |
459 | return CURLE_OUT_OF_MEMORY; |
460 | } |
461 | |
462 | switch(conn_config->version) { |
463 | case CURL_SSLVERSION_DEFAULT: |
464 | case CURL_SSLVERSION_TLSv1: |
465 | #if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ |
466 | /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is |
467 | * whatever minimum version of TLS was built in and at least TLS 1.0. For |
468 | * later library versions that could change (eg TLS 1.0 built in but |
469 | * defaults to TLS 1.1) so we have this short circuit evaluation to find |
470 | * the minimum supported TLS version. |
471 | */ |
472 | if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) && |
473 | (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) && |
474 | (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1) |
475 | #ifdef WOLFSSL_TLS13 |
476 | && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1) |
477 | #endif |
478 | ) { |
479 | failf(data, "SSL: couldn't set the minimum protocol version" ); |
480 | return CURLE_SSL_CONNECT_ERROR; |
481 | } |
482 | #endif |
483 | break; |
484 | } |
485 | |
486 | ciphers = conn_config->cipher_list; |
487 | if(ciphers) { |
488 | if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) { |
489 | failf(data, "failed setting cipher list: %s" , ciphers); |
490 | return CURLE_SSL_CIPHER; |
491 | } |
492 | infof(data, "Cipher selection: %s" , ciphers); |
493 | } |
494 | |
495 | curves = conn_config->curves; |
496 | if(curves) { |
497 | |
498 | #ifdef HAVE_LIBOQS |
499 | for(idx = 0; gnm[idx].name != NULL; idx++) { |
500 | if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) { |
501 | oqsAlg = gnm[idx].group; |
502 | break; |
503 | } |
504 | } |
505 | |
506 | if(oqsAlg == 0) |
507 | #endif |
508 | { |
509 | if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) { |
510 | failf(data, "failed setting curves list: '%s'" , curves); |
511 | return CURLE_SSL_CIPHER; |
512 | } |
513 | } |
514 | } |
515 | |
516 | #ifndef NO_FILESYSTEM |
517 | /* load native CA certificates */ |
518 | if(ssl_config->native_ca_store) { |
519 | if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) { |
520 | infof(data, "error importing native CA store, continuing anyway" ); |
521 | } |
522 | else { |
523 | imported_native_ca = true; |
524 | infof(data, "successfully imported native CA store" ); |
525 | } |
526 | } |
527 | #endif /* !NO_FILESYSTEM */ |
528 | |
529 | /* load certificate blob */ |
530 | if(ca_info_blob) { |
531 | if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data, |
532 | ca_info_blob->len, |
533 | SSL_FILETYPE_PEM) != SSL_SUCCESS) { |
534 | if(imported_native_ca) { |
535 | infof(data, "error importing CA certificate blob, continuing anyway" ); |
536 | } |
537 | else { |
538 | failf(data, "error importing CA certificate blob" ); |
539 | return CURLE_SSL_CACERT_BADFILE; |
540 | } |
541 | } |
542 | else { |
543 | imported_ca_info_blob = true; |
544 | infof(data, "successfully imported CA certificate blob" ); |
545 | } |
546 | } |
547 | |
548 | #ifndef NO_FILESYSTEM |
549 | /* load trusted cacert from file if not blob */ |
550 | if(ssl_cafile || ssl_capath) { |
551 | int rc = |
552 | wolfSSL_CTX_load_verify_locations_ex(backend->ctx, |
553 | ssl_cafile, |
554 | ssl_capath, |
555 | WOLFSSL_LOAD_FLAG_IGNORE_ERR); |
556 | if(SSL_SUCCESS != rc) { |
557 | if(conn_config->verifypeer && !imported_ca_info_blob && |
558 | !imported_native_ca) { |
559 | /* Fail if we insist on successfully verifying the server. */ |
560 | failf(data, "error setting certificate verify locations:" |
561 | " CAfile: %s CApath: %s" , |
562 | ssl_cafile ? ssl_cafile : "none" , |
563 | ssl_capath ? ssl_capath : "none" ); |
564 | return CURLE_SSL_CACERT_BADFILE; |
565 | } |
566 | else { |
567 | /* Just continue with a warning if no strict certificate |
568 | verification is required. */ |
569 | infof(data, "error setting certificate verify locations," |
570 | " continuing anyway:" ); |
571 | } |
572 | } |
573 | else { |
574 | /* Everything is fine. */ |
575 | infof(data, "successfully set certificate verify locations:" ); |
576 | } |
577 | infof(data, " CAfile: %s" , ssl_cafile ? ssl_cafile : "none" ); |
578 | infof(data, " CApath: %s" , ssl_capath ? ssl_capath : "none" ); |
579 | } |
580 | |
581 | /* Load the client certificate, and private key */ |
582 | if(ssl_config->primary.clientcert && ssl_config->key) { |
583 | int file_type = do_file_type(ssl_config->cert_type); |
584 | |
585 | if(wolfSSL_CTX_use_certificate_file(backend->ctx, |
586 | ssl_config->primary.clientcert, |
587 | file_type) != 1) { |
588 | failf(data, "unable to use client certificate (no key or wrong pass" |
589 | " phrase?)" ); |
590 | return CURLE_SSL_CONNECT_ERROR; |
591 | } |
592 | |
593 | file_type = do_file_type(ssl_config->key_type); |
594 | if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key, |
595 | file_type) != 1) { |
596 | failf(data, "unable to set private key" ); |
597 | return CURLE_SSL_CONNECT_ERROR; |
598 | } |
599 | } |
600 | #endif /* !NO_FILESYSTEM */ |
601 | |
602 | /* SSL always tries to verify the peer, this only says whether it should |
603 | * fail to connect if the verification fails, or if it should continue |
604 | * anyway. In the latter case the result of the verification is checked with |
605 | * SSL_get_verify_result() below. */ |
606 | wolfSSL_CTX_set_verify(backend->ctx, |
607 | conn_config->verifypeer?SSL_VERIFY_PEER: |
608 | SSL_VERIFY_NONE, NULL); |
609 | |
610 | #ifdef HAVE_SNI |
611 | if(sni) { |
612 | struct in_addr addr4; |
613 | #ifdef ENABLE_IPV6 |
614 | struct in6_addr addr6; |
615 | #endif |
616 | size_t hostname_len = strlen(connssl->hostname); |
617 | |
618 | if((hostname_len < USHRT_MAX) && |
619 | !Curl_inet_pton(AF_INET, connssl->hostname, &addr4) |
620 | #ifdef ENABLE_IPV6 |
621 | && !Curl_inet_pton(AF_INET6, connssl->hostname, &addr6) |
622 | #endif |
623 | ) { |
624 | size_t snilen; |
625 | char *snihost = Curl_ssl_snihost(data, connssl->hostname, &snilen); |
626 | if(!snihost || |
627 | wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, snihost, |
628 | (unsigned short)snilen) != 1) { |
629 | failf(data, "Failed to set SNI" ); |
630 | return CURLE_SSL_CONNECT_ERROR; |
631 | } |
632 | } |
633 | } |
634 | #endif |
635 | |
636 | /* give application a chance to interfere with SSL set up. */ |
637 | if(data->set.ssl.fsslctx) { |
638 | CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx, |
639 | data->set.ssl.fsslctxp); |
640 | if(result) { |
641 | failf(data, "error signaled by ssl ctx callback" ); |
642 | return result; |
643 | } |
644 | } |
645 | #ifdef NO_FILESYSTEM |
646 | else if(conn_config->verifypeer) { |
647 | failf(data, "SSL: Certificates can't be loaded because wolfSSL was built" |
648 | " with \"no filesystem\". Either disable peer verification" |
649 | " (insecure) or if you are building an application with libcurl you" |
650 | " can load certificates via CURLOPT_SSL_CTX_FUNCTION." ); |
651 | return CURLE_SSL_CONNECT_ERROR; |
652 | } |
653 | #endif |
654 | |
655 | /* Let's make an SSL structure */ |
656 | if(backend->handle) |
657 | wolfSSL_free(backend->handle); |
658 | backend->handle = wolfSSL_new(backend->ctx); |
659 | if(!backend->handle) { |
660 | failf(data, "SSL: couldn't create a handle" ); |
661 | return CURLE_OUT_OF_MEMORY; |
662 | } |
663 | |
664 | #ifdef HAVE_LIBOQS |
665 | if(oqsAlg) { |
666 | if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) { |
667 | failf(data, "unable to use oqs KEM" ); |
668 | } |
669 | } |
670 | #endif |
671 | |
672 | #ifdef HAVE_ALPN |
673 | if(connssl->alpn) { |
674 | struct alpn_proto_buf proto; |
675 | CURLcode result; |
676 | |
677 | result = Curl_alpn_to_proto_str(&proto, connssl->alpn); |
678 | if(result || |
679 | wolfSSL_UseALPN(backend->handle, (char *)proto.data, proto.len, |
680 | WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { |
681 | failf(data, "SSL: failed setting ALPN protocols" ); |
682 | return CURLE_SSL_CONNECT_ERROR; |
683 | } |
684 | infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); |
685 | } |
686 | #endif /* HAVE_ALPN */ |
687 | |
688 | #ifdef OPENSSL_EXTRA |
689 | if(Curl_tls_keylog_enabled()) { |
690 | /* Ensure the Client Random is preserved. */ |
691 | wolfSSL_KeepArrays(backend->handle); |
692 | #if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) |
693 | wolfSSL_set_tls13_secret_cb(backend->handle, |
694 | wolfssl_tls13_secret_callback, NULL); |
695 | #endif |
696 | } |
697 | #endif /* OPENSSL_EXTRA */ |
698 | |
699 | #ifdef HAVE_SECURE_RENEGOTIATION |
700 | if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) { |
701 | failf(data, "SSL: failed setting secure renegotiation" ); |
702 | return CURLE_SSL_CONNECT_ERROR; |
703 | } |
704 | #endif /* HAVE_SECURE_RENEGOTIATION */ |
705 | |
706 | /* Check if there's a cached ID we can/should use here! */ |
707 | if(ssl_config->primary.sessionid) { |
708 | void *ssl_sessionid = NULL; |
709 | |
710 | Curl_ssl_sessionid_lock(data); |
711 | if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) { |
712 | /* we got a session id, use it! */ |
713 | if(!SSL_set_session(backend->handle, ssl_sessionid)) { |
714 | Curl_ssl_delsessionid(data, ssl_sessionid); |
715 | infof(data, "Can't use session ID, going on without" ); |
716 | } |
717 | else |
718 | infof(data, "SSL reusing session ID" ); |
719 | } |
720 | Curl_ssl_sessionid_unlock(data); |
721 | } |
722 | |
723 | #ifdef USE_BIO_CHAIN |
724 | { |
725 | WOLFSSL_BIO *bio; |
726 | |
727 | bio = BIO_new(wolfssl_bio_cf_method); |
728 | if(!bio) |
729 | return CURLE_OUT_OF_MEMORY; |
730 | |
731 | wolfSSL_BIO_set_data(bio, cf); |
732 | wolfSSL_set_bio(backend->handle, bio, bio); |
733 | } |
734 | #else /* USE_BIO_CHAIN */ |
735 | /* pass the raw socket into the SSL layer */ |
736 | if(!wolfSSL_set_fd(backend->handle, |
737 | (int)Curl_conn_cf_get_socket(cf, data))) { |
738 | failf(data, "SSL: SSL_set_fd failed" ); |
739 | return CURLE_SSL_CONNECT_ERROR; |
740 | } |
741 | #endif /* !USE_BIO_CHAIN */ |
742 | |
743 | connssl->connecting_state = ssl_connect_2; |
744 | return CURLE_OK; |
745 | } |
746 | |
747 | |
748 | static CURLcode |
749 | wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) |
750 | { |
751 | int ret = -1; |
752 | struct ssl_connect_data *connssl = cf->ctx; |
753 | struct wolfssl_ssl_backend_data *backend = |
754 | (struct wolfssl_ssl_backend_data *)connssl->backend; |
755 | struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); |
756 | const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)? |
757 | data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]: |
758 | data->set.str[STRING_SSL_PINNEDPUBLICKEY]; |
759 | |
760 | DEBUGASSERT(backend); |
761 | |
762 | wolfSSL_ERR_clear_error(); |
763 | |
764 | /* Enable RFC2818 checks */ |
765 | if(conn_config->verifyhost) { |
766 | char *snihost = Curl_ssl_snihost(data, connssl->hostname, NULL); |
767 | if(!snihost || |
768 | (wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)) |
769 | return CURLE_SSL_CONNECT_ERROR; |
770 | } |
771 | |
772 | ret = wolfSSL_connect(backend->handle); |
773 | |
774 | #ifdef OPENSSL_EXTRA |
775 | if(Curl_tls_keylog_enabled()) { |
776 | /* If key logging is enabled, wait for the handshake to complete and then |
777 | * proceed with logging secrets (for TLS 1.2 or older). |
778 | * |
779 | * During the handshake (ret==-1), wolfSSL_want_read() is true as it waits |
780 | * for the server response. At that point the master secret is not yet |
781 | * available, so we must not try to read it. |
782 | * To log the secret on completion with a handshake failure, detect |
783 | * completion via the observation that there is nothing to read or write. |
784 | * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever |
785 | * changes, the worst case is that no key is logged on error. |
786 | */ |
787 | if(ret == SSL_SUCCESS || |
788 | (!wolfSSL_want_read(backend->handle) && |
789 | !wolfSSL_want_write(backend->handle))) { |
790 | wolfssl_log_tls12_secret(backend->handle); |
791 | /* Client Random and master secrets are no longer needed, erase these. |
792 | * Ignored while the handshake is still in progress. */ |
793 | wolfSSL_FreeArrays(backend->handle); |
794 | } |
795 | } |
796 | #endif /* OPENSSL_EXTRA */ |
797 | |
798 | if(ret != 1) { |
799 | char error_buffer[WOLFSSL_MAX_ERROR_SZ]; |
800 | int detail = wolfSSL_get_error(backend->handle, ret); |
801 | |
802 | if(SSL_ERROR_WANT_READ == detail) { |
803 | connssl->connecting_state = ssl_connect_2_reading; |
804 | return CURLE_OK; |
805 | } |
806 | else if(SSL_ERROR_WANT_WRITE == detail) { |
807 | connssl->connecting_state = ssl_connect_2_writing; |
808 | return CURLE_OK; |
809 | } |
810 | /* There is no easy way to override only the CN matching. |
811 | * This will enable the override of both mismatching SubjectAltNames |
812 | * as also mismatching CN fields */ |
813 | else if(DOMAIN_NAME_MISMATCH == detail) { |
814 | #if 1 |
815 | failf(data, " subject alt name(s) or common name do not match \"%s\"" , |
816 | connssl->dispname); |
817 | return CURLE_PEER_FAILED_VERIFICATION; |
818 | #else |
819 | /* When the wolfssl_check_domain_name() is used and you desire to |
820 | * continue on a DOMAIN_NAME_MISMATCH, i.e. 'ssl_config.verifyhost |
821 | * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA |
822 | * error. The only way to do this is currently to switch the |
823 | * Wolfssl_check_domain_name() in and out based on the |
824 | * 'ssl_config.verifyhost' value. */ |
825 | if(conn_config->verifyhost) { |
826 | failf(data, |
827 | " subject alt name(s) or common name do not match \"%s\"\n" , |
828 | connssl->dispname); |
829 | return CURLE_PEER_FAILED_VERIFICATION; |
830 | } |
831 | else { |
832 | infof(data, |
833 | " subject alt name(s) and/or common name do not match \"%s\"" , |
834 | connssl->dispname); |
835 | return CURLE_OK; |
836 | } |
837 | #endif |
838 | } |
839 | #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ |
840 | else if(ASN_NO_SIGNER_E == detail) { |
841 | if(conn_config->verifypeer) { |
842 | failf(data, " CA signer not available for verification" ); |
843 | return CURLE_SSL_CACERT_BADFILE; |
844 | } |
845 | else { |
846 | /* Just continue with a warning if no strict certificate |
847 | verification is required. */ |
848 | infof(data, "CA signer not available for verification, " |
849 | "continuing anyway" ); |
850 | } |
851 | } |
852 | #endif |
853 | else if(backend->io_result == CURLE_AGAIN) { |
854 | return CURLE_OK; |
855 | } |
856 | else { |
857 | failf(data, "SSL_connect failed with error %d: %s" , detail, |
858 | wolfSSL_ERR_error_string(detail, error_buffer)); |
859 | return CURLE_SSL_CONNECT_ERROR; |
860 | } |
861 | } |
862 | |
863 | if(pinnedpubkey) { |
864 | #ifdef KEEP_PEER_CERT |
865 | X509 *x509; |
866 | const char *x509_der; |
867 | int x509_der_len; |
868 | struct Curl_X509certificate x509_parsed; |
869 | struct Curl_asn1Element *pubkey; |
870 | CURLcode result; |
871 | |
872 | x509 = wolfSSL_get_peer_certificate(backend->handle); |
873 | if(!x509) { |
874 | failf(data, "SSL: failed retrieving server certificate" ); |
875 | return CURLE_SSL_PINNEDPUBKEYNOTMATCH; |
876 | } |
877 | |
878 | x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len); |
879 | if(!x509_der) { |
880 | failf(data, "SSL: failed retrieving ASN.1 server certificate" ); |
881 | return CURLE_SSL_PINNEDPUBKEYNOTMATCH; |
882 | } |
883 | |
884 | memset(&x509_parsed, 0, sizeof(x509_parsed)); |
885 | if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len)) |
886 | return CURLE_SSL_PINNEDPUBKEYNOTMATCH; |
887 | |
888 | pubkey = &x509_parsed.subjectPublicKeyInfo; |
889 | if(!pubkey->header || pubkey->end <= pubkey->header) { |
890 | failf(data, "SSL: failed retrieving public key from server certificate" ); |
891 | return CURLE_SSL_PINNEDPUBKEYNOTMATCH; |
892 | } |
893 | |
894 | result = Curl_pin_peer_pubkey(data, |
895 | pinnedpubkey, |
896 | (const unsigned char *)pubkey->header, |
897 | (size_t)(pubkey->end - pubkey->header)); |
898 | if(result) { |
899 | failf(data, "SSL: public key does not match pinned public key" ); |
900 | return result; |
901 | } |
902 | #else |
903 | failf(data, "Library lacks pinning support built-in" ); |
904 | return CURLE_NOT_BUILT_IN; |
905 | #endif |
906 | } |
907 | |
908 | #ifdef HAVE_ALPN |
909 | if(connssl->alpn) { |
910 | int rc; |
911 | char *protocol = NULL; |
912 | unsigned short protocol_len = 0; |
913 | |
914 | rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len); |
915 | |
916 | if(rc == SSL_SUCCESS) { |
917 | Curl_alpn_set_negotiated(cf, data, (const unsigned char *)protocol, |
918 | protocol_len); |
919 | } |
920 | else if(rc == SSL_ALPN_NOT_FOUND) |
921 | Curl_alpn_set_negotiated(cf, data, NULL, 0); |
922 | else { |
923 | failf(data, "ALPN, failure getting protocol, error %d" , rc); |
924 | return CURLE_SSL_CONNECT_ERROR; |
925 | } |
926 | } |
927 | #endif /* HAVE_ALPN */ |
928 | |
929 | connssl->connecting_state = ssl_connect_3; |
930 | #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010) |
931 | infof(data, "SSL connection using %s / %s" , |
932 | wolfSSL_get_version(backend->handle), |
933 | wolfSSL_get_cipher_name(backend->handle)); |
934 | #else |
935 | infof(data, "SSL connected" ); |
936 | #endif |
937 | |
938 | return CURLE_OK; |
939 | } |
940 | |
941 | |
942 | static CURLcode |
943 | wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) |
944 | { |
945 | CURLcode result = CURLE_OK; |
946 | struct ssl_connect_data *connssl = cf->ctx; |
947 | struct wolfssl_ssl_backend_data *backend = |
948 | (struct wolfssl_ssl_backend_data *)connssl->backend; |
949 | const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); |
950 | |
951 | DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); |
952 | DEBUGASSERT(backend); |
953 | |
954 | if(ssl_config->primary.sessionid) { |
955 | bool incache; |
956 | bool added = FALSE; |
957 | void *old_ssl_sessionid = NULL; |
958 | /* wolfSSL_get1_session allocates memory that has to be freed. */ |
959 | WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle); |
960 | |
961 | if(our_ssl_sessionid) { |
962 | Curl_ssl_sessionid_lock(data); |
963 | incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL)); |
964 | if(incache) { |
965 | if(old_ssl_sessionid != our_ssl_sessionid) { |
966 | infof(data, "old SSL session ID is stale, removing" ); |
967 | Curl_ssl_delsessionid(data, old_ssl_sessionid); |
968 | incache = FALSE; |
969 | } |
970 | } |
971 | |
972 | if(!incache) { |
973 | result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL); |
974 | if(result) { |
975 | Curl_ssl_sessionid_unlock(data); |
976 | wolfSSL_SESSION_free(our_ssl_sessionid); |
977 | failf(data, "failed to store ssl session" ); |
978 | return result; |
979 | } |
980 | else { |
981 | added = TRUE; |
982 | } |
983 | } |
984 | Curl_ssl_sessionid_unlock(data); |
985 | |
986 | if(!added) { |
987 | /* If the session info wasn't added to the cache, free our copy. */ |
988 | wolfSSL_SESSION_free(our_ssl_sessionid); |
989 | } |
990 | } |
991 | } |
992 | |
993 | connssl->connecting_state = ssl_connect_done; |
994 | |
995 | return result; |
996 | } |
997 | |
998 | |
999 | static ssize_t wolfssl_send(struct Curl_cfilter *cf, |
1000 | struct Curl_easy *data, |
1001 | const void *mem, |
1002 | size_t len, |
1003 | CURLcode *curlcode) |
1004 | { |
1005 | struct ssl_connect_data *connssl = cf->ctx; |
1006 | struct wolfssl_ssl_backend_data *backend = |
1007 | (struct wolfssl_ssl_backend_data *)connssl->backend; |
1008 | char error_buffer[WOLFSSL_MAX_ERROR_SZ]; |
1009 | int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; |
1010 | int rc; |
1011 | |
1012 | DEBUGASSERT(backend); |
1013 | |
1014 | wolfSSL_ERR_clear_error(); |
1015 | |
1016 | rc = wolfSSL_write(backend->handle, mem, memlen); |
1017 | if(rc <= 0) { |
1018 | int err = wolfSSL_get_error(backend->handle, rc); |
1019 | |
1020 | switch(err) { |
1021 | case SSL_ERROR_WANT_READ: |
1022 | case SSL_ERROR_WANT_WRITE: |
1023 | /* there's data pending, re-invoke SSL_write() */ |
1024 | CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN" , len); |
1025 | *curlcode = CURLE_AGAIN; |
1026 | return -1; |
1027 | default: |
1028 | if(backend->io_result == CURLE_AGAIN) { |
1029 | CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN" , len); |
1030 | *curlcode = CURLE_AGAIN; |
1031 | return -1; |
1032 | } |
1033 | CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d" , len, rc, err); |
1034 | failf(data, "SSL write: %s, errno %d" , |
1035 | wolfSSL_ERR_error_string(err, error_buffer), |
1036 | SOCKERRNO); |
1037 | *curlcode = CURLE_SEND_ERROR; |
1038 | return -1; |
1039 | } |
1040 | } |
1041 | CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d" , len, rc); |
1042 | return rc; |
1043 | } |
1044 | |
1045 | static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) |
1046 | { |
1047 | struct ssl_connect_data *connssl = cf->ctx; |
1048 | struct wolfssl_ssl_backend_data *backend = |
1049 | (struct wolfssl_ssl_backend_data *)connssl->backend; |
1050 | |
1051 | (void) data; |
1052 | |
1053 | DEBUGASSERT(backend); |
1054 | |
1055 | if(backend->handle) { |
1056 | char buf[32]; |
1057 | /* Maybe the server has already sent a close notify alert. |
1058 | Read it to avoid an RST on the TCP connection. */ |
1059 | (void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf)); |
1060 | (void)wolfSSL_shutdown(backend->handle); |
1061 | wolfSSL_free(backend->handle); |
1062 | backend->handle = NULL; |
1063 | } |
1064 | if(backend->ctx) { |
1065 | wolfSSL_CTX_free(backend->ctx); |
1066 | backend->ctx = NULL; |
1067 | } |
1068 | } |
1069 | |
1070 | static ssize_t wolfssl_recv(struct Curl_cfilter *cf, |
1071 | struct Curl_easy *data, |
1072 | char *buf, size_t blen, |
1073 | CURLcode *curlcode) |
1074 | { |
1075 | struct ssl_connect_data *connssl = cf->ctx; |
1076 | struct wolfssl_ssl_backend_data *backend = |
1077 | (struct wolfssl_ssl_backend_data *)connssl->backend; |
1078 | char error_buffer[WOLFSSL_MAX_ERROR_SZ]; |
1079 | int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen; |
1080 | int nread; |
1081 | |
1082 | DEBUGASSERT(backend); |
1083 | |
1084 | wolfSSL_ERR_clear_error(); |
1085 | *curlcode = CURLE_OK; |
1086 | |
1087 | nread = wolfSSL_read(backend->handle, buf, buffsize); |
1088 | |
1089 | if(nread <= 0) { |
1090 | int err = wolfSSL_get_error(backend->handle, nread); |
1091 | |
1092 | switch(err) { |
1093 | case SSL_ERROR_ZERO_RETURN: /* no more data */ |
1094 | CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED" , blen); |
1095 | *curlcode = CURLE_OK; |
1096 | return 0; |
1097 | case SSL_ERROR_NONE: |
1098 | /* FALLTHROUGH */ |
1099 | case SSL_ERROR_WANT_READ: |
1100 | /* FALLTHROUGH */ |
1101 | case SSL_ERROR_WANT_WRITE: |
1102 | /* there's data pending, re-invoke wolfSSL_read() */ |
1103 | CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN" , blen); |
1104 | *curlcode = CURLE_AGAIN; |
1105 | return -1; |
1106 | default: |
1107 | if(backend->io_result == CURLE_AGAIN) { |
1108 | CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN" , blen); |
1109 | *curlcode = CURLE_AGAIN; |
1110 | return -1; |
1111 | } |
1112 | failf(data, "SSL read: %s, errno %d" , |
1113 | wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO); |
1114 | *curlcode = CURLE_RECV_ERROR; |
1115 | return -1; |
1116 | } |
1117 | } |
1118 | CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> %d" , blen, nread); |
1119 | return nread; |
1120 | } |
1121 | |
1122 | |
1123 | static void wolfssl_session_free(void *ptr) |
1124 | { |
1125 | wolfSSL_SESSION_free(ptr); |
1126 | } |
1127 | |
1128 | |
1129 | static size_t wolfssl_version(char *buffer, size_t size) |
1130 | { |
1131 | #if LIBWOLFSSL_VERSION_HEX >= 0x03006000 |
1132 | return msnprintf(buffer, size, "wolfSSL/%s" , wolfSSL_lib_version()); |
1133 | #elif defined(WOLFSSL_VERSION) |
1134 | return msnprintf(buffer, size, "wolfSSL/%s" , WOLFSSL_VERSION); |
1135 | #endif |
1136 | } |
1137 | |
1138 | |
1139 | static int wolfssl_init(void) |
1140 | { |
1141 | int ret; |
1142 | |
1143 | #ifdef OPENSSL_EXTRA |
1144 | Curl_tls_keylog_open(); |
1145 | #endif |
1146 | ret = (wolfSSL_Init() == SSL_SUCCESS); |
1147 | wolfssl_bio_cf_init_methods(); |
1148 | return ret; |
1149 | } |
1150 | |
1151 | |
1152 | static void wolfssl_cleanup(void) |
1153 | { |
1154 | wolfssl_bio_cf_free_methods(); |
1155 | wolfSSL_Cleanup(); |
1156 | #ifdef OPENSSL_EXTRA |
1157 | Curl_tls_keylog_close(); |
1158 | #endif |
1159 | } |
1160 | |
1161 | |
1162 | static bool wolfssl_data_pending(struct Curl_cfilter *cf, |
1163 | const struct Curl_easy *data) |
1164 | { |
1165 | struct ssl_connect_data *ctx = cf->ctx; |
1166 | struct wolfssl_ssl_backend_data *backend; |
1167 | |
1168 | (void)data; |
1169 | DEBUGASSERT(ctx && ctx->backend); |
1170 | |
1171 | backend = (struct wolfssl_ssl_backend_data *)ctx->backend; |
1172 | if(backend->handle) /* SSL is in use */ |
1173 | return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE; |
1174 | else |
1175 | return FALSE; |
1176 | } |
1177 | |
1178 | |
1179 | /* |
1180 | * This function is called to shut down the SSL layer but keep the |
1181 | * socket open (CCC - Clear Command Channel) |
1182 | */ |
1183 | static int wolfssl_shutdown(struct Curl_cfilter *cf, |
1184 | struct Curl_easy *data) |
1185 | { |
1186 | struct ssl_connect_data *ctx = cf->ctx; |
1187 | struct wolfssl_ssl_backend_data *backend; |
1188 | int retval = 0; |
1189 | |
1190 | (void)data; |
1191 | DEBUGASSERT(ctx && ctx->backend); |
1192 | |
1193 | backend = (struct wolfssl_ssl_backend_data *)ctx->backend; |
1194 | if(backend->handle) { |
1195 | wolfSSL_ERR_clear_error(); |
1196 | wolfSSL_free(backend->handle); |
1197 | backend->handle = NULL; |
1198 | } |
1199 | return retval; |
1200 | } |
1201 | |
1202 | |
1203 | static CURLcode |
1204 | wolfssl_connect_common(struct Curl_cfilter *cf, |
1205 | struct Curl_easy *data, |
1206 | bool nonblocking, |
1207 | bool *done) |
1208 | { |
1209 | CURLcode result; |
1210 | struct ssl_connect_data *connssl = cf->ctx; |
1211 | curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); |
1212 | int what; |
1213 | |
1214 | /* check if the connection has already been established */ |
1215 | if(ssl_connection_complete == connssl->state) { |
1216 | *done = TRUE; |
1217 | return CURLE_OK; |
1218 | } |
1219 | |
1220 | if(ssl_connect_1 == connssl->connecting_state) { |
1221 | /* Find out how much more time we're allowed */ |
1222 | const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); |
1223 | |
1224 | if(timeout_ms < 0) { |
1225 | /* no need to continue if time already is up */ |
1226 | failf(data, "SSL connection timeout" ); |
1227 | return CURLE_OPERATION_TIMEDOUT; |
1228 | } |
1229 | |
1230 | result = wolfssl_connect_step1(cf, data); |
1231 | if(result) |
1232 | return result; |
1233 | } |
1234 | |
1235 | while(ssl_connect_2 == connssl->connecting_state || |
1236 | ssl_connect_2_reading == connssl->connecting_state || |
1237 | ssl_connect_2_writing == connssl->connecting_state) { |
1238 | |
1239 | /* check allowed time left */ |
1240 | const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); |
1241 | |
1242 | if(timeout_ms < 0) { |
1243 | /* no need to continue if time already is up */ |
1244 | failf(data, "SSL connection timeout" ); |
1245 | return CURLE_OPERATION_TIMEDOUT; |
1246 | } |
1247 | |
1248 | /* if ssl is expecting something, check if it's available. */ |
1249 | if(connssl->connecting_state == ssl_connect_2_reading |
1250 | || connssl->connecting_state == ssl_connect_2_writing) { |
1251 | |
1252 | curl_socket_t writefd = ssl_connect_2_writing == |
1253 | connssl->connecting_state?sockfd:CURL_SOCKET_BAD; |
1254 | curl_socket_t readfd = ssl_connect_2_reading == |
1255 | connssl->connecting_state?sockfd:CURL_SOCKET_BAD; |
1256 | |
1257 | what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, |
1258 | nonblocking?0:timeout_ms); |
1259 | if(what < 0) { |
1260 | /* fatal error */ |
1261 | failf(data, "select/poll on SSL socket, errno: %d" , SOCKERRNO); |
1262 | return CURLE_SSL_CONNECT_ERROR; |
1263 | } |
1264 | else if(0 == what) { |
1265 | if(nonblocking) { |
1266 | *done = FALSE; |
1267 | return CURLE_OK; |
1268 | } |
1269 | else { |
1270 | /* timeout */ |
1271 | failf(data, "SSL connection timeout" ); |
1272 | return CURLE_OPERATION_TIMEDOUT; |
1273 | } |
1274 | } |
1275 | /* socket is readable or writable */ |
1276 | } |
1277 | |
1278 | /* Run transaction, and return to the caller if it failed or if |
1279 | * this connection is part of a multi handle and this loop would |
1280 | * execute again. This permits the owner of a multi handle to |
1281 | * abort a connection attempt before step2 has completed while |
1282 | * ensuring that a client using select() or epoll() will always |
1283 | * have a valid fdset to wait on. |
1284 | */ |
1285 | result = wolfssl_connect_step2(cf, data); |
1286 | if(result || (nonblocking && |
1287 | (ssl_connect_2 == connssl->connecting_state || |
1288 | ssl_connect_2_reading == connssl->connecting_state || |
1289 | ssl_connect_2_writing == connssl->connecting_state))) |
1290 | return result; |
1291 | } /* repeat step2 until all transactions are done. */ |
1292 | |
1293 | if(ssl_connect_3 == connssl->connecting_state) { |
1294 | result = wolfssl_connect_step3(cf, data); |
1295 | if(result) |
1296 | return result; |
1297 | } |
1298 | |
1299 | if(ssl_connect_done == connssl->connecting_state) { |
1300 | connssl->state = ssl_connection_complete; |
1301 | *done = TRUE; |
1302 | } |
1303 | else |
1304 | *done = FALSE; |
1305 | |
1306 | /* Reset our connect state machine */ |
1307 | connssl->connecting_state = ssl_connect_1; |
1308 | |
1309 | return CURLE_OK; |
1310 | } |
1311 | |
1312 | |
1313 | static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf, |
1314 | struct Curl_easy *data, |
1315 | bool *done) |
1316 | { |
1317 | return wolfssl_connect_common(cf, data, TRUE, done); |
1318 | } |
1319 | |
1320 | |
1321 | static CURLcode wolfssl_connect(struct Curl_cfilter *cf, |
1322 | struct Curl_easy *data) |
1323 | { |
1324 | CURLcode result; |
1325 | bool done = FALSE; |
1326 | |
1327 | result = wolfssl_connect_common(cf, data, FALSE, &done); |
1328 | if(result) |
1329 | return result; |
1330 | |
1331 | DEBUGASSERT(done); |
1332 | |
1333 | return CURLE_OK; |
1334 | } |
1335 | |
1336 | static CURLcode wolfssl_random(struct Curl_easy *data, |
1337 | unsigned char *entropy, size_t length) |
1338 | { |
1339 | WC_RNG rng; |
1340 | (void)data; |
1341 | if(wc_InitRng(&rng)) |
1342 | return CURLE_FAILED_INIT; |
1343 | if(length > UINT_MAX) |
1344 | return CURLE_FAILED_INIT; |
1345 | if(wc_RNG_GenerateBlock(&rng, entropy, (unsigned)length)) |
1346 | return CURLE_FAILED_INIT; |
1347 | if(wc_FreeRng(&rng)) |
1348 | return CURLE_FAILED_INIT; |
1349 | return CURLE_OK; |
1350 | } |
1351 | |
1352 | static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */ |
1353 | size_t tmplen, |
1354 | unsigned char *sha256sum /* output */, |
1355 | size_t unused) |
1356 | { |
1357 | wc_Sha256 SHA256pw; |
1358 | (void)unused; |
1359 | if(wc_InitSha256(&SHA256pw)) |
1360 | return CURLE_FAILED_INIT; |
1361 | wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen); |
1362 | wc_Sha256Final(&SHA256pw, sha256sum); |
1363 | return CURLE_OK; |
1364 | } |
1365 | |
1366 | static void *wolfssl_get_internals(struct ssl_connect_data *connssl, |
1367 | CURLINFO info UNUSED_PARAM) |
1368 | { |
1369 | struct wolfssl_ssl_backend_data *backend = |
1370 | (struct wolfssl_ssl_backend_data *)connssl->backend; |
1371 | (void)info; |
1372 | DEBUGASSERT(backend); |
1373 | return backend->handle; |
1374 | } |
1375 | |
1376 | const struct Curl_ssl Curl_ssl_wolfssl = { |
1377 | { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */ |
1378 | |
1379 | #ifdef KEEP_PEER_CERT |
1380 | SSLSUPP_PINNEDPUBKEY | |
1381 | #endif |
1382 | #ifdef USE_BIO_CHAIN |
1383 | SSLSUPP_HTTPS_PROXY | |
1384 | #endif |
1385 | SSLSUPP_CA_PATH | |
1386 | SSLSUPP_CAINFO_BLOB | |
1387 | SSLSUPP_SSL_CTX, |
1388 | |
1389 | sizeof(struct wolfssl_ssl_backend_data), |
1390 | |
1391 | wolfssl_init, /* init */ |
1392 | wolfssl_cleanup, /* cleanup */ |
1393 | wolfssl_version, /* version */ |
1394 | Curl_none_check_cxn, /* check_cxn */ |
1395 | wolfssl_shutdown, /* shutdown */ |
1396 | wolfssl_data_pending, /* data_pending */ |
1397 | wolfssl_random, /* random */ |
1398 | Curl_none_cert_status_request, /* cert_status_request */ |
1399 | wolfssl_connect, /* connect */ |
1400 | wolfssl_connect_nonblocking, /* connect_nonblocking */ |
1401 | Curl_ssl_get_select_socks, /* getsock */ |
1402 | wolfssl_get_internals, /* get_internals */ |
1403 | wolfssl_close, /* close_one */ |
1404 | Curl_none_close_all, /* close_all */ |
1405 | wolfssl_session_free, /* session_free */ |
1406 | Curl_none_set_engine, /* set_engine */ |
1407 | Curl_none_set_engine_default, /* set_engine_default */ |
1408 | Curl_none_engines_list, /* engines_list */ |
1409 | Curl_none_false_start, /* false_start */ |
1410 | wolfssl_sha256sum, /* sha256sum */ |
1411 | NULL, /* associate_connection */ |
1412 | NULL, /* disassociate_connection */ |
1413 | NULL, /* free_multi_ssl_backend_data */ |
1414 | wolfssl_recv, /* recv decrypted data */ |
1415 | wolfssl_send, /* send data to encrypt */ |
1416 | }; |
1417 | |
1418 | #endif |
1419 | |