summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlessandro Ghedini <alessandro@cloudflare.com>2022-01-13 13:43:20 +0000
committerDaniel Stenberg <daniel@haxx.se>2022-01-15 17:47:00 +0100
commit3aee3612b466418612c685cc9dfb2878ff3ad89c (patch)
treeef1438d2be1797b9a0c1a48202821e89c79e8af3
parent7053c9138f3193825342b4564666b6cf48576b3b (diff)
downloadcurl-3aee3612b466418612c685cc9dfb2878ff3ad89c.tar.gz
quiche: verify the server cert on connect
Similarly to c148f0f551f9bea0e3d0, make quiche correctly acknowledge `CURLOPT_SSL_VERIFYPEER` and `CURLOPT_SSL_VERIFYHOST`. Fixes #8173 Closes #8275
-rw-r--r--lib/vquic/quiche.c119
-rw-r--r--lib/vquic/quiche.h5
2 files changed, 109 insertions, 15 deletions
diff --git a/lib/vquic/quiche.c b/lib/vquic/quiche.c
index f7577605c..1bff3753e 100644
--- a/lib/vquic/quiche.c
+++ b/lib/vquic/quiche.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -25,6 +25,7 @@
#ifdef USE_QUICHE
#include <quiche.h>
#include <openssl/err.h>
+#include <openssl/ssl.h>
#include "urldata.h"
#include "sendf.h"
#include "strdup.h"
@@ -35,6 +36,8 @@
#include "connect.h"
#include "strerror.h"
#include "vquic.h"
+#include "vtls/openssl.h"
+#include "vtls/keylog.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -172,6 +175,68 @@ static void quiche_debug_log(const char *line, void *argp)
}
#endif
+static void keylog_callback(const SSL *ssl, const char *line)
+{
+ (void)ssl;
+ Curl_tls_keylog_write_line(line);
+}
+
+static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
+{
+ SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
+
+ SSL_CTX_set_alpn_protos(ssl_ctx,
+ (const uint8_t *)QUICHE_H3_APPLICATION_PROTOCOL,
+ sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1);
+
+ SSL_CTX_set_default_verify_paths(ssl_ctx);
+
+ /* Open the file if a TLS or QUIC backend has not done this before. */
+ Curl_tls_keylog_open();
+ if(Curl_tls_keylog_enabled()) {
+ SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
+ }
+
+ {
+ struct connectdata *conn = data->conn;
+ const char * const ssl_cafile = conn->ssl_config.CAfile;
+ const char * const ssl_capath = conn->ssl_config.CApath;
+
+ if(conn->ssl_config.verifypeer) {
+ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
+ /* tell OpenSSL where to find CA certificates that are used to verify
+ the server's certificate. */
+ if(!SSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:"
+ " CAfile: %s CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ return NULL;
+ }
+ infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+ infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+ }
+ }
+ return ssl_ctx;
+}
+
+static int quic_init_ssl(struct quicsocket *qs, struct connectdata *conn)
+{
+ /* this will need some attention when HTTPS proxy over QUIC get fixed */
+ const char * const hostname = conn->host.name;
+
+ DEBUGASSERT(!qs->ssl);
+ qs->ssl = SSL_new(qs->sslctx);
+
+ SSL_set_app_data(qs->ssl, qs);
+
+ /* set SNI */
+ SSL_set_tlsext_host_name(qs->ssl, hostname);
+ return 0;
+}
+
+
CURLcode Curl_quic_connect(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t sockfd,
int sockindex,
@@ -179,7 +244,6 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
{
CURLcode result;
struct quicsocket *qs = &conn->hequic[sockindex];
- char *keylog_file = NULL;
char ipbuf[40];
int port;
@@ -216,25 +280,25 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
sizeof(QUICHE_H3_APPLICATION_PROTOCOL)
- 1);
+ qs->sslctx = quic_ssl_ctx(data);
+ if(!qs->sslctx)
+ return CURLE_QUIC_CONNECT_ERROR;
+
+ if(quic_init_ssl(qs, conn))
+ return CURLE_QUIC_CONNECT_ERROR;
+
result = Curl_rand(data, qs->scid, sizeof(qs->scid));
if(result)
return result;
- keylog_file = getenv("SSLKEYLOGFILE");
-
- if(keylog_file)
- quiche_config_log_keys(qs->cfg);
-
- qs->conn = quiche_connect(conn->host.name, (const uint8_t *) qs->scid,
- sizeof(qs->scid), addr, addrlen, qs->cfg);
+ qs->conn = quiche_conn_new_with_tls((const uint8_t *) qs->scid,
+ sizeof(qs->scid), NULL, 0, addr, addrlen,
+ qs->cfg, qs->ssl, false);
if(!qs->conn) {
failf(data, "can't create quiche connection");
return CURLE_OUT_OF_MEMORY;
}
- if(keylog_file)
- quiche_conn_set_keylog_path(qs->conn, keylog_file);
-
/* Known to not work on Windows */
#if !defined(WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD)
{
@@ -284,7 +348,8 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode quiche_has_connected(struct connectdata *conn,
+static CURLcode quiche_has_connected(struct Curl_easy *data,
+ struct connectdata *conn,
int sockindex,
int tempindex)
{
@@ -298,6 +363,21 @@ static CURLcode quiche_has_connected(struct connectdata *conn,
conn->httpversion = 30;
conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+ if(conn->ssl_config.verifyhost) {
+ X509 *server_cert;
+ server_cert = SSL_get_peer_certificate(qs->ssl);
+ if(!server_cert) {
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ result = Curl_ossl_verifyhost(data, conn, server_cert);
+ X509_free(server_cert);
+ if(result)
+ return result;
+ infof(data, "Verified certificate just fine");
+ }
+ else
+ infof(data, "Skipped certificate verification");
+
qs->h3config = quiche_h3_config_new();
if(!qs->h3config)
return CURLE_OUT_OF_MEMORY;
@@ -344,7 +424,7 @@ CURLcode Curl_quic_is_connected(struct Curl_easy *data,
if(quiche_conn_is_established(qs->conn)) {
*done = TRUE;
- result = quiche_has_connected(conn, 0, sockindex);
+ result = quiche_has_connected(data, conn, 0, sockindex);
DEBUGF(infof(data, "quiche established connection!"));
}
@@ -392,7 +472,18 @@ static CURLcode process_ingress(struct Curl_easy *data, int sockfd,
break;
if(recvd < 0) {
+ if(QUICHE_ERR_TLS_FAIL == recvd) {
+ long verify_ok = SSL_get_verify_result(qs->ssl);
+ if(verify_ok != X509_V_OK) {
+ failf(data, "SSL certificate problem: %s",
+ X509_verify_cert_error_string(verify_ok));
+
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+
failf(data, "quiche_conn_recv() == %zd", recvd);
+
return CURLE_RECV_ERROR;
}
} while(1);
diff --git a/lib/vquic/quiche.h b/lib/vquic/quiche.h
index d311e9988..4a079d37b 100644
--- a/lib/vquic/quiche.h
+++ b/lib/vquic/quiche.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -27,6 +27,7 @@
#ifdef USE_QUICHE
#include <quiche.h>
+#include <openssl/ssl.h>
struct quic_handshake {
char *buf; /* pointer to the buffer */
@@ -43,6 +44,8 @@ struct quicsocket {
uint8_t scid[QUICHE_MAX_CONN_ID_LEN];
curl_socket_t sockfd;
uint32_t version;
+ SSL_CTX *sslctx;
+ SSL *ssl;
};
#endif