]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
rustls: use ALPN
authorJacob Hoffman-Andrews <github@hoffman-andrews.com>
Sun, 25 Apr 2021 01:02:24 +0000 (18:02 -0700)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 30 Apr 2021 06:27:37 +0000 (08:27 +0200)
Update required rustls to 0.5.0

Closes #6960

.travis.yml
docs/RUSTLS.md
lib/vtls/rustls.c

index 18bc79ff0e4a07f8c4465bdfac58e86f855b6f6c..72ff1c138071912e55a9f58c342c7823060c1fe7 100644 (file)
@@ -125,7 +125,7 @@ jobs:
         - libbrotli-dev
         - libzstd-dev
   - env:
-    - T=debug-rustls RUSTLS_VERSION="v0.4.0" C="--with-rustls=$HOME/crust"
+    - T=debug-rustls RUSTLS_VERSION="v0.5.0" C="--with-rustls=$HOME/crust"
     addons:
       apt:
         <<: *common_apt
index 39d96ab600723345d755a526393e1a025915a6d5..569002c06aa6b85e65a5310db6df75ff229d059a 100644 (file)
@@ -3,7 +3,7 @@
 [Rustls is a TLS backend written in Rust.](https://docs.rs/rustls/). Curl can
 be built to use it as an alternative to OpenSSL or other TLS backends. We use
 the [crustls C bindings](https://github.com/abetterinternet/crustls/). This
-version of curl depends on version v0.4.0 of crustls.
+version of curl depends on version v0.5.0 of crustls.
 
 # Building with rustls
 
@@ -12,7 +12,7 @@ First, [install Rust](https://rustup.rs/).
 Next, check out, build, and install the appropriate version of crustls:
 
     % cargo install cbindgen
-    % git clone https://github.com/abetterinternet/crustls/ -b v0.4.0
+    % git clone https://github.com/abetterinternet/crustls/ -b v0.5.0
     % cd crustls
     % make
     % make DESTDIR=${HOME}/crustls-built/ install
index 282bcfef06f16e2a4244bdeb14d8607612a78dc2..9dfbd2c3c4c20c5b57357db8acfb4cd1d9ca58f9 100644 (file)
@@ -321,6 +321,10 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
   char errorbuf[256];
   size_t errorlen;
   int result;
+  rustls_slice_bytes alpn[2] = {
+    { (const uint8_t *)ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH },
+    { (const uint8_t *)ALPN_H2, ALPN_H2_LENGTH },
+  };
 
   backend->tlsbuf = calloc(TLSBUF_SIZE, 1);
   if(!backend->tlsbuf) {
@@ -328,6 +332,13 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
   }
 
   config_builder = rustls_client_config_builder_new();
+#ifdef USE_HTTP2
+  infof(data, "offering ALPN for HTTP/1.1 and HTTP/2\n");
+  rustls_client_config_builder_set_protocols(config_builder, alpn, 2);
+#else
+  infof(data, "offering ALPN for HTTP/1.1 only\n");
+  rustls_client_config_builder_set_protocols(config_builder, alpn, 1);
+#endif
   if(!verifypeer) {
     rustls_client_config_builder_dangerous_set_certificate_verifier(
       config_builder, cr_verify_none, NULL);
@@ -372,6 +383,39 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
   return CURLE_OK;
 }
 
+static void
+cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
+  const struct rustls_client_session *session)
+{
+  const uint8_t *protocol = NULL;
+  size_t len = 0;
+
+  rustls_client_session_get_alpn_protocol(session, &protocol, &len);
+  if(NULL == protocol) {
+    infof(data, "ALPN, server did not agree to a protocol\n");
+    return;
+  }
+
+#ifdef USE_HTTP2
+  if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) {
+    infof(data, "ALPN, negotiated h2\n");
+    conn->negnpn = CURL_HTTP_VERSION_2;
+  }
+  else
+#endif
+  if(len == ALPN_HTTP_1_1_LENGTH &&
+      0 == memcmp(ALPN_HTTP_1_1, protocol, len)) {
+    infof(data, "ALPN, negotiated http/1.1\n");
+    conn->negnpn = CURL_HTTP_VERSION_1_1;
+  }
+  else {
+    infof(data, "ALPN, negotiated an unrecognized protocol\n");
+  }
+
+  Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
+                      BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
+}
+
 static CURLcode
 cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
                        int sockindex, bool *done)
@@ -411,6 +455,9 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
       infof(data, "Done handshaking\n");
       /* Done with the handshake. Set up callbacks to send/receive data. */
       connssl->state = ssl_connection_complete;
+
+      cr_set_negotiated_alpn(data, conn, session);
+
       conn->recv[sockindex] = cr_recv;
       conn->send[sockindex] = cr_send;
       *done = TRUE;