ngtcp2: verify the server cert on connect (quictls)
Make ngtcp2+quictls correctly acknowledge `CURLOPT_SSL_VERIFYPEER` and `CURLOPT_SSL_VERIFYHOST`. The name check now uses a function from lib/vtls/openssl.c which will need attention for when TLS is not done by OpenSSL or is disabled while QUIC is enabled. Possibly the servercert() function in openssl.c should be adjusted to be able to use for both regular TLS and QUIC. Ref: #8173 Closes #8178
This commit is contained in:
Родитель
1914465cf1
Коммит
c148f0f551
|
@ -894,6 +894,8 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
|
|||
connkeep(conn, "HTTP/3 default");
|
||||
return CURLE_OK;
|
||||
}
|
||||
/* When a QUIC connect attempt fails, the better error explanation is in
|
||||
'result' and not in errno */
|
||||
if(result) {
|
||||
conn->tempsock[i] = CURL_SOCKET_BAD;
|
||||
error = SOCKERRNO;
|
||||
|
@ -977,6 +979,13 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
|
|||
char buffer[STRERROR_LEN];
|
||||
Curl_printable_address(conn->tempaddr[i], ipaddress,
|
||||
sizeof(ipaddress));
|
||||
#ifdef ENABLE_QUIC
|
||||
if(conn->transport == TRNSPRT_QUIC) {
|
||||
infof(data, "connect to %s port %u failed: %s",
|
||||
ipaddress, conn->port, curl_easy_strerror(result));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
infof(data, "connect to %s port %u failed: %s",
|
||||
ipaddress, conn->port,
|
||||
Curl_strerror(error, buffer, sizeof(buffer)));
|
||||
|
@ -988,12 +997,14 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
|
|||
ainext(conn, i, TRUE);
|
||||
status = trynextip(data, conn, sockindex, i);
|
||||
if((status != CURLE_COULDNT_CONNECT) ||
|
||||
conn->tempsock[other] == CURL_SOCKET_BAD)
|
||||
conn->tempsock[other] == CURL_SOCKET_BAD) {
|
||||
/* the last attempt failed and no other sockets remain open */
|
||||
if(!result)
|
||||
result = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we've checked whether we are connected, check whether we've
|
||||
|
@ -1016,6 +1027,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
|
|||
/* no more addresses to try */
|
||||
const char *hostname;
|
||||
char buffer[STRERROR_LEN];
|
||||
CURLcode failreason = result;
|
||||
|
||||
/* if the first address family runs out of addresses to try before the
|
||||
happy eyeball timeout, go ahead and try the next family now */
|
||||
|
@ -1023,6 +1035,8 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
|
|||
if(!result)
|
||||
return result;
|
||||
|
||||
result = failreason;
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(conn->bits.socksproxy)
|
||||
hostname = conn->socks_proxy.host.name;
|
||||
|
@ -1039,6 +1053,10 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
|
|||
"%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
|
||||
hostname, conn->port,
|
||||
Curl_timediff(now, data->progress.t_startsingle),
|
||||
#ifdef ENABLE_QUIC
|
||||
(conn->transport == TRNSPRT_QUIC) ?
|
||||
curl_easy_strerror(result) :
|
||||
#endif
|
||||
Curl_strerror(error, buffer, sizeof(buffer)));
|
||||
|
||||
Curl_quic_disconnect(data, conn, 0);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#ifdef USE_OPENSSL
|
||||
#include <openssl/err.h>
|
||||
#include <ngtcp2/ngtcp2_crypto_openssl.h>
|
||||
#include "vtls/openssl.h"
|
||||
#elif defined(USE_GNUTLS)
|
||||
#include <ngtcp2/ngtcp2_crypto_gnutls.h>
|
||||
#endif
|
||||
|
@ -287,6 +288,27 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -1638,7 +1660,8 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
|
|||
return sent;
|
||||
}
|
||||
|
||||
static void ng_has_connected(struct connectdata *conn, int tempindex)
|
||||
static CURLcode ng_has_connected(struct Curl_easy *data,
|
||||
struct connectdata *conn, int tempindex)
|
||||
{
|
||||
conn->recv[FIRSTSOCKET] = ngh3_stream_recv;
|
||||
conn->send[FIRSTSOCKET] = ngh3_stream_send;
|
||||
|
@ -1647,6 +1670,27 @@ static void ng_has_connected(struct connectdata *conn, int tempindex)
|
|||
conn->httpversion = 30;
|
||||
conn->bundle->multiuse = BUNDLE_MULTIPLEX;
|
||||
conn->quic = &conn->hequic[tempindex];
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
if(conn->ssl_config.verifyhost) {
|
||||
X509 *server_cert;
|
||||
CURLcode result;
|
||||
server_cert = SSL_get_peer_certificate(conn->quic->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");
|
||||
#else
|
||||
(void)data;
|
||||
#endif
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1671,7 +1715,7 @@ CURLcode Curl_quic_is_connected(struct Curl_easy *data,
|
|||
|
||||
if(ngtcp2_conn_get_handshake_completed(qs->qconn)) {
|
||||
*done = TRUE;
|
||||
ng_has_connected(conn, sockindex);
|
||||
result = ng_has_connected(data, conn, sockindex);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1718,6 +1762,10 @@ static CURLcode ng_process_ingress(struct Curl_easy *data,
|
|||
rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts);
|
||||
if(rv) {
|
||||
/* TODO Send CONNECTION_CLOSE if possible */
|
||||
if(rv == NGTCP2_ERR_CRYPTO)
|
||||
/* this is a "TLS problem", but a failed certificate verification
|
||||
is a common reason for this */
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
return CURLE_RECV_ERROR;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1673,8 +1673,9 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
|
|||
hostname. In this case, the iPAddress subjectAltName must be present
|
||||
in the certificate and must exactly match the IP in the URI.
|
||||
|
||||
This function is now used from ngtcp2 (QUIC) as well.
|
||||
*/
|
||||
static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
X509 *server_cert)
|
||||
{
|
||||
bool matched = FALSE;
|
||||
|
@ -3923,7 +3924,7 @@ static CURLcode servercert(struct Curl_easy *data,
|
|||
BIO_free(mem);
|
||||
|
||||
if(SSL_CONN_CONFIG(verifyhost)) {
|
||||
result = verifyhost(data, conn, backend->server_cert);
|
||||
result = Curl_ossl_verifyhost(data, conn, backend->server_cert);
|
||||
if(result) {
|
||||
X509_free(backend->server_cert);
|
||||
backend->server_cert = NULL;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2021, 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
|
||||
|
@ -26,11 +26,15 @@
|
|||
|
||||
#ifdef USE_OPENSSL
|
||||
/*
|
||||
* This header should only be needed to get included by vtls.c and openssl.c
|
||||
* This header should only be needed to get included by vtls.c, openssl.c
|
||||
* and ngtcp2.c
|
||||
*/
|
||||
|
||||
#include <openssl/x509v3.h>
|
||||
#include "urldata.h"
|
||||
|
||||
CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
|
||||
X509 *server_cert);
|
||||
extern const struct Curl_ssl Curl_ssl_openssl;
|
||||
|
||||
#endif /* USE_OPENSSL */
|
||||
|
|
Загрузка…
Ссылка в новой задаче