mirror of
https://github.com/curl/curl.git
synced 2026-05-30 05:17:30 +03:00
gnutls: use common gnutls init and verify code for ngtcp2
Closes #10007
This commit is contained in:
parent
b8ffb02e84
commit
27ec767ebd
4 changed files with 352 additions and 312 deletions
|
|
@ -27,6 +27,7 @@
|
|||
#ifdef USE_NGTCP2
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
#include <openssl/err.h>
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
|
|
@ -42,6 +43,7 @@
|
|||
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
|
||||
#include "vtls/wolfssl.h"
|
||||
#endif
|
||||
|
||||
#include "urldata.h"
|
||||
#include "sendf.h"
|
||||
#include "strdup.h"
|
||||
|
|
@ -321,13 +323,17 @@ static CURLcode quic_set_client_cert(struct Curl_easy *data,
|
|||
|
||||
/** SSL callbacks ***/
|
||||
|
||||
static int quic_init_ssl(struct quicsocket *qs)
|
||||
static CURLcode quic_init_ssl(struct quicsocket *qs,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
const uint8_t *alpn = NULL;
|
||||
size_t alpnlen = 0;
|
||||
/* this will need some attention when HTTPS proxy over QUIC get fixed */
|
||||
const char * const hostname = qs->conn->host.name;
|
||||
|
||||
(void)data;
|
||||
(void)conn;
|
||||
DEBUGASSERT(!qs->ssl);
|
||||
qs->ssl = SSL_new(qs->sslctx);
|
||||
|
||||
|
|
@ -342,64 +348,49 @@ static int quic_init_ssl(struct quicsocket *qs)
|
|||
|
||||
/* set SNI */
|
||||
SSL_set_tlsext_host_name(qs->ssl, hostname);
|
||||
return 0;
|
||||
return CURLE_OK;
|
||||
}
|
||||
#elif defined(USE_GNUTLS)
|
||||
static int quic_init_ssl(struct quicsocket *qs)
|
||||
static CURLcode quic_init_ssl(struct quicsocket *qs,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
CURLcode result;
|
||||
gnutls_datum_t alpn[2];
|
||||
/* this will need some attention when HTTPS proxy over QUIC get fixed */
|
||||
const char * const hostname = qs->conn->host.name;
|
||||
long * const pverifyresult = &data->set.ssl.certverifyresult;
|
||||
int rc;
|
||||
|
||||
DEBUGASSERT(!qs->ssl);
|
||||
DEBUGASSERT(qs->gtls == NULL);
|
||||
qs->gtls = calloc(1, sizeof(*(qs->gtls)));
|
||||
if(!qs->gtls)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
gnutls_init(&qs->ssl, GNUTLS_CLIENT);
|
||||
gnutls_session_set_ptr(qs->ssl, &qs->conn_ref);
|
||||
result = gtls_client_init(data, &conn->ssl_config, &data->set.ssl,
|
||||
hostname, qs->gtls, pverifyresult);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(ngtcp2_crypto_gnutls_configure_client_session(qs->ssl) != 0) {
|
||||
gnutls_session_set_ptr(qs->gtls->session, &qs->conn_ref);
|
||||
|
||||
if(ngtcp2_crypto_gnutls_configure_client_session(qs->gtls->session) != 0) {
|
||||
H3BUGF(fprintf(stderr,
|
||||
"ngtcp2_crypto_gnutls_configure_client_session failed\n"));
|
||||
return 1;
|
||||
return CURLE_QUIC_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL);
|
||||
rc = gnutls_priority_set_direct(qs->gtls->session, QUIC_PRIORITY, NULL);
|
||||
if(rc < 0) {
|
||||
H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n",
|
||||
gnutls_strerror(rc)));
|
||||
return 1;
|
||||
return CURLE_QUIC_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
/* Open the file if a TLS or QUIC backend has not done this before. */
|
||||
Curl_tls_keylog_open();
|
||||
if(Curl_tls_keylog_enabled()) {
|
||||
gnutls_session_set_keylog_function(qs->ssl, keylog_callback);
|
||||
}
|
||||
|
||||
if(qs->cred)
|
||||
gnutls_certificate_free_credentials(qs->cred);
|
||||
|
||||
rc = gnutls_certificate_allocate_credentials(&qs->cred);
|
||||
if(rc < 0) {
|
||||
H3BUGF(fprintf(stderr,
|
||||
"gnutls_certificate_allocate_credentials failed: %s\n",
|
||||
gnutls_strerror(rc)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = gnutls_certificate_set_x509_system_trust(qs->cred);
|
||||
if(rc < 0) {
|
||||
H3BUGF(fprintf(stderr,
|
||||
"gnutls_certificate_set_x509_system_trust failed: %s\n",
|
||||
gnutls_strerror(rc)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred);
|
||||
if(rc < 0) {
|
||||
H3BUGF(fprintf(stderr, "gnutls_credentials_set failed: %s\n",
|
||||
gnutls_strerror(rc)));
|
||||
return 1;
|
||||
gnutls_session_set_keylog_function(qs->gtls->session, keylog_callback);
|
||||
}
|
||||
|
||||
/* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
|
||||
|
|
@ -408,11 +399,9 @@ static int quic_init_ssl(struct quicsocket *qs)
|
|||
alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1;
|
||||
alpn[1].size = sizeof(H3_ALPN_H3) - 2;
|
||||
|
||||
gnutls_alpn_set_protocols(qs->ssl, alpn, 2, GNUTLS_ALPN_MANDATORY);
|
||||
gnutls_alpn_set_protocols(qs->gtls->session, alpn, 2, GNUTLS_ALPN_MANDATORY);
|
||||
|
||||
/* set SNI */
|
||||
gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
|
||||
return 0;
|
||||
return CURLE_OK;
|
||||
}
|
||||
#elif defined(USE_WOLFSSL)
|
||||
|
||||
|
|
@ -487,13 +476,17 @@ static WOLFSSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
|
|||
|
||||
/** SSL callbacks ***/
|
||||
|
||||
static int quic_init_ssl(struct quicsocket *qs)
|
||||
static CURLcode quic_init_ssl(struct quicsocket *qs,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
const uint8_t *alpn = NULL;
|
||||
size_t alpnlen = 0;
|
||||
/* this will need some attention when HTTPS proxy over QUIC get fixed */
|
||||
const char * const hostname = qs->conn->host.name;
|
||||
|
||||
(void)data;
|
||||
(void)conn;
|
||||
DEBUGASSERT(!qs->ssl);
|
||||
qs->ssl = SSL_new(qs->sslctx);
|
||||
|
||||
|
|
@ -510,7 +503,7 @@ static int quic_init_ssl(struct quicsocket *qs)
|
|||
wolfSSL_UseSNI(qs->ssl, WOLFSSL_SNI_HOST_NAME,
|
||||
hostname, (unsigned short)strlen(hostname));
|
||||
|
||||
return 0;
|
||||
return CURLE_OK;
|
||||
}
|
||||
#endif /* defined(USE_WOLFSSL) */
|
||||
|
||||
|
|
@ -815,8 +808,9 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
|
|||
return CURLE_QUIC_CONNECT_ERROR;
|
||||
#endif
|
||||
|
||||
if(quic_init_ssl(qs))
|
||||
return CURLE_QUIC_CONNECT_ERROR;
|
||||
result = quic_init_ssl(qs, data, conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
qs->dcid.datalen = NGTCP2_MAX_CIDLEN;
|
||||
result = Curl_rand(data, qs->dcid.data, NGTCP2_MAX_CIDLEN);
|
||||
|
|
@ -848,7 +842,11 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
|
|||
if(rc)
|
||||
return CURLE_QUIC_CONNECT_ERROR;
|
||||
|
||||
#ifdef USE_GNUTLS
|
||||
ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->gtls->session);
|
||||
#else
|
||||
ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->ssl);
|
||||
#endif
|
||||
|
||||
ngtcp2_connection_close_error_default(&qs->last_error);
|
||||
|
||||
|
|
@ -935,29 +933,29 @@ static void qs_disconnect(struct quicsocket *qs)
|
|||
close(qs->qlogfd);
|
||||
qs->qlogfd = -1;
|
||||
}
|
||||
if(qs->ssl)
|
||||
#ifdef USE_OPENSSL
|
||||
if(qs->ssl)
|
||||
SSL_free(qs->ssl);
|
||||
#elif defined(USE_GNUTLS)
|
||||
gnutls_deinit(qs->ssl);
|
||||
#elif defined(USE_WOLFSSL)
|
||||
wolfSSL_free(qs->ssl);
|
||||
#endif
|
||||
qs->ssl = NULL;
|
||||
#ifdef USE_GNUTLS
|
||||
if(qs->cred) {
|
||||
gnutls_certificate_free_credentials(qs->cred);
|
||||
qs->cred = NULL;
|
||||
SSL_CTX_free(qs->sslctx);
|
||||
#elif defined(USE_GNUTLS)
|
||||
if(qs->gtls) {
|
||||
if(qs->gtls->cred)
|
||||
gnutls_certificate_free_credentials(qs->gtls->cred);
|
||||
if(qs->gtls->session)
|
||||
gnutls_deinit(qs->gtls->session);
|
||||
free(qs->gtls);
|
||||
qs->gtls = NULL;
|
||||
}
|
||||
#elif defined(USE_WOLFSSL)
|
||||
if(qs->ssl)
|
||||
wolfSSL_free(qs->ssl);
|
||||
qs->ssl = NULL;
|
||||
wolfSSL_CTX_free(qs->sslctx);
|
||||
#endif
|
||||
free(qs->pktbuf);
|
||||
nghttp3_conn_del(qs->h3conn);
|
||||
ngtcp2_conn_del(qs->qconn);
|
||||
#ifdef USE_OPENSSL
|
||||
SSL_CTX_free(qs->sslctx);
|
||||
#elif defined(USE_WOLFSSL)
|
||||
wolfSSL_CTX_free(qs->sslctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Curl_quic_disconnect(struct Curl_easy *data,
|
||||
|
|
@ -1675,6 +1673,15 @@ static CURLcode ng_has_connected(struct Curl_easy *data,
|
|||
struct connectdata *conn, int tempindex)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
const char *hostname, *disp_hostname;
|
||||
int port;
|
||||
char *snihost;
|
||||
|
||||
Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
|
||||
snihost = Curl_ssl_snihost(data, hostname, NULL);
|
||||
if(!snihost)
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
|
||||
conn->recv[FIRSTSOCKET] = ngh3_stream_recv;
|
||||
conn->send[FIRSTSOCKET] = ngh3_stream_send;
|
||||
conn->handler = &Curl_handler_http3;
|
||||
|
|
@ -1694,22 +1701,18 @@ static CURLcode ng_has_connected(struct Curl_easy *data,
|
|||
X509_free(server_cert);
|
||||
if(result)
|
||||
return result;
|
||||
infof(data, "Verified certificate just fine");
|
||||
#elif defined(USE_GNUTLS)
|
||||
result = Curl_gtls_verifyserver(conn->cfilter[FIRSTSOCKET],
|
||||
data, conn->quic->ssl);
|
||||
result = Curl_gtls_verifyserver(data, conn->quic->gtls->session,
|
||||
&conn->ssl_config, &data->set.ssl,
|
||||
hostname, disp_hostname,
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
|
||||
if(result)
|
||||
return result;
|
||||
#elif defined(USE_WOLFSSL)
|
||||
const char *hostname, *disp_hostname;
|
||||
int port;
|
||||
char *snihost;
|
||||
|
||||
Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
|
||||
snihost = Curl_ssl_snihost(data, hostname, NULL);
|
||||
if(!snihost ||
|
||||
(wolfSSL_check_domain_name(conn->quic->ssl, snihost) == SSL_FAILURE))
|
||||
if(wolfSSL_check_domain_name(conn->quic->ssl, snihost) == SSL_FAILURE)
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
infof(data, "Verified certificate just fine");
|
||||
#endif
|
||||
infof(data, "Verified certificate just fine");
|
||||
}
|
||||
else
|
||||
infof(data, "Skipped certificate verification");
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@
|
|||
#include <nghttp3/nghttp3.h>
|
||||
#ifdef USE_OPENSSL
|
||||
#include <openssl/ssl.h>
|
||||
#elif defined(USE_GNUTLS)
|
||||
#include <gnutls/gnutls.h>
|
||||
#elif defined(USE_WOLFSSL)
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/quic.h>
|
||||
#endif
|
||||
|
||||
struct gtls_instance;
|
||||
|
||||
struct blocked_pkt {
|
||||
const uint8_t *pkt;
|
||||
size_t pktlen;
|
||||
|
|
@ -64,8 +64,7 @@ struct quicsocket {
|
|||
SSL_CTX *sslctx;
|
||||
SSL *ssl;
|
||||
#elif defined(USE_GNUTLS)
|
||||
gnutls_certificate_credentials_t cred;
|
||||
gnutls_session_t ssl;
|
||||
struct gtls_instance *gtls;
|
||||
#elif defined(USE_WOLFSSL)
|
||||
WOLFSSL_CTX *sslctx;
|
||||
WOLFSSL *ssl;
|
||||
|
|
|
|||
466
lib/vtls/gtls.c
466
lib/vtls/gtls.c
|
|
@ -59,14 +59,6 @@
|
|||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
#ifdef HAVE_GNUTLS_SRP
|
||||
/* the function exists */
|
||||
#ifdef USE_TLS_SRP
|
||||
/* the functionality is not disabled */
|
||||
#define USE_GNUTLS_SRP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Enable GnuTLS debugging by defining GTLSDEBUG */
|
||||
/*#define GTLSDEBUG */
|
||||
|
||||
|
|
@ -85,11 +77,7 @@ static bool gtls_inited = FALSE;
|
|||
# include <gnutls/ocsp.h>
|
||||
|
||||
struct ssl_backend_data {
|
||||
gnutls_session_t session;
|
||||
gnutls_certificate_credentials_t cred;
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
gnutls_srp_client_credentials_t srp_client_cred;
|
||||
#endif
|
||||
struct gtls_instance gtls;
|
||||
};
|
||||
|
||||
static ssize_t gtls_push(void *s, const void *buf, size_t blen)
|
||||
|
|
@ -103,7 +91,7 @@ static ssize_t gtls_push(void *s, const void *buf, size_t blen)
|
|||
DEBUGASSERT(data);
|
||||
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
|
||||
if(nwritten < 0) {
|
||||
gnutls_transport_set_errno(connssl->backend->session,
|
||||
gnutls_transport_set_errno(connssl->backend->gtls.session,
|
||||
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
|
||||
nwritten = -1;
|
||||
}
|
||||
|
|
@ -121,7 +109,7 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen)
|
|||
DEBUGASSERT(data);
|
||||
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
|
||||
if(nread < 0) {
|
||||
gnutls_transport_set_errno(connssl->backend->session,
|
||||
gnutls_transport_set_errno(connssl->backend->gtls.session,
|
||||
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
|
||||
nread = -1;
|
||||
}
|
||||
|
|
@ -229,7 +217,7 @@ static CURLcode handshake(struct Curl_cfilter *cf,
|
|||
curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
session = backend->session;
|
||||
session = backend->gtls.session;
|
||||
|
||||
for(;;) {
|
||||
timediff_t timeout_ms;
|
||||
|
|
@ -334,12 +322,11 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
|
|||
#define GNUTLS_SRP "+SRP"
|
||||
|
||||
static CURLcode
|
||||
set_ssl_version_min_max(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
set_ssl_version_min_max(struct Curl_easy *data,
|
||||
struct ssl_primary_config *conn_config,
|
||||
const char **prioritylist,
|
||||
const char *tls13support)
|
||||
{
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
long ssl_version = conn_config->version;
|
||||
long ssl_version_max = conn_config->version_max;
|
||||
|
||||
|
|
@ -407,20 +394,16 @@ set_ssl_version_min_max(struct Curl_cfilter *cf,
|
|||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
CURLcode gtls_client_init(struct Curl_easy *data,
|
||||
struct ssl_primary_config *config,
|
||||
struct ssl_config_data *ssl_config,
|
||||
const char *hostname,
|
||||
struct gtls_instance *gtls,
|
||||
long *pverifyresult)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
unsigned int init_flags;
|
||||
gnutls_session_t session;
|
||||
int rc;
|
||||
bool sni = TRUE; /* default is SNI enabled */
|
||||
void *transport_ptr = NULL;
|
||||
gnutls_push_func gnutls_transport_push = NULL;
|
||||
gnutls_pull_func gnutls_transport_pull = NULL;
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr addr;
|
||||
#else
|
||||
|
|
@ -428,54 +411,44 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
#endif
|
||||
const char *prioritylist;
|
||||
const char *err = NULL;
|
||||
const char *hostname = connssl->hostname;
|
||||
long * const certverifyresult = &ssl_config->certverifyresult;
|
||||
const char *tls13support;
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
if(connssl->state == ssl_connection_complete)
|
||||
/* to make us tolerant against being called more than once for the
|
||||
same connection */
|
||||
return CURLE_OK;
|
||||
|
||||
if(!gtls_inited)
|
||||
gtls_init();
|
||||
|
||||
/* Initialize certverifyresult to OK */
|
||||
*certverifyresult = 0;
|
||||
*pverifyresult = 0;
|
||||
|
||||
if(conn_config->version == CURL_SSLVERSION_SSLv2) {
|
||||
if(config->version == CURL_SSLVERSION_SSLv2) {
|
||||
failf(data, "GnuTLS does not support SSLv2");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
else if(conn_config->version == CURL_SSLVERSION_SSLv3)
|
||||
else if(config->version == CURL_SSLVERSION_SSLv3)
|
||||
sni = FALSE; /* SSLv3 has no SNI */
|
||||
|
||||
/* allocate a cred struct */
|
||||
rc = gnutls_certificate_allocate_credentials(&backend->cred);
|
||||
rc = gnutls_certificate_allocate_credentials(>ls->cred);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
if((ssl_config->primary.authtype == CURL_TLSAUTH_SRP) &&
|
||||
if((config->authtype == CURL_TLSAUTH_SRP) &&
|
||||
Curl_auth_allowed_to_host(data)) {
|
||||
infof(data, "Using TLS-SRP username: %s",
|
||||
ssl_config->primary.username);
|
||||
infof(data, "Using TLS-SRP username: %s", config->username);
|
||||
|
||||
rc = gnutls_srp_allocate_client_credentials(&backend->srp_client_cred);
|
||||
rc = gnutls_srp_allocate_client_credentials(
|
||||
>ls->srp_client_cred);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
|
||||
gnutls_strerror(rc));
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rc = gnutls_srp_set_client_credentials(backend->srp_client_cred,
|
||||
ssl_config->primary.username,
|
||||
ssl_config->primary.password);
|
||||
rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
|
||||
config->username,
|
||||
config->password);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_srp_set_client_cred() failed: %s",
|
||||
gnutls_strerror(rc));
|
||||
|
|
@ -484,67 +457,63 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
}
|
||||
#endif
|
||||
|
||||
if(conn_config->CAfile) {
|
||||
if(config->CAfile) {
|
||||
/* set the trusted CA cert bundle file */
|
||||
gnutls_certificate_set_verify_flags(backend->cred,
|
||||
gnutls_certificate_set_verify_flags(gtls->cred,
|
||||
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
|
||||
|
||||
rc = gnutls_certificate_set_x509_trust_file(backend->cred,
|
||||
conn_config->CAfile,
|
||||
rc = gnutls_certificate_set_x509_trust_file(gtls->cred,
|
||||
config->CAfile,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
if(rc < 0) {
|
||||
infof(data, "error reading ca cert file %s (%s)",
|
||||
conn_config->CAfile, gnutls_strerror(rc));
|
||||
if(conn_config->verifypeer) {
|
||||
*certverifyresult = rc;
|
||||
config->CAfile, gnutls_strerror(rc));
|
||||
if(config->verifypeer) {
|
||||
*pverifyresult = rc;
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
}
|
||||
else
|
||||
infof(data, "found %d certificates in %s", rc,
|
||||
conn_config->CAfile);
|
||||
infof(data, "found %d certificates in %s", rc, config->CAfile);
|
||||
}
|
||||
|
||||
if(conn_config->CApath) {
|
||||
if(config->CApath) {
|
||||
/* set the trusted CA cert directory */
|
||||
rc = gnutls_certificate_set_x509_trust_dir(backend->cred,
|
||||
conn_config->CApath,
|
||||
rc = gnutls_certificate_set_x509_trust_dir(gtls->cred,
|
||||
config->CApath,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
if(rc < 0) {
|
||||
infof(data, "error reading ca cert file %s (%s)",
|
||||
conn_config->CApath, gnutls_strerror(rc));
|
||||
if(conn_config->verifypeer) {
|
||||
*certverifyresult = rc;
|
||||
config->CApath, gnutls_strerror(rc));
|
||||
if(config->verifypeer) {
|
||||
*pverifyresult = rc;
|
||||
return CURLE_SSL_CACERT_BADFILE;
|
||||
}
|
||||
}
|
||||
else
|
||||
infof(data, "found %d certificates in %s",
|
||||
rc, conn_config->CApath);
|
||||
infof(data, "found %d certificates in %s", rc, config->CApath);
|
||||
}
|
||||
|
||||
#ifdef CURL_CA_FALLBACK
|
||||
/* use system ca certificate store as fallback */
|
||||
if(conn_config->verifypeer &&
|
||||
!(conn_config->CAfile || conn_config->CApath)) {
|
||||
if(config->verifypeer && !(config->CAfile || config->CApath)) {
|
||||
/* this ignores errors on purpose */
|
||||
gnutls_certificate_set_x509_system_trust(backend->cred);
|
||||
gnutls_certificate_set_x509_system_trust(gtls->cred);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(ssl_config->primary.CRLfile) {
|
||||
if(config->CRLfile) {
|
||||
/* set the CRL list file */
|
||||
rc = gnutls_certificate_set_x509_crl_file(backend->cred,
|
||||
ssl_config->primary.CRLfile,
|
||||
rc = gnutls_certificate_set_x509_crl_file(gtls->cred,
|
||||
config->CRLfile,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
if(rc < 0) {
|
||||
failf(data, "error reading crl file %s (%s)",
|
||||
ssl_config->primary.CRLfile, gnutls_strerror(rc));
|
||||
config->CRLfile, gnutls_strerror(rc));
|
||||
return CURLE_SSL_CRL_BADFILE;
|
||||
}
|
||||
else
|
||||
infof(data, "found %d CRL in %s",
|
||||
rc, ssl_config->primary.CRLfile);
|
||||
infof(data, "found %d CRL in %s", rc, config->CRLfile);
|
||||
}
|
||||
|
||||
/* Initialize TLS session as a client */
|
||||
|
|
@ -559,15 +528,12 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
init_flags |= GNUTLS_NO_TICKETS;
|
||||
#endif
|
||||
|
||||
rc = gnutls_init(&backend->session, init_flags);
|
||||
rc = gnutls_init(>ls->session, init_flags);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_init() failed: %d", rc);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
/* convenient assign */
|
||||
session = backend->session;
|
||||
|
||||
if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
|
||||
#ifdef ENABLE_IPV6
|
||||
(0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
|
||||
|
|
@ -575,15 +541,15 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
sni) {
|
||||
size_t snilen;
|
||||
char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
|
||||
if(!snihost || gnutls_server_name_set(session, GNUTLS_NAME_DNS, snihost,
|
||||
snilen) < 0) {
|
||||
if(!snihost || gnutls_server_name_set(gtls->session, GNUTLS_NAME_DNS,
|
||||
snihost, snilen) < 0) {
|
||||
failf(data, "Failed to set SNI");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use default priorities */
|
||||
rc = gnutls_set_default_priority(session);
|
||||
rc = gnutls_set_default_priority(gtls->session);
|
||||
if(rc != GNUTLS_E_SUCCESS)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
||||
|
|
@ -594,13 +560,13 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
* removed if a run-time error indicates that SRP is not supported by this
|
||||
* GnuTLS version */
|
||||
|
||||
if(conn_config->version == CURL_SSLVERSION_SSLv2 ||
|
||||
conn_config->version == CURL_SSLVERSION_SSLv3) {
|
||||
if(config->version == CURL_SSLVERSION_SSLv2 ||
|
||||
config->version == CURL_SSLVERSION_SSLv3) {
|
||||
failf(data, "GnuTLS does not support SSLv2 or SSLv3");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
if(conn_config->version == CURL_SSLVERSION_TLSv1_3) {
|
||||
if(config->version == CURL_SSLVERSION_TLSv1_3) {
|
||||
if(!tls13support) {
|
||||
failf(data, "This GnuTLS installation does not support TLS 1.3");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
|
@ -608,14 +574,14 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
}
|
||||
|
||||
/* At this point we know we have a supported TLS version, so set it */
|
||||
result = set_ssl_version_min_max(cf, data, &prioritylist, tls13support);
|
||||
result = set_ssl_version_min_max(data, config, &prioritylist, tls13support);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
/* Only add SRP to the cipher list if SRP is requested. Otherwise
|
||||
* GnuTLS will disable TLS 1.3 support. */
|
||||
if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP) {
|
||||
if(config->authtype == CURL_TLSAUTH_SRP) {
|
||||
size_t len = strlen(prioritylist);
|
||||
|
||||
char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1);
|
||||
|
|
@ -623,7 +589,7 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
return CURLE_OUT_OF_MEMORY;
|
||||
strcpy(prioritysrp, prioritylist);
|
||||
strcpy(prioritysrp + len, ":" GNUTLS_SRP);
|
||||
rc = gnutls_priority_set_direct(session, prioritysrp, &err);
|
||||
rc = gnutls_priority_set_direct(gtls->session, prioritysrp, &err);
|
||||
free(prioritysrp);
|
||||
|
||||
if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
|
||||
|
|
@ -633,7 +599,7 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
else {
|
||||
#endif
|
||||
infof(data, "GnuTLS ciphers: %s", prioritylist);
|
||||
rc = gnutls_priority_set_direct(session, prioritylist, &err);
|
||||
rc = gnutls_priority_set_direct(gtls->session, prioritylist, &err);
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
}
|
||||
#endif
|
||||
|
|
@ -644,6 +610,96 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
if(config->clientcert) {
|
||||
if(ssl_config->key_passwd) {
|
||||
const unsigned int supported_key_encryption_algorithms =
|
||||
GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
|
||||
GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
|
||||
GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
|
||||
GNUTLS_PKCS_USE_PBES2_AES_256;
|
||||
rc = gnutls_certificate_set_x509_key_file2(
|
||||
gtls->cred,
|
||||
config->clientcert,
|
||||
ssl_config->key ? ssl_config->key : config->clientcert,
|
||||
do_file_type(ssl_config->cert_type),
|
||||
ssl_config->key_passwd,
|
||||
supported_key_encryption_algorithms);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data,
|
||||
"error reading X.509 potentially-encrypted key file: %s",
|
||||
gnutls_strerror(rc));
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(gnutls_certificate_set_x509_key_file(
|
||||
gtls->cred,
|
||||
config->clientcert,
|
||||
ssl_config->key ? ssl_config->key : config->clientcert,
|
||||
do_file_type(ssl_config->cert_type) ) !=
|
||||
GNUTLS_E_SUCCESS) {
|
||||
failf(data, "error reading X.509 key or certificate file");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
/* put the credentials to the current session */
|
||||
if(config->authtype == CURL_TLSAUTH_SRP) {
|
||||
rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_SRP,
|
||||
gtls->srp_client_cred);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
|
||||
gtls->cred);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if(config->verifystatus) {
|
||||
rc = gnutls_ocsp_status_request_enable_client(gtls->session,
|
||||
NULL, 0, NULL);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode
|
||||
gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_backend_data *backend = connssl->backend;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
long * const pverifyresult = &ssl_config->certverifyresult;
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
if(connssl->state == ssl_connection_complete)
|
||||
/* to make us tolerant against being called more than once for the
|
||||
same connection */
|
||||
return CURLE_OK;
|
||||
|
||||
result = gtls_client_init(data, conn_config, ssl_config,
|
||||
connssl->hostname,
|
||||
&backend->gtls, pverifyresult);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(cf->conn->bits.tls_enable_alpn) {
|
||||
int cur = 0;
|
||||
gnutls_datum_t protocols[2];
|
||||
|
|
@ -666,99 +722,23 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
cur++;
|
||||
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1);
|
||||
|
||||
if(gnutls_alpn_set_protocols(session, protocols, cur, 0)) {
|
||||
if(gnutls_alpn_set_protocols(backend->gtls.session, protocols, cur, 0)) {
|
||||
failf(data, "failed setting ALPN");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if(ssl_config->primary.clientcert) {
|
||||
if(ssl_config->key_passwd) {
|
||||
const unsigned int supported_key_encryption_algorithms =
|
||||
GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
|
||||
GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
|
||||
GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
|
||||
GNUTLS_PKCS_USE_PBES2_AES_256;
|
||||
rc = gnutls_certificate_set_x509_key_file2(
|
||||
backend->cred,
|
||||
ssl_config->primary.clientcert,
|
||||
ssl_config->key ?
|
||||
ssl_config->key : ssl_config->primary.clientcert,
|
||||
do_file_type(ssl_config->cert_type),
|
||||
ssl_config->key_passwd,
|
||||
supported_key_encryption_algorithms);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data,
|
||||
"error reading X.509 potentially-encrypted key file: %s",
|
||||
gnutls_strerror(rc));
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(gnutls_certificate_set_x509_key_file(
|
||||
backend->cred,
|
||||
ssl_config->primary.clientcert,
|
||||
ssl_config->key ?
|
||||
ssl_config->key : ssl_config->primary.clientcert,
|
||||
do_file_type(ssl_config->cert_type) ) !=
|
||||
GNUTLS_E_SUCCESS) {
|
||||
failf(data, "error reading X.509 key or certificate file");
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
/* put the credentials to the current session */
|
||||
if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP) {
|
||||
rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
|
||||
backend->srp_client_cred);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
|
||||
backend->cred);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* push/pull through filter chain */
|
||||
transport_ptr = cf;
|
||||
gnutls_transport_push = gtls_push;
|
||||
gnutls_transport_pull = gtls_pull;
|
||||
|
||||
/* set the connection handle */
|
||||
gnutls_transport_set_ptr(session, transport_ptr);
|
||||
|
||||
/* register callback functions to send and receive data. */
|
||||
gnutls_transport_set_push_function(session, gnutls_transport_push);
|
||||
gnutls_transport_set_pull_function(session, gnutls_transport_pull);
|
||||
|
||||
if(conn_config->verifystatus) {
|
||||
rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
|
||||
if(rc != GNUTLS_E_SUCCESS) {
|
||||
failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* This might be a reconnect, so we check for a session ID in the cache
|
||||
to speed up things */
|
||||
if(ssl_config->primary.sessionid) {
|
||||
if(conn_config->sessionid) {
|
||||
void *ssl_sessionid;
|
||||
size_t ssl_idsize;
|
||||
|
||||
Curl_ssl_sessionid_lock(data);
|
||||
if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, &ssl_idsize)) {
|
||||
/* we got a session id, use it! */
|
||||
gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
|
||||
gnutls_session_set_data(backend->gtls.session,
|
||||
ssl_sessionid, ssl_idsize);
|
||||
|
||||
/* Informational message */
|
||||
infof(data, "SSL re-using session ID");
|
||||
|
|
@ -766,6 +746,11 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
Curl_ssl_sessionid_unlock(data);
|
||||
}
|
||||
|
||||
/* register callback functions and handle to send and receive data. */
|
||||
gnutls_transport_set_ptr(backend->gtls.session, cf);
|
||||
gnutls_transport_set_push_function(backend->gtls.session, gtls_push);
|
||||
gnutls_transport_set_pull_function(backend->gtls.session, gtls_pull);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
|
@ -828,13 +813,14 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
CURLcode
|
||||
Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
gnutls_session_t session)
|
||||
Curl_gtls_verifyserver(struct Curl_easy *data,
|
||||
gnutls_session_t session,
|
||||
struct ssl_primary_config *config,
|
||||
struct ssl_config_data *ssl_config,
|
||||
const char *hostname,
|
||||
const char *dispname,
|
||||
const char *pinned_key)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
unsigned int cert_list_size;
|
||||
const gnutls_datum_t *chainp;
|
||||
unsigned int verify_status = 0;
|
||||
|
|
@ -846,14 +832,12 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
time_t certclock;
|
||||
const char *ptr;
|
||||
int rc;
|
||||
gnutls_datum_t proto;
|
||||
CURLcode result = CURLE_OK;
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
unsigned int algo;
|
||||
unsigned int bits;
|
||||
gnutls_protocol_t version = gnutls_protocol_get_version(session);
|
||||
#endif
|
||||
const char *hostname = connssl->hostname;
|
||||
long * const certverifyresult = &ssl_config->certverifyresult;
|
||||
|
||||
/* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
|
||||
|
|
@ -872,13 +856,13 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
|
||||
chainp = gnutls_certificate_get_peers(session, &cert_list_size);
|
||||
if(!chainp) {
|
||||
if(conn_config->verifypeer ||
|
||||
conn_config->verifyhost ||
|
||||
conn_config->issuercert) {
|
||||
if(config->verifypeer ||
|
||||
config->verifyhost ||
|
||||
config->issuercert) {
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP
|
||||
&& ssl_config->primary.username
|
||||
&& !conn_config->verifypeer
|
||||
&& !config->verifypeer
|
||||
&& gnutls_cipher_get(session)) {
|
||||
/* no peer cert, but auth is ok if we have SRP user and cipher and no
|
||||
peer verify */
|
||||
|
|
@ -912,7 +896,7 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
}
|
||||
}
|
||||
|
||||
if(conn_config->verifypeer) {
|
||||
if(config->verifypeer) {
|
||||
/* This function will try to verify the peer's certificate and return its
|
||||
status (trusted, invalid etc.). The value of status should be one or
|
||||
more of the gnutls_certificate_status_t enumerated elements bitwise
|
||||
|
|
@ -931,9 +915,9 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
|
||||
/* verify_status is a bitmask of gnutls_certificate_status bits */
|
||||
if(verify_status & GNUTLS_CERT_INVALID) {
|
||||
if(conn_config->verifypeer) {
|
||||
if(config->verifypeer) {
|
||||
failf(data, "server certificate verification failed. CAfile: %s "
|
||||
"CRLfile: %s", conn_config->CAfile ? conn_config->CAfile:
|
||||
"CRLfile: %s", config->CAfile ? config->CAfile:
|
||||
"none",
|
||||
ssl_config->primary.CRLfile ?
|
||||
ssl_config->primary.CRLfile : "none");
|
||||
|
|
@ -948,7 +932,7 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
else
|
||||
infof(data, " server certificate verification SKIPPED");
|
||||
|
||||
if(conn_config->verifystatus) {
|
||||
if(config->verifystatus) {
|
||||
if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
|
||||
gnutls_datum_t status_request;
|
||||
gnutls_ocsp_resp_t ocsp_resp;
|
||||
|
|
@ -1059,21 +1043,21 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
gnutls_x509_crt_t format */
|
||||
gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
|
||||
|
||||
if(conn_config->issuercert) {
|
||||
if(config->issuercert) {
|
||||
gnutls_x509_crt_init(&x509_issuer);
|
||||
issuerp = load_file(conn_config->issuercert);
|
||||
issuerp = load_file(config->issuercert);
|
||||
gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
|
||||
rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
|
||||
gnutls_x509_crt_deinit(x509_issuer);
|
||||
unload_file(issuerp);
|
||||
if(rc <= 0) {
|
||||
failf(data, "server certificate issuer check failed (IssuerCert: %s)",
|
||||
conn_config->issuercert?conn_config->issuercert:"none");
|
||||
config->issuercert?config->issuercert:"none");
|
||||
gnutls_x509_crt_deinit(x509_cert);
|
||||
return CURLE_SSL_ISSUER_ERROR;
|
||||
}
|
||||
infof(data, " server certificate issuer check OK (Issuer Cert: %s)",
|
||||
conn_config->issuercert?conn_config->issuercert:"none");
|
||||
config->issuercert?config->issuercert:"none");
|
||||
}
|
||||
|
||||
size = sizeof(certname);
|
||||
|
|
@ -1136,15 +1120,15 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
}
|
||||
#endif
|
||||
if(!rc) {
|
||||
if(conn_config->verifyhost) {
|
||||
if(config->verifyhost) {
|
||||
failf(data, "SSL: certificate subject name (%s) does not match "
|
||||
"target host name '%s'", certname, connssl->dispname);
|
||||
"target host name '%s'", certname, dispname);
|
||||
gnutls_x509_crt_deinit(x509_cert);
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else
|
||||
infof(data, " common name: %s (does not match '%s')",
|
||||
certname, connssl->dispname);
|
||||
certname, dispname);
|
||||
}
|
||||
else
|
||||
infof(data, " common name: %s (matched)", certname);
|
||||
|
|
@ -1153,7 +1137,7 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
|
||||
|
||||
if(certclock == (time_t)-1) {
|
||||
if(conn_config->verifypeer) {
|
||||
if(config->verifypeer) {
|
||||
failf(data, "server cert expiration date verify failed");
|
||||
*certverifyresult = GNUTLS_CERT_EXPIRED;
|
||||
gnutls_x509_crt_deinit(x509_cert);
|
||||
|
|
@ -1164,7 +1148,7 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
}
|
||||
else {
|
||||
if(certclock < time(NULL)) {
|
||||
if(conn_config->verifypeer) {
|
||||
if(config->verifypeer) {
|
||||
failf(data, "server certificate expiration date has passed.");
|
||||
*certverifyresult = GNUTLS_CERT_EXPIRED;
|
||||
gnutls_x509_crt_deinit(x509_cert);
|
||||
|
|
@ -1180,7 +1164,7 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
certclock = gnutls_x509_crt_get_activation_time(x509_cert);
|
||||
|
||||
if(certclock == (time_t)-1) {
|
||||
if(conn_config->verifypeer) {
|
||||
if(config->verifypeer) {
|
||||
failf(data, "server cert activation date verify failed");
|
||||
*certverifyresult = GNUTLS_CERT_NOT_ACTIVATED;
|
||||
gnutls_x509_crt_deinit(x509_cert);
|
||||
|
|
@ -1191,7 +1175,7 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
}
|
||||
else {
|
||||
if(certclock > time(NULL)) {
|
||||
if(conn_config->verifypeer) {
|
||||
if(config->verifypeer) {
|
||||
failf(data, "server certificate not activated yet.");
|
||||
*certverifyresult = GNUTLS_CERT_NOT_ACTIVATED;
|
||||
gnutls_x509_crt_deinit(x509_cert);
|
||||
|
|
@ -1204,11 +1188,8 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
infof(data, " server certificate activation date OK");
|
||||
}
|
||||
|
||||
ptr = Curl_ssl_cf_is_proxy(cf)?
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
||||
if(ptr) {
|
||||
result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
|
||||
if(pinned_key) {
|
||||
result = pkp_pin_peer_pubkey(data, x509_cert, pinned_key);
|
||||
if(result != CURLE_OK) {
|
||||
failf(data, "SSL: public key does not match pinned public key");
|
||||
gnutls_x509_crt_deinit(x509_cert);
|
||||
|
|
@ -1264,7 +1245,31 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
|
||||
gnutls_x509_crt_deinit(x509_cert);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
gnutls_session_t session)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||
const char *pinned_key = Curl_ssl_cf_is_proxy(cf)?
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
|
||||
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
||||
CURLcode result;
|
||||
|
||||
result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config,
|
||||
connssl->hostname, connssl->dispname,
|
||||
pinned_key);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
if(cf->conn->bits.tls_enable_alpn) {
|
||||
gnutls_datum_t proto;
|
||||
int rc;
|
||||
|
||||
rc = gnutls_alpn_get_selected_protocol(session, &proto);
|
||||
if(rc == 0) {
|
||||
infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, proto.size,
|
||||
|
|
@ -1290,8 +1295,6 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
|
||||
}
|
||||
|
||||
connssl->state = ssl_connection_complete;
|
||||
|
||||
if(ssl_config->primary.sessionid) {
|
||||
/* we always unconditionally get the session id here, as even if we
|
||||
already got it from the cache and asked to use it in the connection, it
|
||||
|
|
@ -1334,10 +1337,10 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called after the TCP connect has completed. Setup the TLS
|
||||
* layer and do all necessary magic.
|
||||
|
|
@ -1378,12 +1381,13 @@ gtls_connect_common(struct Curl_cfilter *cf,
|
|||
struct ssl_backend_data *backend = connssl->backend;
|
||||
gnutls_session_t session;
|
||||
DEBUGASSERT(backend);
|
||||
session = backend->session;
|
||||
rc = Curl_gtls_verifyserver(cf, data, session);
|
||||
session = backend->gtls.session;
|
||||
rc = gtls_verifyserver(cf, data, session);
|
||||
if(rc) {
|
||||
result = rc;
|
||||
goto out;
|
||||
}
|
||||
connssl->state = ssl_connection_complete;
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -1421,8 +1425,8 @@ static bool gtls_data_pending(struct Curl_cfilter *cf,
|
|||
|
||||
(void)data;
|
||||
DEBUGASSERT(ctx && ctx->backend);
|
||||
if(ctx->backend->session &&
|
||||
0 != gnutls_record_check_pending(ctx->backend->session))
|
||||
if(ctx->backend->gtls.session &&
|
||||
0 != gnutls_record_check_pending(ctx->backend->gtls.session))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -1439,7 +1443,7 @@ static ssize_t gtls_send(struct Curl_cfilter *cf,
|
|||
|
||||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
rc = gnutls_record_send(backend->session, mem, len);
|
||||
rc = gnutls_record_send(backend->gtls.session, mem, len);
|
||||
|
||||
if(rc < 0) {
|
||||
*curlcode = (rc == GNUTLS_E_AGAIN)
|
||||
|
|
@ -1461,23 +1465,23 @@ static void gtls_close(struct Curl_cfilter *cf,
|
|||
(void) data;
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
if(backend->session) {
|
||||
if(backend->gtls.session) {
|
||||
char buf[32];
|
||||
/* Maybe the server has already sent a close notify alert.
|
||||
Read it to avoid an RST on the TCP connection. */
|
||||
(void)gnutls_record_recv(backend->session, buf, sizeof(buf));
|
||||
gnutls_bye(backend->session, GNUTLS_SHUT_WR);
|
||||
gnutls_deinit(backend->session);
|
||||
backend->session = NULL;
|
||||
(void)gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
|
||||
gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
|
||||
gnutls_deinit(backend->gtls.session);
|
||||
backend->gtls.session = NULL;
|
||||
}
|
||||
if(backend->cred) {
|
||||
gnutls_certificate_free_credentials(backend->cred);
|
||||
backend->cred = NULL;
|
||||
if(backend->gtls.cred) {
|
||||
gnutls_certificate_free_credentials(backend->gtls.cred);
|
||||
backend->gtls.cred = NULL;
|
||||
}
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
if(backend->srp_client_cred) {
|
||||
gnutls_srp_free_client_credentials(backend->srp_client_cred);
|
||||
backend->srp_client_cred = NULL;
|
||||
if(backend->gtls.srp_client_cred) {
|
||||
gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
|
||||
backend->gtls.srp_client_cred = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1503,10 +1507,10 @@ static int gtls_shutdown(struct Curl_cfilter *cf,
|
|||
we do not send one. Let's hope other servers do the same... */
|
||||
|
||||
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
|
||||
gnutls_bye(backend->session, GNUTLS_SHUT_WR);
|
||||
gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
|
||||
#endif
|
||||
|
||||
if(backend->session) {
|
||||
if(backend->gtls.session) {
|
||||
ssize_t result;
|
||||
bool done = FALSE;
|
||||
char buf[120];
|
||||
|
|
@ -1517,7 +1521,7 @@ static int gtls_shutdown(struct Curl_cfilter *cf,
|
|||
if(what > 0) {
|
||||
/* Something to read, let's do it and hope that it is the close
|
||||
notify alert from the server */
|
||||
result = gnutls_record_recv(backend->session,
|
||||
result = gnutls_record_recv(backend->gtls.session,
|
||||
buf, sizeof(buf));
|
||||
switch(result) {
|
||||
case 0:
|
||||
|
|
@ -1547,18 +1551,18 @@ static int gtls_shutdown(struct Curl_cfilter *cf,
|
|||
done = TRUE;
|
||||
}
|
||||
}
|
||||
gnutls_deinit(backend->session);
|
||||
gnutls_deinit(backend->gtls.session);
|
||||
}
|
||||
gnutls_certificate_free_credentials(backend->cred);
|
||||
gnutls_certificate_free_credentials(backend->gtls.cred);
|
||||
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP
|
||||
&& ssl_config->primary.username != NULL)
|
||||
gnutls_srp_free_client_credentials(backend->srp_client_cred);
|
||||
gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
|
||||
#endif
|
||||
|
||||
backend->cred = NULL;
|
||||
backend->session = NULL;
|
||||
backend->gtls.cred = NULL;
|
||||
backend->gtls.session = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -1576,7 +1580,7 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
|
|||
(void)data;
|
||||
DEBUGASSERT(backend);
|
||||
|
||||
ret = gnutls_record_recv(backend->session, buf, buffersize);
|
||||
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
|
||||
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
|
||||
*curlcode = CURLE_AGAIN;
|
||||
ret = -1;
|
||||
|
|
@ -1652,7 +1656,7 @@ static void *gtls_get_internals(struct ssl_connect_data *connssl,
|
|||
struct ssl_backend_data *backend = connssl->backend;
|
||||
(void)info;
|
||||
DEBUGASSERT(backend);
|
||||
return backend->session;
|
||||
return backend->gtls.session;
|
||||
}
|
||||
|
||||
const struct Curl_ssl Curl_ssl_gnutls = {
|
||||
|
|
|
|||
|
|
@ -25,16 +25,50 @@
|
|||
***************************************************************************/
|
||||
|
||||
#include "curl_setup.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
#ifdef USE_GNUTLS
|
||||
|
||||
#include "urldata.h"
|
||||
#include "cfilters.h"
|
||||
#include <gnutls/gnutls.h>
|
||||
|
||||
#ifdef HAVE_GNUTLS_SRP
|
||||
/* the function exists */
|
||||
#ifdef USE_TLS_SRP
|
||||
/* the functionality is not disabled */
|
||||
#define USE_GNUTLS_SRP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct Curl_easy;
|
||||
struct Curl_cfilter;
|
||||
struct ssl_primary_config;
|
||||
struct ssl_config_data;
|
||||
|
||||
struct gtls_instance {
|
||||
gnutls_session_t session;
|
||||
gnutls_certificate_credentials_t cred;
|
||||
#ifdef USE_GNUTLS_SRP
|
||||
gnutls_srp_client_credentials_t srp_client_cred;
|
||||
#endif
|
||||
};
|
||||
|
||||
CURLcode
|
||||
Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
gnutls_session_t session);
|
||||
gtls_client_init(struct Curl_easy *data,
|
||||
struct ssl_primary_config *config,
|
||||
struct ssl_config_data *ssl_config,
|
||||
const char *hostname,
|
||||
struct gtls_instance *gtls,
|
||||
long *pverifyresult);
|
||||
|
||||
CURLcode
|
||||
Curl_gtls_verifyserver(struct Curl_easy *data,
|
||||
gnutls_session_t session,
|
||||
struct ssl_primary_config *config,
|
||||
struct ssl_config_data *ssl_config,
|
||||
const char *hostname,
|
||||
const char *dispname,
|
||||
const char *pinned_key);
|
||||
|
||||
extern const struct Curl_ssl Curl_ssl_gnutls;
|
||||
|
||||
#endif /* USE_GNUTLS */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue