1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Jacob Hoffman-Andrews,
9 * <github@hoffman-andrews.com>
10 * Copyright (C) kpcyrd, <kpcyrd@archlinux.org>
11 *
12 * This software is licensed as described in the file COPYING, which
13 * you should have received as part of this distribution. The terms
14 * are also available at https://curl.se/docs/copyright.html.
15 *
16 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17 * copies of the Software, and permit persons to whom the Software is
18 * furnished to do so, under the terms of the COPYING file.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 * SPDX-License-Identifier: curl
24 *
25 ***************************************************************************/
26 #include "curl_setup.h"
27
28 #ifdef USE_RUSTLS
29
30 #include "curl_printf.h"
31
32 #include <errno.h>
33 #include <rustls.h>
34
35 #include "inet_pton.h"
36 #include "urldata.h"
37 #include "sendf.h"
38 #include "vtls.h"
39 #include "vtls_int.h"
40 #include "select.h"
41 #include "strerror.h"
42 #include "multiif.h"
43 #include "connect.h" /* for the connect timeout */
44
45 struct rustls_ssl_backend_data
46 {
47 const struct rustls_client_config *config;
48 struct rustls_connection *conn;
49 size_t plain_out_buffered;
50 BIT(data_in_pending);
51 };
52
53 /* For a given rustls_result error code, return the best-matching CURLcode. */
map_error(rustls_result r)54 static CURLcode map_error(rustls_result r)
55 {
56 if(rustls_result_is_cert_error(r)) {
57 return CURLE_PEER_FAILED_VERIFICATION;
58 }
59 switch(r) {
60 case RUSTLS_RESULT_OK:
61 return CURLE_OK;
62 case RUSTLS_RESULT_NULL_PARAMETER:
63 return CURLE_BAD_FUNCTION_ARGUMENT;
64 default:
65 return CURLE_RECV_ERROR;
66 }
67 }
68
69 static bool
cr_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)70 cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
71 {
72 struct ssl_connect_data *ctx = cf->ctx;
73 struct rustls_ssl_backend_data *backend;
74
75 (void)data;
76 DEBUGASSERT(ctx && ctx->backend);
77 backend = (struct rustls_ssl_backend_data *)ctx->backend;
78 return backend->data_in_pending;
79 }
80
81 struct io_ctx {
82 struct Curl_cfilter *cf;
83 struct Curl_easy *data;
84 };
85
86 static int
read_cb(void * userdata,uint8_t * buf,uintptr_t len,uintptr_t * out_n)87 read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
88 {
89 struct io_ctx *io_ctx = userdata;
90 struct ssl_connect_data *const connssl = io_ctx->cf->ctx;
91 CURLcode result;
92 int ret = 0;
93 ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
94 (char *)buf, len, &result);
95 if(nread < 0) {
96 nread = 0;
97 if(CURLE_AGAIN == result)
98 ret = EAGAIN;
99 else
100 ret = EINVAL;
101 }
102 else if(nread == 0)
103 connssl->peer_closed = TRUE;
104 *out_n = (int)nread;
105 CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
106 len, nread, result);
107 return ret;
108 }
109
110 static int
write_cb(void * userdata,const uint8_t * buf,uintptr_t len,uintptr_t * out_n)111 write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
112 {
113 struct io_ctx *io_ctx = userdata;
114 CURLcode result;
115 int ret = 0;
116 ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
117 (const char *)buf, len, &result);
118 if(nwritten < 0) {
119 nwritten = 0;
120 if(CURLE_AGAIN == result)
121 ret = EAGAIN;
122 else
123 ret = EINVAL;
124 }
125 *out_n = (int)nwritten;
126 CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
127 len, nwritten, result);
128 return ret;
129 }
130
tls_recv_more(struct Curl_cfilter * cf,struct Curl_easy * data,CURLcode * err)131 static ssize_t tls_recv_more(struct Curl_cfilter *cf,
132 struct Curl_easy *data, CURLcode *err)
133 {
134 struct ssl_connect_data *const connssl = cf->ctx;
135 struct rustls_ssl_backend_data *const backend =
136 (struct rustls_ssl_backend_data *)connssl->backend;
137 struct io_ctx io_ctx;
138 size_t tls_bytes_read = 0;
139 rustls_io_result io_error;
140 rustls_result rresult = 0;
141
142 io_ctx.cf = cf;
143 io_ctx.data = data;
144 io_error = rustls_connection_read_tls(backend->conn, read_cb, &io_ctx,
145 &tls_bytes_read);
146 if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
147 *err = CURLE_AGAIN;
148 return -1;
149 }
150 else if(io_error) {
151 char buffer[STRERROR_LEN];
152 failf(data, "reading from socket: %s",
153 Curl_strerror(io_error, buffer, sizeof(buffer)));
154 *err = CURLE_RECV_ERROR;
155 return -1;
156 }
157
158 rresult = rustls_connection_process_new_packets(backend->conn);
159 if(rresult != RUSTLS_RESULT_OK) {
160 char errorbuf[255];
161 size_t errorlen;
162 rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
163 failf(data, "rustls_connection_process_new_packets: %.*s",
164 (int)errorlen, errorbuf);
165 *err = map_error(rresult);
166 return -1;
167 }
168
169 backend->data_in_pending = TRUE;
170 *err = CURLE_OK;
171 return (ssize_t)tls_bytes_read;
172 }
173
174 /*
175 * On each run:
176 * - Read a chunk of bytes from the socket into rustls' TLS input buffer.
177 * - Tell rustls to process any new packets.
178 * - Read out as many plaintext bytes from rustls as possible, until hitting
179 * error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up.
180 *
181 * It's okay to call this function with plainbuf == NULL and plainlen == 0.
182 * In that case, it will copy bytes from the socket into rustls' TLS input
183 * buffer, and process packets, but won't consume bytes from rustls' plaintext
184 * output buffer.
185 */
186 static ssize_t
cr_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * plainbuf,size_t plainlen,CURLcode * err)187 cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
188 char *plainbuf, size_t plainlen, CURLcode *err)
189 {
190 struct ssl_connect_data *const connssl = cf->ctx;
191 struct rustls_ssl_backend_data *const backend =
192 (struct rustls_ssl_backend_data *)connssl->backend;
193 struct rustls_connection *rconn = NULL;
194 size_t n = 0;
195 size_t plain_bytes_copied = 0;
196 rustls_result rresult = 0;
197 ssize_t nread;
198 bool eof = FALSE;
199
200 DEBUGASSERT(backend);
201 rconn = backend->conn;
202
203 while(plain_bytes_copied < plainlen) {
204 if(!backend->data_in_pending) {
205 if(tls_recv_more(cf, data, err) < 0) {
206 if(*err != CURLE_AGAIN) {
207 nread = -1;
208 goto out;
209 }
210 break;
211 }
212 }
213
214 rresult = rustls_connection_read(rconn,
215 (uint8_t *)plainbuf + plain_bytes_copied,
216 plainlen - plain_bytes_copied,
217 &n);
218 if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
219 backend->data_in_pending = FALSE;
220 }
221 else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
222 failf(data, "rustls: peer closed TCP connection "
223 "without first closing TLS connection");
224 *err = CURLE_RECV_ERROR;
225 nread = -1;
226 goto out;
227 }
228 else if(rresult != RUSTLS_RESULT_OK) {
229 /* n always equals 0 in this case, don't need to check it */
230 char errorbuf[255];
231 size_t errorlen;
232 rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
233 failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf);
234 *err = CURLE_RECV_ERROR;
235 nread = -1;
236 goto out;
237 }
238 else if(n == 0) {
239 /* n == 0 indicates clean EOF, but we may have read some other
240 plaintext bytes before we reached this. Break out of the loop
241 so we can figure out whether to return success or EOF. */
242 eof = TRUE;
243 break;
244 }
245 else {
246 plain_bytes_copied += n;
247 }
248 }
249
250 if(plain_bytes_copied) {
251 *err = CURLE_OK;
252 nread = (ssize_t)plain_bytes_copied;
253 }
254 else if(eof) {
255 *err = CURLE_OK;
256 nread = 0;
257 }
258 else {
259 *err = CURLE_AGAIN;
260 nread = -1;
261 }
262
263 out:
264 CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d",
265 plainlen, nread, *err);
266 return nread;
267 }
268
cr_flush_out(struct Curl_cfilter * cf,struct Curl_easy * data,struct rustls_connection * rconn)269 static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
270 struct rustls_connection *rconn)
271 {
272 struct io_ctx io_ctx;
273 rustls_io_result io_error;
274 size_t tlswritten = 0;
275 size_t tlswritten_total = 0;
276 CURLcode result = CURLE_OK;
277
278 io_ctx.cf = cf;
279 io_ctx.data = data;
280
281 while(rustls_connection_wants_write(rconn)) {
282 io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
283 &tlswritten);
284 if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
285 CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
286 tlswritten_total);
287 return CURLE_AGAIN;
288 }
289 else if(io_error) {
290 char buffer[STRERROR_LEN];
291 failf(data, "writing to socket: %s",
292 Curl_strerror(io_error, buffer, sizeof(buffer)));
293 return CURLE_SEND_ERROR;
294 }
295 if(tlswritten == 0) {
296 failf(data, "EOF in swrite");
297 return CURLE_SEND_ERROR;
298 }
299 CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
300 tlswritten_total += tlswritten;
301 }
302 return result;
303 }
304
305 /*
306 * On each call:
307 * - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0).
308 * - Fully drain rustls' plaintext output buffer into the socket until
309 * we get either an error or EAGAIN/EWOULDBLOCK.
310 *
311 * It's okay to call this function with plainbuf == NULL and plainlen == 0.
312 * In that case, it won't read anything into rustls' plaintext input buffer.
313 * It will only drain rustls' plaintext output buffer into the socket.
314 */
315 static ssize_t
cr_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * plainbuf,size_t plainlen,CURLcode * err)316 cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
317 const void *plainbuf, size_t plainlen, CURLcode *err)
318 {
319 struct ssl_connect_data *const connssl = cf->ctx;
320 struct rustls_ssl_backend_data *const backend =
321 (struct rustls_ssl_backend_data *)connssl->backend;
322 struct rustls_connection *rconn = NULL;
323 size_t plainwritten = 0;
324 rustls_result rresult;
325 char errorbuf[256];
326 size_t errorlen;
327 const unsigned char *buf = plainbuf;
328 size_t blen = plainlen;
329 ssize_t nwritten = 0;
330
331 DEBUGASSERT(backend);
332 rconn = backend->conn;
333 DEBUGASSERT(rconn);
334
335 CURL_TRC_CF(data, cf, "cf_send(len=%zu)", plainlen);
336
337 /* If a previous send blocked, we already added its plain bytes
338 * to rustsls and must not do that again. Flush the TLS bytes and,
339 * if successful, deduct the previous plain bytes from the current
340 * send. */
341 if(backend->plain_out_buffered) {
342 *err = cr_flush_out(cf, data, rconn);
343 CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d",
344 backend->plain_out_buffered, *err);
345 if(*err)
346 return -1;
347 if(blen > backend->plain_out_buffered) {
348 blen -= backend->plain_out_buffered;
349 buf += backend->plain_out_buffered;
350 }
351 else
352 blen = 0;
353 nwritten += (ssize_t)backend->plain_out_buffered;
354 backend->plain_out_buffered = 0;
355 }
356
357 if(blen > 0) {
358 CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to rustls", blen);
359 rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
360 if(rresult != RUSTLS_RESULT_OK) {
361 rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
362 failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf);
363 *err = CURLE_WRITE_ERROR;
364 return -1;
365 }
366 else if(plainwritten == 0) {
367 failf(data, "rustls_connection_write: EOF");
368 *err = CURLE_WRITE_ERROR;
369 return -1;
370 }
371 }
372
373 *err = cr_flush_out(cf, data, rconn);
374 if(*err) {
375 if(CURLE_AGAIN == *err) {
376 /* The TLS bytes may have been partially written, but we fail the
377 * complete send() and remember how much we already added to rustls. */
378 CURL_TRC_CF(data, cf, "cf_send: EAGAIN, remember we added %zu plain"
379 " bytes already to rustls", blen);
380 backend->plain_out_buffered = plainwritten;
381 if(nwritten) {
382 *err = CURLE_OK;
383 return (ssize_t)nwritten;
384 }
385 }
386 return -1;
387 }
388 else
389 nwritten += (ssize_t)plainwritten;
390
391 CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zd",
392 plainlen, *err, nwritten);
393 return nwritten;
394 }
395
396 /* A server certificate verify callback for rustls that always returns
397 RUSTLS_RESULT_OK, or in other words disable certificate verification. */
398 static uint32_t
cr_verify_none(void * userdata UNUSED_PARAM,const rustls_verify_server_cert_params * params UNUSED_PARAM)399 cr_verify_none(void *userdata UNUSED_PARAM,
400 const rustls_verify_server_cert_params *params UNUSED_PARAM)
401 {
402 return RUSTLS_RESULT_OK;
403 }
404
405 static bool
cr_hostname_is_ip(const char * hostname)406 cr_hostname_is_ip(const char *hostname)
407 {
408 struct in_addr in;
409 #ifdef USE_IPV6
410 struct in6_addr in6;
411 if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
412 return true;
413 }
414 #endif /* USE_IPV6 */
415 if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
416 return true;
417 }
418 return false;
419 }
420
421 static CURLcode
cr_init_backend(struct Curl_cfilter * cf,struct Curl_easy * data,struct rustls_ssl_backend_data * const backend)422 cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
423 struct rustls_ssl_backend_data *const backend)
424 {
425 struct ssl_connect_data *connssl = cf->ctx;
426 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
427 struct rustls_connection *rconn = NULL;
428 struct rustls_client_config_builder *config_builder = NULL;
429 const struct rustls_root_cert_store *roots = NULL;
430 struct rustls_root_cert_store_builder *roots_builder = NULL;
431 struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL;
432 struct rustls_server_cert_verifier *server_cert_verifier = NULL;
433 const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
434 const char * const ssl_cafile =
435 /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
436 (ca_info_blob ? NULL : conn_config->CAfile);
437 const bool verifypeer = conn_config->verifypeer;
438 const char *hostname = connssl->peer.hostname;
439 char errorbuf[256];
440 size_t errorlen;
441 int result;
442
443 DEBUGASSERT(backend);
444 rconn = backend->conn;
445
446 config_builder = rustls_client_config_builder_new();
447 if(connssl->alpn) {
448 struct alpn_proto_buf proto;
449 rustls_slice_bytes alpn[ALPN_ENTRIES_MAX];
450 size_t i;
451
452 for(i = 0; i < connssl->alpn->count; ++i) {
453 alpn[i].data = (const uint8_t *)connssl->alpn->entries[i];
454 alpn[i].len = strlen(connssl->alpn->entries[i]);
455 }
456 rustls_client_config_builder_set_alpn_protocols(config_builder, alpn,
457 connssl->alpn->count);
458 Curl_alpn_to_proto_str(&proto, connssl->alpn);
459 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
460 }
461 if(!verifypeer) {
462 rustls_client_config_builder_dangerous_set_certificate_verifier(
463 config_builder, cr_verify_none);
464 /* rustls doesn't support IP addresses (as of 0.19.0), and will reject
465 * connections created with an IP address, even when certificate
466 * verification is turned off. Set a placeholder hostname and disable
467 * SNI. */
468 if(cr_hostname_is_ip(hostname)) {
469 rustls_client_config_builder_set_enable_sni(config_builder, false);
470 hostname = "example.invalid";
471 }
472 }
473 else if(ca_info_blob || ssl_cafile) {
474 roots_builder = rustls_root_cert_store_builder_new();
475
476 if(ca_info_blob) {
477 /* Enable strict parsing only if verification isn't disabled. */
478 result = rustls_root_cert_store_builder_add_pem(roots_builder,
479 ca_info_blob->data,
480 ca_info_blob->len,
481 verifypeer);
482 if(result != RUSTLS_RESULT_OK) {
483 failf(data, "rustls: failed to parse trusted certificates from blob");
484 rustls_root_cert_store_builder_free(roots_builder);
485 rustls_client_config_free(
486 rustls_client_config_builder_build(config_builder));
487 return CURLE_SSL_CACERT_BADFILE;
488 }
489 }
490 else if(ssl_cafile) {
491 /* Enable strict parsing only if verification isn't disabled. */
492 result = rustls_root_cert_store_builder_load_roots_from_file(
493 roots_builder, ssl_cafile, verifypeer);
494 if(result != RUSTLS_RESULT_OK) {
495 failf(data, "rustls: failed to load trusted certificates");
496 rustls_root_cert_store_builder_free(roots_builder);
497 rustls_client_config_free(
498 rustls_client_config_builder_build(config_builder));
499 return CURLE_SSL_CACERT_BADFILE;
500 }
501 }
502
503 result = rustls_root_cert_store_builder_build(roots_builder, &roots);
504 rustls_root_cert_store_builder_free(roots_builder);
505 if(result != RUSTLS_RESULT_OK) {
506 failf(data, "rustls: failed to load trusted certificates");
507 rustls_client_config_free(
508 rustls_client_config_builder_build(config_builder));
509 return CURLE_SSL_CACERT_BADFILE;
510 }
511
512 verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
513
514 result = rustls_web_pki_server_cert_verifier_builder_build(
515 verifier_builder, &server_cert_verifier);
516 rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
517 if(result != RUSTLS_RESULT_OK) {
518 failf(data, "rustls: failed to load trusted certificates");
519 rustls_server_cert_verifier_free(server_cert_verifier);
520 rustls_client_config_free(
521 rustls_client_config_builder_build(config_builder));
522 return CURLE_SSL_CACERT_BADFILE;
523 }
524
525 rustls_client_config_builder_set_server_verifier(config_builder,
526 server_cert_verifier);
527 }
528
529 backend->config = rustls_client_config_builder_build(config_builder);
530 DEBUGASSERT(rconn == NULL);
531 result = rustls_client_connection_new(backend->config,
532 connssl->peer.hostname, &rconn);
533 if(result != RUSTLS_RESULT_OK) {
534 rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
535 failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf);
536 return CURLE_COULDNT_CONNECT;
537 }
538 DEBUGASSERT(rconn);
539 rustls_connection_set_userdata(rconn, backend);
540 backend->conn = rconn;
541 return CURLE_OK;
542 }
543
544 static void
cr_set_negotiated_alpn(struct Curl_cfilter * cf,struct Curl_easy * data,const struct rustls_connection * rconn)545 cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data,
546 const struct rustls_connection *rconn)
547 {
548 const uint8_t *protocol = NULL;
549 size_t len = 0;
550
551 rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
552 Curl_alpn_set_negotiated(cf, data, protocol, len);
553 }
554
555 /* Given an established network connection, do a TLS handshake.
556 *
557 * If `blocking` is true, this function will block until the handshake is
558 * complete. Otherwise it will return as soon as I/O would block.
559 *
560 * For the non-blocking I/O case, this function will set `*done` to true
561 * once the handshake is complete. This function never reads the value of
562 * `*done*`.
563 */
564 static CURLcode
cr_connect_common(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)565 cr_connect_common(struct Curl_cfilter *cf,
566 struct Curl_easy *data,
567 bool blocking,
568 bool *done)
569 {
570 struct ssl_connect_data *const connssl = cf->ctx;
571 curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
572 struct rustls_ssl_backend_data *const backend =
573 (struct rustls_ssl_backend_data *)connssl->backend;
574 struct rustls_connection *rconn = NULL;
575 CURLcode tmperr = CURLE_OK;
576 int result;
577 int what;
578 bool wants_read;
579 bool wants_write;
580 curl_socket_t writefd;
581 curl_socket_t readfd;
582 timediff_t timeout_ms;
583 timediff_t socket_check_timeout;
584
585 DEBUGASSERT(backend);
586
587 CURL_TRC_CF(data, cf, "cr_connect_common, state=%d", connssl->state);
588 *done = FALSE;
589 if(!backend->conn) {
590 result = cr_init_backend(cf, data,
591 (struct rustls_ssl_backend_data *)connssl->backend);
592 CURL_TRC_CF(data, cf, "cr_connect_common, init backend -> %d", result);
593 if(result != CURLE_OK) {
594 return result;
595 }
596 connssl->state = ssl_connection_negotiating;
597 }
598
599 rconn = backend->conn;
600
601 /* Read/write data until the handshake is done or the socket would block. */
602 for(;;) {
603 /*
604 * Connection has been established according to rustls. Set send/recv
605 * handlers, and update the state machine.
606 */
607 if(!rustls_connection_is_handshaking(rconn)) {
608 infof(data, "Done handshaking");
609 /* rustls claims it is no longer handshaking *before* it has
610 * send its FINISHED message off. We attempt to let it write
611 * one more time. Oh my.
612 */
613 cr_set_negotiated_alpn(cf, data, rconn);
614 cr_send(cf, data, NULL, 0, &tmperr);
615 if(tmperr == CURLE_AGAIN) {
616 connssl->connecting_state = ssl_connect_2_writing;
617 return CURLE_OK;
618 }
619 else if(tmperr != CURLE_OK) {
620 return tmperr;
621 }
622 /* REALLY Done with the handshake. */
623 connssl->state = ssl_connection_complete;
624 *done = TRUE;
625 return CURLE_OK;
626 }
627
628 wants_read = rustls_connection_wants_read(rconn);
629 wants_write = rustls_connection_wants_write(rconn) ||
630 backend->plain_out_buffered;
631 DEBUGASSERT(wants_read || wants_write);
632 writefd = wants_write?sockfd:CURL_SOCKET_BAD;
633 readfd = wants_read?sockfd:CURL_SOCKET_BAD;
634
635 connssl->connecting_state = wants_write?
636 ssl_connect_2_writing : ssl_connect_2_reading;
637 /* check allowed time left */
638 timeout_ms = Curl_timeleft(data, NULL, TRUE);
639
640 if(timeout_ms < 0) {
641 /* no need to continue if time already is up */
642 failf(data, "rustls: operation timed out before socket check");
643 return CURLE_OPERATION_TIMEDOUT;
644 }
645
646 socket_check_timeout = blocking?timeout_ms:0;
647
648 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
649 socket_check_timeout);
650 if(what < 0) {
651 /* fatal error */
652 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
653 return CURLE_SSL_CONNECT_ERROR;
654 }
655 if(blocking && 0 == what) {
656 failf(data, "rustls connection timeout after %"
657 CURL_FORMAT_TIMEDIFF_T " ms", socket_check_timeout);
658 return CURLE_OPERATION_TIMEDOUT;
659 }
660 if(0 == what) {
661 CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
662 wants_read&&wants_write ? "writing and reading" :
663 wants_write ? "writing" : "reading");
664 return CURLE_OK;
665 }
666 /* socket is readable or writable */
667
668 if(wants_write) {
669 CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
670 cr_send(cf, data, NULL, 0, &tmperr);
671 if(tmperr == CURLE_AGAIN) {
672 CURL_TRC_CF(data, cf, "writing would block");
673 /* fall through */
674 }
675 else if(tmperr != CURLE_OK) {
676 return tmperr;
677 }
678 }
679
680 if(wants_read) {
681 CURL_TRC_CF(data, cf, "rustls_connection wants us to read_tls.");
682 if(tls_recv_more(cf, data, &tmperr) < 0) {
683 if(tmperr == CURLE_AGAIN) {
684 CURL_TRC_CF(data, cf, "reading would block");
685 /* fall through */
686 }
687 else if(tmperr == CURLE_RECV_ERROR) {
688 return CURLE_SSL_CONNECT_ERROR;
689 }
690 else {
691 return tmperr;
692 }
693 }
694 }
695 }
696
697 /* We should never fall through the loop. We should return either because
698 the handshake is done or because we can't read/write without blocking. */
699 DEBUGASSERT(false);
700 }
701
702 static CURLcode
cr_connect_nonblocking(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)703 cr_connect_nonblocking(struct Curl_cfilter *cf,
704 struct Curl_easy *data, bool *done)
705 {
706 return cr_connect_common(cf, data, false, done);
707 }
708
709 static CURLcode
cr_connect_blocking(struct Curl_cfilter * cf,struct Curl_easy * data)710 cr_connect_blocking(struct Curl_cfilter *cf, struct Curl_easy *data)
711 {
712 bool done; /* unused */
713 return cr_connect_common(cf, data, true, &done);
714 }
715
716 static void *
cr_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)717 cr_get_internals(struct ssl_connect_data *connssl,
718 CURLINFO info UNUSED_PARAM)
719 {
720 struct rustls_ssl_backend_data *backend =
721 (struct rustls_ssl_backend_data *)connssl->backend;
722 DEBUGASSERT(backend);
723 return &backend->conn;
724 }
725
726 static void
cr_close(struct Curl_cfilter * cf,struct Curl_easy * data)727 cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
728 {
729 struct ssl_connect_data *connssl = cf->ctx;
730 struct rustls_ssl_backend_data *backend =
731 (struct rustls_ssl_backend_data *)connssl->backend;
732 CURLcode tmperr = CURLE_OK;
733 ssize_t n = 0;
734
735 DEBUGASSERT(backend);
736 if(backend->conn && !connssl->peer_closed) {
737 CURL_TRC_CF(data, cf, "closing connection, send notify");
738 rustls_connection_send_close_notify(backend->conn);
739 n = cr_send(cf, data, NULL, 0, &tmperr);
740 if(n < 0) {
741 failf(data, "rustls: error sending close_notify: %d", tmperr);
742 }
743
744 rustls_connection_free(backend->conn);
745 backend->conn = NULL;
746 }
747 if(backend->config) {
748 rustls_client_config_free(backend->config);
749 backend->config = NULL;
750 }
751 }
752
cr_version(char * buffer,size_t size)753 static size_t cr_version(char *buffer, size_t size)
754 {
755 struct rustls_str ver = rustls_version();
756 return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data);
757 }
758
759 const struct Curl_ssl Curl_ssl_rustls = {
760 { CURLSSLBACKEND_RUSTLS, "rustls" },
761 SSLSUPP_CAINFO_BLOB | /* supports */
762 SSLSUPP_HTTPS_PROXY,
763 sizeof(struct rustls_ssl_backend_data),
764
765 Curl_none_init, /* init */
766 Curl_none_cleanup, /* cleanup */
767 cr_version, /* version */
768 Curl_none_check_cxn, /* check_cxn */
769 Curl_none_shutdown, /* shutdown */
770 cr_data_pending, /* data_pending */
771 Curl_none_random, /* random */
772 Curl_none_cert_status_request, /* cert_status_request */
773 cr_connect_blocking, /* connect */
774 cr_connect_nonblocking, /* connect_nonblocking */
775 Curl_ssl_adjust_pollset, /* adjust_pollset */
776 cr_get_internals, /* get_internals */
777 cr_close, /* close_one */
778 Curl_none_close_all, /* close_all */
779 Curl_none_set_engine, /* set_engine */
780 Curl_none_set_engine_default, /* set_engine_default */
781 Curl_none_engines_list, /* engines_list */
782 Curl_none_false_start, /* false_start */
783 NULL, /* sha256sum */
784 NULL, /* associate_connection */
785 NULL, /* disassociate_connection */
786 cr_recv, /* recv decrypted data */
787 cr_send, /* send data to encrypt */
788 };
789
790 #endif /* USE_RUSTLS */
791