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