rustls.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 2020 - 2021, Jacob Hoffman-Andrews,
  9. * <[email protected]>
  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. ***************************************************************************/
  23. #include "curl_setup.h"
  24. #ifdef USE_RUSTLS
  25. #include "curl_printf.h"
  26. #include <errno.h>
  27. #include <crustls.h>
  28. #include "inet_pton.h"
  29. #include "urldata.h"
  30. #include "sendf.h"
  31. #include "vtls.h"
  32. #include "select.h"
  33. #include "multiif.h"
  34. struct ssl_backend_data
  35. {
  36. const struct rustls_client_config *config;
  37. struct rustls_connection *conn;
  38. bool data_pending;
  39. };
  40. /* For a given rustls_result error code, return the best-matching CURLcode. */
  41. static CURLcode map_error(rustls_result r)
  42. {
  43. if(rustls_result_is_cert_error(r)) {
  44. return CURLE_PEER_FAILED_VERIFICATION;
  45. }
  46. switch(r) {
  47. case RUSTLS_RESULT_OK:
  48. return CURLE_OK;
  49. case RUSTLS_RESULT_NULL_PARAMETER:
  50. return CURLE_BAD_FUNCTION_ARGUMENT;
  51. default:
  52. return CURLE_READ_ERROR;
  53. }
  54. }
  55. static bool
  56. cr_data_pending(const struct connectdata *conn, int sockindex)
  57. {
  58. const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  59. struct ssl_backend_data *backend = connssl->backend;
  60. return backend->data_pending;
  61. }
  62. static CURLcode
  63. cr_connect(struct Curl_easy *data UNUSED_PARAM,
  64. struct connectdata *conn UNUSED_PARAM,
  65. int sockindex UNUSED_PARAM)
  66. {
  67. infof(data, "rustls_connect: unimplemented\n");
  68. return CURLE_SSL_CONNECT_ERROR;
  69. }
  70. static int
  71. read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
  72. {
  73. ssize_t n = sread(*(int *)userdata, buf, len);
  74. if(n < 0) {
  75. return SOCKERRNO;
  76. }
  77. *out_n = n;
  78. return 0;
  79. }
  80. static int
  81. write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
  82. {
  83. ssize_t n = swrite(*(int *)userdata, buf, len);
  84. if(n < 0) {
  85. return SOCKERRNO;
  86. }
  87. *out_n = n;
  88. return 0;
  89. }
  90. /*
  91. * On each run:
  92. * - Read a chunk of bytes from the socket into rustls' TLS input buffer.
  93. * - Tell rustls to process any new packets.
  94. * - Read out as many plaintext bytes from rustls as possible, until hitting
  95. * error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up.
  96. *
  97. * It's okay to call this function with plainbuf == NULL and plainlen == 0.
  98. * In that case, it will copy bytes from the socket into rustls' TLS input
  99. * buffer, and process packets, but won't consume bytes from rustls' plaintext
  100. * output buffer.
  101. */
  102. static ssize_t
  103. cr_recv(struct Curl_easy *data, int sockindex,
  104. char *plainbuf, size_t plainlen, CURLcode *err)
  105. {
  106. struct connectdata *conn = data->conn;
  107. struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
  108. struct ssl_backend_data *const backend = connssl->backend;
  109. struct rustls_connection *const rconn = backend->conn;
  110. size_t n = 0;
  111. size_t tls_bytes_read = 0;
  112. size_t plain_bytes_copied = 0;
  113. rustls_result rresult = 0;
  114. char errorbuf[255];
  115. rustls_io_result io_error;
  116. io_error = rustls_connection_read_tls(rconn, read_cb,
  117. &conn->sock[sockindex], &tls_bytes_read);
  118. if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
  119. infof(data, "sread: EAGAIN or EWOULDBLOCK\n");
  120. }
  121. else if(io_error) {
  122. failf(data, "reading from socket: %s", strerror(io_error));
  123. *err = CURLE_READ_ERROR;
  124. return -1;
  125. }
  126. else if(tls_bytes_read == 0) {
  127. failf(data, "connection closed without TLS close_notify alert");
  128. *err = CURLE_READ_ERROR;
  129. return -1;
  130. }
  131. infof(data, "cr_recv read %ld bytes from the network\n", tls_bytes_read);
  132. rresult = rustls_connection_process_new_packets(rconn);
  133. if(rresult != RUSTLS_RESULT_OK) {
  134. rustls_error(rresult, errorbuf, sizeof(errorbuf), &n);
  135. failf(data, "%.*s", n, errorbuf);
  136. *err = map_error(rresult);
  137. return -1;
  138. }
  139. backend->data_pending = TRUE;
  140. while(plain_bytes_copied < plainlen) {
  141. rresult = rustls_connection_read(rconn,
  142. (uint8_t *)plainbuf + plain_bytes_copied,
  143. plainlen - plain_bytes_copied,
  144. &n);
  145. if(rresult == RUSTLS_RESULT_ALERT_CLOSE_NOTIFY) {
  146. *err = CURLE_OK;
  147. return 0;
  148. }
  149. else if(rresult != RUSTLS_RESULT_OK) {
  150. failf(data, "error in rustls_connection_read");
  151. *err = CURLE_READ_ERROR;
  152. return -1;
  153. }
  154. else if(n == 0) {
  155. /* rustls returns 0 from connection_read to mean "all currently
  156. available data has been read." If we bring in more ciphertext with
  157. read_tls, more plaintext will become available. So don't tell curl
  158. this is an EOF. Instead, say "come back later." */
  159. infof(data, "cr_recv got 0 bytes of plaintext\n");
  160. backend->data_pending = FALSE;
  161. break;
  162. }
  163. else {
  164. infof(data, "cr_recv copied out %ld bytes of plaintext\n", n);
  165. plain_bytes_copied += n;
  166. }
  167. }
  168. /* If we wrote out 0 plaintext bytes, it might just mean we haven't yet
  169. read a full TLS record. Return CURLE_AGAIN so curl doesn't treat this
  170. as EOF. */
  171. if(plain_bytes_copied == 0) {
  172. *err = CURLE_AGAIN;
  173. return -1;
  174. }
  175. return plain_bytes_copied;
  176. }
  177. /*
  178. * On each call:
  179. * - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0).
  180. * - Fully drain rustls' plaintext output buffer into the socket until
  181. * we get either an error or EAGAIN/EWOULDBLOCK.
  182. *
  183. * It's okay to call this function with plainbuf == NULL and plainlen == 0.
  184. * In that case, it won't read anything into rustls' plaintext input buffer.
  185. * It will only drain rustls' plaintext output buffer into the socket.
  186. */
  187. static ssize_t
  188. cr_send(struct Curl_easy *data, int sockindex,
  189. const void *plainbuf, size_t plainlen, CURLcode *err)
  190. {
  191. struct connectdata *conn = data->conn;
  192. struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
  193. struct ssl_backend_data *const backend = connssl->backend;
  194. struct rustls_connection *const rconn = backend->conn;
  195. size_t plainwritten = 0;
  196. size_t tlswritten = 0;
  197. size_t tlswritten_total = 0;
  198. rustls_result rresult;
  199. rustls_io_result io_error;
  200. infof(data, "cr_send %ld bytes of plaintext\n", plainlen);
  201. if(plainlen > 0) {
  202. rresult = rustls_connection_write(rconn, plainbuf, plainlen,
  203. &plainwritten);
  204. if(rresult != RUSTLS_RESULT_OK) {
  205. failf(data, "error in rustls_connection_write");
  206. *err = CURLE_WRITE_ERROR;
  207. return -1;
  208. }
  209. else if(plainwritten == 0) {
  210. failf(data, "EOF in rustls_connection_write");
  211. *err = CURLE_WRITE_ERROR;
  212. return -1;
  213. }
  214. }
  215. while(rustls_connection_wants_write(rconn)) {
  216. io_error = rustls_connection_write_tls(rconn, write_cb,
  217. &conn->sock[sockindex], &tlswritten);
  218. if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
  219. infof(data, "swrite: EAGAIN after %ld bytes\n", tlswritten_total);
  220. *err = CURLE_AGAIN;
  221. return -1;
  222. }
  223. else if(io_error) {
  224. failf(data, "writing to socket: %s", strerror(io_error));
  225. *err = CURLE_WRITE_ERROR;
  226. return -1;
  227. }
  228. if(tlswritten == 0) {
  229. failf(data, "EOF in swrite");
  230. *err = CURLE_WRITE_ERROR;
  231. return -1;
  232. }
  233. infof(data, "cr_send wrote %ld bytes to network\n", tlswritten);
  234. tlswritten_total += tlswritten;
  235. }
  236. return plainwritten;
  237. }
  238. /* A server certificate verify callback for rustls that always returns
  239. RUSTLS_RESULT_OK, or in other words disable certificate verification. */
  240. static enum rustls_result
  241. cr_verify_none(void *userdata UNUSED_PARAM,
  242. const rustls_verify_server_cert_params *params UNUSED_PARAM)
  243. {
  244. return RUSTLS_RESULT_OK;
  245. }
  246. static bool
  247. cr_hostname_is_ip(const char *hostname)
  248. {
  249. struct in_addr in;
  250. #ifdef ENABLE_IPV6
  251. struct in6_addr in6;
  252. if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
  253. return true;
  254. }
  255. #endif /* ENABLE_IPV6 */
  256. if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
  257. return true;
  258. }
  259. return false;
  260. }
  261. static CURLcode
  262. cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
  263. struct ssl_backend_data *const backend)
  264. {
  265. struct rustls_connection *rconn = backend->conn;
  266. struct rustls_client_config_builder *config_builder = NULL;
  267. const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
  268. const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
  269. const char *hostname = conn->host.name;
  270. char errorbuf[256];
  271. size_t errorlen;
  272. int result;
  273. rustls_slice_bytes alpn[2] = {
  274. { (const uint8_t *)ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH },
  275. { (const uint8_t *)ALPN_H2, ALPN_H2_LENGTH },
  276. };
  277. config_builder = rustls_client_config_builder_new();
  278. #ifdef USE_HTTP2
  279. infof(data, "offering ALPN for HTTP/1.1 and HTTP/2\n");
  280. rustls_client_config_builder_set_protocols(config_builder, alpn, 2);
  281. #else
  282. infof(data, "offering ALPN for HTTP/1.1 only\n");
  283. rustls_client_config_builder_set_protocols(config_builder, alpn, 1);
  284. #endif
  285. if(!verifypeer) {
  286. rustls_client_config_builder_dangerous_set_certificate_verifier(
  287. config_builder, cr_verify_none);
  288. /* rustls doesn't support IP addresses (as of 0.19.0), and will reject
  289. * connections created with an IP address, even when certificate
  290. * verification is turned off. Set a placeholder hostname and disable
  291. * SNI. */
  292. if(cr_hostname_is_ip(hostname)) {
  293. rustls_client_config_builder_set_enable_sni(config_builder, false);
  294. hostname = "example.invalid";
  295. }
  296. }
  297. else if(ssl_cafile) {
  298. result = rustls_client_config_builder_load_roots_from_file(
  299. config_builder, ssl_cafile);
  300. if(result != RUSTLS_RESULT_OK) {
  301. failf(data, "failed to load trusted certificates");
  302. rustls_client_config_free(
  303. rustls_client_config_builder_build(config_builder));
  304. return CURLE_SSL_CACERT_BADFILE;
  305. }
  306. }
  307. else {
  308. result = rustls_client_config_builder_load_native_roots(config_builder);
  309. if(result != RUSTLS_RESULT_OK) {
  310. failf(data, "failed to load trusted certificates");
  311. rustls_client_config_free(
  312. rustls_client_config_builder_build(config_builder));
  313. return CURLE_SSL_CACERT_BADFILE;
  314. }
  315. }
  316. backend->config = rustls_client_config_builder_build(config_builder);
  317. DEBUGASSERT(rconn == NULL);
  318. result = rustls_client_connection_new(backend->config, hostname, &rconn);
  319. if(result != RUSTLS_RESULT_OK) {
  320. rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
  321. failf(data, "rustls_client_connection_new: %.*s", errorlen, errorbuf);
  322. return CURLE_COULDNT_CONNECT;
  323. }
  324. rustls_connection_set_userdata(rconn, backend);
  325. backend->conn = rconn;
  326. return CURLE_OK;
  327. }
  328. static void
  329. cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
  330. const struct rustls_connection *rconn)
  331. {
  332. const uint8_t *protocol = NULL;
  333. size_t len = 0;
  334. rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
  335. if(NULL == protocol) {
  336. infof(data, "ALPN, server did not agree to a protocol\n");
  337. return;
  338. }
  339. #ifdef USE_HTTP2
  340. if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) {
  341. infof(data, "ALPN, negotiated h2\n");
  342. conn->negnpn = CURL_HTTP_VERSION_2;
  343. }
  344. else
  345. #endif
  346. if(len == ALPN_HTTP_1_1_LENGTH &&
  347. 0 == memcmp(ALPN_HTTP_1_1, protocol, len)) {
  348. infof(data, "ALPN, negotiated http/1.1\n");
  349. conn->negnpn = CURL_HTTP_VERSION_1_1;
  350. }
  351. else {
  352. infof(data, "ALPN, negotiated an unrecognized protocol\n");
  353. }
  354. Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
  355. BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
  356. }
  357. static CURLcode
  358. cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
  359. int sockindex, bool *done)
  360. {
  361. struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
  362. curl_socket_t sockfd = conn->sock[sockindex];
  363. struct ssl_backend_data *const backend = connssl->backend;
  364. struct rustls_connection *rconn = NULL;
  365. CURLcode tmperr = CURLE_OK;
  366. int result;
  367. int what;
  368. bool wants_read;
  369. bool wants_write;
  370. curl_socket_t writefd;
  371. curl_socket_t readfd;
  372. if(ssl_connection_none == connssl->state) {
  373. result = cr_init_backend(data, conn, connssl->backend);
  374. if(result != CURLE_OK) {
  375. return result;
  376. }
  377. connssl->state = ssl_connection_negotiating;
  378. }
  379. rconn = backend->conn;
  380. /* Read/write data until the handshake is done or the socket would block. */
  381. for(;;) {
  382. /*
  383. * Connection has been established according to rustls. Set send/recv
  384. * handlers, and update the state machine.
  385. * This check has to come last because is_handshaking starts out false,
  386. * then becomes true when we first write data, then becomes false again
  387. * once the handshake is done.
  388. */
  389. if(!rustls_connection_is_handshaking(rconn)) {
  390. infof(data, "Done handshaking\n");
  391. /* Done with the handshake. Set up callbacks to send/receive data. */
  392. connssl->state = ssl_connection_complete;
  393. cr_set_negotiated_alpn(data, conn, rconn);
  394. conn->recv[sockindex] = cr_recv;
  395. conn->send[sockindex] = cr_send;
  396. *done = TRUE;
  397. return CURLE_OK;
  398. }
  399. wants_read = rustls_connection_wants_read(rconn);
  400. wants_write = rustls_connection_wants_write(rconn);
  401. DEBUGASSERT(wants_read || wants_write);
  402. writefd = wants_write?sockfd:CURL_SOCKET_BAD;
  403. readfd = wants_read?sockfd:CURL_SOCKET_BAD;
  404. what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, 0);
  405. if(what < 0) {
  406. /* fatal error */
  407. failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
  408. return CURLE_SSL_CONNECT_ERROR;
  409. }
  410. if(0 == what) {
  411. infof(data, "Curl_socket_check: %s would block\n",
  412. wants_read&&wants_write ?
  413. "writing and reading" :
  414. wants_write ?
  415. "writing" :
  416. "reading");
  417. *done = FALSE;
  418. return CURLE_OK;
  419. }
  420. /* socket is readable or writable */
  421. if(wants_write) {
  422. infof(data, "rustls_connection wants us to write_tls.\n");
  423. cr_send(data, sockindex, NULL, 0, &tmperr);
  424. if(tmperr == CURLE_AGAIN) {
  425. infof(data, "writing would block\n");
  426. /* fall through */
  427. }
  428. else if(tmperr != CURLE_OK) {
  429. return tmperr;
  430. }
  431. }
  432. if(wants_read) {
  433. infof(data, "rustls_connection wants us to read_tls.\n");
  434. cr_recv(data, sockindex, NULL, 0, &tmperr);
  435. if(tmperr == CURLE_AGAIN) {
  436. infof(data, "reading would block\n");
  437. /* fall through */
  438. }
  439. else if(tmperr != CURLE_OK) {
  440. if(tmperr == CURLE_READ_ERROR) {
  441. return CURLE_SSL_CONNECT_ERROR;
  442. }
  443. else {
  444. return tmperr;
  445. }
  446. }
  447. }
  448. }
  449. /* We should never fall through the loop. We should return either because
  450. the handshake is done or because we can't read/write without blocking. */
  451. DEBUGASSERT(false);
  452. }
  453. /* returns a bitmap of flags for this connection's first socket indicating
  454. whether we want to read or write */
  455. static int
  456. cr_getsock(struct connectdata *conn, curl_socket_t *socks)
  457. {
  458. struct ssl_connect_data *const connssl = &conn->ssl[FIRSTSOCKET];
  459. curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
  460. struct ssl_backend_data *const backend = connssl->backend;
  461. struct rustls_connection *rconn = backend->conn;
  462. if(rustls_connection_wants_write(rconn)) {
  463. socks[0] = sockfd;
  464. return GETSOCK_WRITESOCK(0);
  465. }
  466. if(rustls_connection_wants_read(rconn)) {
  467. socks[0] = sockfd;
  468. return GETSOCK_READSOCK(0);
  469. }
  470. return GETSOCK_BLANK;
  471. }
  472. static void *
  473. cr_get_internals(struct ssl_connect_data *connssl,
  474. CURLINFO info UNUSED_PARAM)
  475. {
  476. struct ssl_backend_data *backend = connssl->backend;
  477. return &backend->conn;
  478. }
  479. static void
  480. cr_close(struct Curl_easy *data, struct connectdata *conn,
  481. int sockindex)
  482. {
  483. struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  484. struct ssl_backend_data *backend = connssl->backend;
  485. CURLcode tmperr = CURLE_OK;
  486. ssize_t n = 0;
  487. if(backend->conn) {
  488. rustls_connection_send_close_notify(backend->conn);
  489. n = cr_send(data, sockindex, NULL, 0, &tmperr);
  490. if(n < 0) {
  491. failf(data, "error sending close notify: %d", tmperr);
  492. }
  493. rustls_connection_free(backend->conn);
  494. backend->conn = NULL;
  495. }
  496. if(backend->config) {
  497. rustls_client_config_free(backend->config);
  498. backend->config = NULL;
  499. }
  500. }
  501. const struct Curl_ssl Curl_ssl_rustls = {
  502. { CURLSSLBACKEND_RUSTLS, "rustls" },
  503. SSLSUPP_TLS13_CIPHERSUITES, /* supports */
  504. sizeof(struct ssl_backend_data),
  505. Curl_none_init, /* init */
  506. Curl_none_cleanup, /* cleanup */
  507. rustls_version, /* version */
  508. Curl_none_check_cxn, /* check_cxn */
  509. Curl_none_shutdown, /* shutdown */
  510. cr_data_pending, /* data_pending */
  511. Curl_none_random, /* random */
  512. Curl_none_cert_status_request, /* cert_status_request */
  513. cr_connect, /* connect */
  514. cr_connect_nonblocking, /* connect_nonblocking */
  515. cr_getsock, /* cr_getsock */
  516. cr_get_internals, /* get_internals */
  517. cr_close, /* close_one */
  518. Curl_none_close_all, /* close_all */
  519. Curl_none_session_free, /* session_free */
  520. Curl_none_set_engine, /* set_engine */
  521. Curl_none_set_engine_default, /* set_engine_default */
  522. Curl_none_engines_list, /* engines_list */
  523. Curl_none_false_start, /* false_start */
  524. NULL, /* sha256sum */
  525. NULL, /* associate_connection */
  526. NULL /* disassociate_connection */
  527. };
  528. #endif /* USE_RUSTLS */