summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Hoffman-Andrews <github@hoffman-andrews.com>2021-02-26 17:29:36 -0800
committerDaniel Stenberg <daniel@haxx.se>2021-03-12 13:15:00 +0100
commit43a56e34e15269bfb0fa5d7392b7fc171e77506d (patch)
treeaf8135642867c5d2f55aaa3ef6b0309ccbf68585
parentf7aeff58a369d3cd2caac4f3becd7c683ba900c7 (diff)
downloadcurl-43a56e34e15269bfb0fa5d7392b7fc171e77506d.tar.gz
rustls: support CURLOPT_SSL_VERIFYPEER
This requires the latest main branch of crustls, which provides rustls_client_config_builder_dangerous_set_certificate_verifier and rustls_client_config_builder_set_enable_sni. This refactors the session setup into its own function, and adds a new function cr_hostname_is_ip. Because crustls doesn't support verification of IP addresses, special handling is needed: We disable SNI and set a placeholder hostname (which never actually gets sent on the wire). Closes #6719
-rw-r--r--lib/vtls/rustls.c139
1 files changed, 97 insertions, 42 deletions
diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c
index 986faa070..f64899acc 100644
--- a/lib/vtls/rustls.c
+++ b/lib/vtls/rustls.c
@@ -29,6 +29,7 @@
#include <errno.h>
#include <crustls.h>
+#include "inet_pton.h"
#include "urldata.h"
#include "sendf.h"
#include "vtls.h"
@@ -202,7 +203,7 @@ cr_recv(struct Curl_easy *data, int sockindex,
*/
static ssize_t
cr_send(struct Curl_easy *data, int sockindex,
- const void *plainbuf, size_t plainlen, CURLcode *err)
+ const void *plainbuf, size_t plainlen, CURLcode *err)
{
struct connectdata *conn = data->conn;
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
@@ -219,7 +220,7 @@ cr_send(struct Curl_easy *data, int sockindex,
if(plainlen > 0) {
rresult = rustls_client_session_write(session,
- plainbuf, plainlen, &plainwritten);
+ plainbuf, plainlen, &plainwritten);
if(rresult != RUSTLS_RESULT_OK) {
failf(data, "error in rustls_client_session_write");
*err = CURLE_WRITE_ERROR;
@@ -234,7 +235,7 @@ cr_send(struct Curl_easy *data, int sockindex,
while(rustls_client_session_wants_write(session)) {
rresult = rustls_client_session_write_tls(
- session, tlsbuf, sizeof(tlsbuf), &tlslen);
+ session, tlsbuf, sizeof(tlsbuf), &tlslen);
if(rresult != RUSTLS_RESULT_OK) {
failf(data, "error in rustls_client_session_write_tls");
*err = CURLE_WRITE_ERROR;
@@ -253,7 +254,7 @@ cr_send(struct Curl_easy *data, int sockindex,
if(n < 0) {
if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
/* Since recv is called from poll, there should be room to
- write at least some bytes before hitting EAGAIN. */
+ write at least some bytes before hitting EAGAIN. */
infof(data, "swrite: EAGAIN after %ld bytes\n", tlswritten);
DEBUGASSERT(tlswritten > 0);
break;
@@ -276,16 +277,97 @@ cr_send(struct Curl_easy *data, int sockindex,
return plainwritten;
}
+/* A server certificate verify callback for rustls that always returns
+ RUSTLS_RESULT_OK, or in other words disable certificate verification. */
+static enum rustls_result
+cr_verify_none(void *userdata UNUSED_PARAM,
+ const rustls_verify_server_cert_params *params UNUSED_PARAM)
+{
+ return RUSTLS_RESULT_OK;
+}
+
+static bool
+cr_hostname_is_ip(const char *hostname)
+{
+ struct in_addr in;
+#ifdef ENABLE_IPV6
+ struct in6_addr in6;
+ if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
+ return true;
+ }
+#endif /* ENABLE_IPV6 */
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+ return true;
+ }
+ return false;
+}
+
+static CURLcode
+cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
+ struct ssl_backend_data *const backend)
+{
+ struct rustls_client_session *session = backend->session;
+ struct rustls_client_config_builder *config_builder = NULL;
+ const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ const char *hostname = conn->host.name;
+ char errorbuf[256];
+ size_t errorlen;
+ int result;
+
+ config_builder = rustls_client_config_builder_new();
+ if(!verifypeer) {
+ rustls_client_config_builder_dangerous_set_certificate_verifier(
+ config_builder, cr_verify_none, NULL);
+ /* rustls doesn't support IP addresses (as of 0.19.0), and will reject
+ * sessions created with an IP address, even when certificate verification
+ * is turned off. Set a placeholder hostname and disable SNI. */
+ if(cr_hostname_is_ip(hostname)) {
+ rustls_client_config_builder_set_enable_sni(config_builder, false);
+ hostname = "example.invalid";
+ }
+ }
+ else if(ssl_cafile) {
+ result = rustls_client_config_builder_load_roots_from_file(
+ config_builder, ssl_cafile);
+ if(result != RUSTLS_RESULT_OK) {
+ failf(data, "failed to load trusted certificates");
+ rustls_client_config_free(
+ rustls_client_config_builder_build(config_builder));
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+ else {
+ result = rustls_client_config_builder_load_native_roots(config_builder);
+ if(result != RUSTLS_RESULT_OK) {
+ failf(data, "failed to load trusted certificates");
+ rustls_client_config_free(
+ rustls_client_config_builder_build(config_builder));
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+
+ backend->config = rustls_client_config_builder_build(config_builder);
+ DEBUGASSERT(session == NULL);
+ result = rustls_client_session_new(
+ backend->config, hostname, &session);
+ if(result != RUSTLS_RESULT_OK) {
+ rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
+ failf(data, "failed to create client session: %.*s", errorlen, errorbuf);
+ return CURLE_COULDNT_CONNECT;
+ }
+ backend->session = session;
+ return CURLE_OK;
+}
+
static CURLcode
cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
- int sockindex, bool *done)
+ int sockindex, bool *done)
{
struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_backend_data *const backend = connssl->backend;
- struct rustls_client_session *session = backend->session;
- struct rustls_client_config_builder *config_builder = NULL;
- const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ struct rustls_client_session *session = NULL;
CURLcode tmperr = CURLE_OK;
int result;
int what;
@@ -293,44 +375,17 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
bool wants_write;
curl_socket_t writefd;
curl_socket_t readfd;
- char errorbuf[256];
- size_t errorlen;
if(ssl_connection_none == connssl->state) {
- config_builder = rustls_client_config_builder_new();
- if(ssl_cafile) {
- result = rustls_client_config_builder_load_roots_from_file(
- config_builder, ssl_cafile);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "failed to load trusted certificates");
- rustls_client_config_free(
- rustls_client_config_builder_build(config_builder));
- return CURLE_SSL_CACERT_BADFILE;
- }
- }
- else {
- result = rustls_client_config_builder_load_native_roots(config_builder);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "failed to load trusted certificates");
- rustls_client_config_free(
- rustls_client_config_builder_build(config_builder));
- return CURLE_SSL_CACERT_BADFILE;
- }
+ result = cr_init_backend(data, conn, connssl->backend);
+ if(result != CURLE_OK) {
+ return result;
}
-
- backend->config = rustls_client_config_builder_build(config_builder);
- DEBUGASSERT(session == NULL);
- result = rustls_client_session_new(
- backend->config, conn->host.name, &session);
- if(result != RUSTLS_RESULT_OK) {
- rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
- failf(data, "failed to create client session: %.*s", errorlen, errorbuf);
- return CURLE_COULDNT_CONNECT;
- }
- backend->session = session;
connssl->state = ssl_connection_negotiating;
}
+ session = backend->session;
+
/* Read/write data until the handshake is done or the socket would block. */
for(;;) {
/*
@@ -434,7 +489,7 @@ cr_getsock(struct connectdata *conn, curl_socket_t *socks)
static void *
cr_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
+ CURLINFO info UNUSED_PARAM)
{
struct ssl_backend_data *backend = connssl->backend;
return &backend->session;
@@ -442,7 +497,7 @@ cr_get_internals(struct ssl_connect_data *connssl,
static void
cr_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+ int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;