summaryrefslogtreecommitdiff
path: root/Utilities/cmcurl/lib/vtls
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/vtls')
-rw-r--r--Utilities/cmcurl/lib/vtls/bearssl.c186
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.c223
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c662
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.h41
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c238
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c13
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h2
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c332
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c1439
-rw-r--r--Utilities/cmcurl/lib/vtls/rustls.c163
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c286
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.h7
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_verify.c24
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.c414
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c753
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h255
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls_int.h190
-rw-r--r--Utilities/cmcurl/lib/vtls/wolfssl.c367
-rw-r--r--Utilities/cmcurl/lib/vtls/x509asn1.c62
-rw-r--r--Utilities/cmcurl/lib/vtls/x509asn1.h3
20 files changed, 3295 insertions, 2365 deletions
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c
index 1221ce8c84..d9c0ce0eed 100644
--- a/Utilities/cmcurl/lib/vtls/bearssl.c
+++ b/Utilities/cmcurl/lib/vtls/bearssl.c
@@ -32,13 +32,17 @@
#include "sendf.h"
#include "inet_pton.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "connect.h"
#include "select.h"
#include "multiif.h"
#include "curl_printf.h"
-#include "curl_memory.h"
#include "strcase.h"
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
struct x509_context {
const br_x509_class *vtable;
br_x509_minimal_context minimal;
@@ -566,18 +570,20 @@ static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode bearssl_connect_step1(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ 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 struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
- const char *hostname = SSL_HOST_NAME();
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const bool verifyhost = SSL_CONN_CONFIG(verifyhost);
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const char *hostname = connssl->hostname;
+ const bool verifypeer = conn_config->verifypeer;
+ const bool verifyhost = conn_config->verifyhost;
CURLcode ret;
unsigned version_min, version_max;
#ifdef ENABLE_IPV6
@@ -588,7 +594,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
DEBUGASSERT(backend);
- switch(SSL_CONN_CONFIG(version)) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_SSLv2:
failf(data, "BearSSL does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
@@ -659,11 +665,11 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf,
sizeof(backend->buf), 1);
- if(SSL_CONN_CONFIG(cipher_list)) {
+ if(conn_config->cipher_list) {
/* Override the ciphers as specified. For the default cipher list see the
BearSSL source code of br_ssl_client_init_full() */
ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng,
- SSL_CONN_CONFIG(cipher_list));
+ conn_config->cipher_list);
if(ret)
return ret;
}
@@ -674,19 +680,18 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
backend->x509.verifyhost = verifyhost;
br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
void *session;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
- &session, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
infof(data, "BearSSL: re-using session ID");
}
Curl_ssl_sessionid_unlock(data);
}
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
int cur = 0;
/* NOTE: when adding more protocols here, increase the size of the
@@ -696,7 +701,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
- && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+ && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy)
#endif
) {
backend->protocols[cur++] = ALPN_H2;
@@ -753,17 +758,17 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode bearssl_run_until(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
unsigned target)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- curl_socket_t sockfd = conn->sock[sockindex];
unsigned state;
unsigned char *buf;
size_t len;
ssize_t ret;
+ CURLcode result;
int err;
DEBUGASSERT(backend);
@@ -802,48 +807,37 @@ static CURLcode bearssl_run_until(struct Curl_easy *data,
return CURLE_OK;
if(state & BR_SSL_SENDREC) {
buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
- ret = swrite(sockfd, buf, len);
- if(ret == -1) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
- if(connssl->state != ssl_connection_complete)
- connssl->connecting_state = ssl_connect_2_writing;
- return CURLE_AGAIN;
- }
- return CURLE_WRITE_ERROR;
+ ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
+ if(ret <= 0) {
+ return result;
}
br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
}
else if(state & BR_SSL_RECVREC) {
buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
- ret = sread(sockfd, buf, len);
+ ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
if(ret == 0) {
failf(data, "SSL: EOF without close notify");
return CURLE_READ_ERROR;
}
- if(ret == -1) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
- if(connssl->state != ssl_connection_complete)
- connssl->connecting_state = ssl_connect_2_reading;
- return CURLE_AGAIN;
- }
- return CURLE_READ_ERROR;
+ if(ret <= 0) {
+ return result;
}
br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
}
}
}
-static CURLcode bearssl_connect_step2(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
CURLcode ret;
DEBUGASSERT(backend);
- ret = bearssl_run_until(data, conn, sockindex,
- BR_SSL_SENDAPP | BR_SSL_RECVAPP);
+ ret = bearssl_run_until(cf, data, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
if(ret == CURLE_AGAIN)
return CURLE_OK;
if(ret == CURLE_OK) {
@@ -856,17 +850,18 @@ static CURLcode bearssl_connect_step2(struct Curl_easy *data,
return ret;
}
-static CURLcode bearssl_connect_step3(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
CURLcode ret;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
const char *protocol;
protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
@@ -875,21 +870,21 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
#ifdef USE_HTTP2
if(!strcmp(protocol, ALPN_H2))
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
else
#endif
if(!strcmp(protocol, ALPN_HTTP_1_1))
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
else
infof(data, "ALPN, unrecognized protocol %s", protocol);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
else
infof(data, VTLS_INFOF_NO_ALPN);
}
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
bool incache;
bool added = FALSE;
void *oldsession;
@@ -900,14 +895,10 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &oldsession, NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, &oldsession, NULL));
if(incache)
Curl_ssl_delsessionid(data, oldsession);
- ret = Curl_ssl_addsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- session, 0, sockindex, &added);
+ ret = Curl_ssl_addsessionid(cf, data, session, 0, &added);
Curl_ssl_sessionid_unlock(data);
if(!added)
free(session);
@@ -921,11 +912,10 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
return CURLE_OK;
}
-static ssize_t bearssl_send(struct Curl_easy *data, int sockindex,
+static ssize_t bearssl_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
unsigned char *app;
size_t applen;
@@ -933,7 +923,7 @@ static ssize_t bearssl_send(struct Curl_easy *data, int sockindex,
DEBUGASSERT(backend);
for(;;) {
- *err = bearssl_run_until(data, conn, sockindex, BR_SSL_SENDAPP);
+ *err = bearssl_run_until(cf, data, BR_SSL_SENDAPP);
if (*err != CURLE_OK)
return -1;
app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen);
@@ -956,18 +946,17 @@ static ssize_t bearssl_send(struct Curl_easy *data, int sockindex,
}
}
-static ssize_t bearssl_recv(struct Curl_easy *data, int sockindex,
+static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
unsigned char *app;
size_t applen;
DEBUGASSERT(backend);
- *err = bearssl_run_until(data, conn, sockindex, BR_SSL_RECVAPP);
+ *err = bearssl_run_until(cf, data, BR_SSL_RECVAPP);
if(*err != CURLE_OK)
return -1;
app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen);
@@ -981,15 +970,14 @@ static ssize_t bearssl_recv(struct Curl_easy *data, int sockindex,
return applen;
}
-static CURLcode bearssl_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking,
bool *done)
{
CURLcode ret;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
timediff_t timeout_ms;
int what;
@@ -1000,7 +988,7 @@ static CURLcode bearssl_connect_common(struct Curl_easy *data,
}
if(ssl_connect_1 == connssl->connecting_state) {
- ret = bearssl_connect_step1(data, conn, sockindex);
+ ret = bearssl_connect_step1(cf, data);
if(ret)
return ret;
}
@@ -1053,7 +1041,7 @@ static CURLcode bearssl_connect_common(struct Curl_easy *data,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
- ret = bearssl_connect_step2(data, conn, sockindex);
+ ret = bearssl_connect_step2(cf, data);
if(ret || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -1062,15 +1050,13 @@ static CURLcode bearssl_connect_common(struct Curl_easy *data,
}
if(ssl_connect_3 == connssl->connecting_state) {
- ret = bearssl_connect_step3(data, conn, sockindex);
+ ret = bearssl_connect_step3(cf, data);
if(ret)
return ret;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = bearssl_recv;
- conn->send[sockindex] = bearssl_send;
*done = TRUE;
}
else
@@ -1087,13 +1073,14 @@ static size_t bearssl_version(char *buffer, size_t size)
return msnprintf(buffer, size, "BearSSL");
}
-static bool bearssl_data_pending(const struct connectdata *conn,
- int connindex)
+static bool bearssl_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP;
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ return br_ssl_engine_current_state(&ctx->backend->ctx.eng) & BR_SSL_RECVAPP;
}
static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
@@ -1116,13 +1103,13 @@ static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
return CURLE_OK;
}
-static CURLcode bearssl_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode bearssl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode ret;
bool done = FALSE;
- ret = bearssl_connect_common(data, conn, sockindex, FALSE, &done);
+ ret = bearssl_connect_common(cf, data, FALSE, &done);
if(ret)
return ret;
@@ -1131,11 +1118,11 @@ static CURLcode bearssl_connect(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode bearssl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode bearssl_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return bearssl_connect_common(data, conn, sockindex, TRUE, done);
+ return bearssl_connect_common(cf, data, TRUE, done);
}
static void *bearssl_get_internals(struct ssl_connect_data *connssl,
@@ -1146,22 +1133,24 @@ static void *bearssl_get_internals(struct ssl_connect_data *connssl,
return &backend->ctx;
}
-static void bearssl_close(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
size_t i;
DEBUGASSERT(backend);
if(backend->active) {
+ backend->active = FALSE;
br_ssl_engine_close(&backend->ctx.eng);
- (void)bearssl_run_until(data, conn, sockindex, BR_SSL_CLOSED);
+ (void)bearssl_run_until(cf, data, BR_SSL_CLOSED);
+ }
+ if(backend->anchors) {
+ for(i = 0; i < backend->anchors_len; ++i)
+ free(backend->anchors[i].dn.data);
+ Curl_safefree(backend->anchors);
}
- for(i = 0; i < backend->anchors_len; ++i)
- free(backend->anchors[i].dn.data);
- free(backend->anchors);
}
static void bearssl_session_free(void *ptr)
@@ -1184,7 +1173,7 @@ static CURLcode bearssl_sha256sum(const unsigned char *input,
const struct Curl_ssl Curl_ssl_bearssl = {
{ CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
- SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX,
+ SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
Curl_none_init, /* init */
@@ -1197,7 +1186,7 @@ const struct Curl_ssl Curl_ssl_bearssl = {
Curl_none_cert_status_request, /* cert_status_request */
bearssl_connect, /* connect */
bearssl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1208,7 +1197,10 @@ const struct Curl_ssl Curl_ssl_bearssl = {
Curl_none_false_start, /* false_start */
bearssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ bearssl_recv, /* recv decrypted data */
+ bearssl_send, /* send data to encrypt */
};
#endif /* USE_BEARSSL */
diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c
index 4ee4edea6c..2074dcaa48 100644
--- a/Utilities/cmcurl/lib/vtls/gskit.c
+++ b/Utilities/cmcurl/lib/vtls/gskit.c
@@ -73,6 +73,7 @@
#include "sendf.h"
#include "gskit.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "strcase.h"
@@ -105,10 +106,8 @@
struct ssl_backend_data {
gsk_handle handle;
int iocport;
-#ifndef CURL_DISABLE_PROXY
int localfd;
int remotefd;
-#endif
};
#define BACKEND connssl->backend
@@ -295,11 +294,12 @@ static CURLcode set_numeric(struct Curl_easy *data,
}
-static CURLcode set_ciphers(struct Curl_easy *data,
+static CURLcode set_ciphers(struct Curl_cfilter *cf, struct Curl_easy *data,
gsk_handle h, unsigned int *protoflags)
{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct connectdata *conn = data->conn;
- const char *cipherlist = SSL_CONN_CONFIG(cipher_list);
+ const char *cipherlist = conn_config->cipher_list;
const char *clp;
const struct gskit_cipher *ctp;
int i;
@@ -324,7 +324,7 @@ static CURLcode set_ciphers(struct Curl_easy *data,
GSKit tokens are always shorter than their cipher names, allocated buffers
will always be large enough to accommodate the result. */
l = strlen(cipherlist) + 1;
- memset((char *) ciphers, 0, sizeof(ciphers));
+ memset(ciphers, 0, sizeof(ciphers));
for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
ciphers[i].buf = malloc(l);
if(!ciphers[i].buf) {
@@ -490,14 +490,16 @@ static CURLcode init_environment(struct Curl_easy *data,
}
-static void cancel_async_handshake(struct connectdata *conn, int sockindex)
+static void cancel_async_handshake(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
Qso_OverlappedIO_t cstat;
+ (void)data;
DEBUGASSERT(BACKEND);
- if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
+ if(QsoCancelOperation(cf->conn->sock[cf->sockindex], 0) > 0)
QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL);
}
@@ -509,12 +511,12 @@ static void close_async_handshake(struct ssl_connect_data *connssl)
BACKEND->iocport = -1;
}
-static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
- int directions)
+static int pipe_ssloverssl(struct Curl_cfilter *cf, int directions)
{
-#ifndef CURL_DISABLE_PROXY
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
+ struct ssl_connect_data *connssl_next = cf_ssl_next?
+ cf_ssl_next->ctx : NULL;
struct pollfd fds[2];
int n;
int m;
@@ -523,14 +525,14 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
char buf[CURL_MAX_WRITE_SIZE];
DEBUGASSERT(BACKEND);
- DEBUGASSERT(connproxyssl->backend);
- if(!connssl->use || !connproxyssl->use)
+ if(!connssl_next)
return 0; /* No SSL over SSL: OK. */
+ DEBUGASSERT(connssl_next->backend);
n = 1;
fds[0].fd = BACKEND->remotefd;
- fds[1].fd = conn->sock[sockindex];
+ fds[1].fd = cf->conn->sock[cf->sockindex];
if(directions & SOS_READ) {
fds[0].events |= POLLOUT;
@@ -547,7 +549,7 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
if(fds[0].revents & POLLOUT) {
/* Try getting data from HTTPS proxy and pipe it upstream. */
n = 0;
- i = gsk_secure_soc_read(connproxyssl->backend->handle,
+ i = gsk_secure_soc_read(connssl_next->backend->handle,
buf, sizeof(buf), &n);
switch(i) {
case GSK_OK:
@@ -572,7 +574,7 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
if(n < 0)
return -1;
if(n) {
- i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m);
+ i = gsk_secure_soc_write(connssl_next->backend->handle, buf, n, &m);
if(i != GSK_OK || n != m)
return -1;
ret = 1;
@@ -580,24 +582,21 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
}
return ret; /* OK */
-#else
- return 0;
-#endif
}
-static void close_one(struct ssl_connect_data *connssl, struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static void close_one(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+
DEBUGASSERT(BACKEND);
if(BACKEND->handle) {
gskit_status(data, gsk_secure_soc_close(&BACKEND->handle),
"gsk_secure_soc_close()", 0);
/* Last chance to drain output. */
- while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
+ while(pipe_ssloverssl(cf, SOS_WRITE) > 0)
;
BACKEND->handle = (gsk_handle) NULL;
-#ifndef CURL_DISABLE_PROXY
if(BACKEND->localfd >= 0) {
close(BACKEND->localfd);
BACKEND->localfd = -1;
@@ -606,30 +605,29 @@ static void close_one(struct ssl_connect_data *connssl, struct Curl_easy *data,
close(BACKEND->remotefd);
BACKEND->remotefd = -1;
}
-#endif
}
if(BACKEND->iocport >= 0)
close_async_handshake(connssl);
}
-static ssize_t gskit_send(struct Curl_easy *data, int sockindex,
+static ssize_t gskit_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *mem, size_t len, CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct connectdata *conn = cf->conn;
+ struct ssl_connect_data *connssl = cf->ctx;
CURLcode cc = CURLE_SEND_ERROR;
int written;
DEBUGASSERT(BACKEND);
- if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
+ if(pipe_ssloverssl(cf, SOS_WRITE) >= 0) {
cc = gskit_status(data,
gsk_secure_soc_write(BACKEND->handle,
(char *) mem, (int) len, &written),
"gsk_secure_soc_write()", CURLE_SEND_ERROR);
if(cc == CURLE_OK)
- if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0)
+ if(pipe_ssloverssl(cf, SOS_WRITE) < 0)
cc = CURLE_SEND_ERROR;
}
if(cc != CURLE_OK) {
@@ -640,17 +638,18 @@ static ssize_t gskit_send(struct Curl_easy *data, int sockindex,
}
-static ssize_t gskit_recv(struct Curl_easy *data, int num, char *buf,
- size_t buffersize, CURLcode *curlcode)
+static ssize_t gskit_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+ char *buf, size_t buffersize, CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct connectdata *conn = cf->conn;
+ struct ssl_connect_data *connssl = cf->ctx;
int nread;
CURLcode cc = CURLE_RECV_ERROR;
+ (void)data;
DEBUGASSERT(BACKEND);
- if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
+ if(pipe_ssloverssl(cf, SOS_READ) >= 0) {
int buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
buf, buffsize, &nread),
@@ -670,11 +669,14 @@ static ssize_t gskit_recv(struct Curl_easy *data, int num, char *buf,
}
static CURLcode
-set_ssl_version_min_max(unsigned int *protoflags, struct Curl_easy *data)
+set_ssl_version_min_max(unsigned int *protoflags,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct connectdata *conn = data->conn;
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
long i = ssl_version;
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
@@ -702,35 +704,36 @@ set_ssl_version_min_max(unsigned int *protoflags, struct Curl_easy *data)
return CURLE_OK;
}
-static CURLcode gskit_connect_step1(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode gskit_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ 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);
+ struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
+ struct ssl_connect_data *connssl_next = cf_ssl_next?
+ cf_ssl_next->ctx : NULL;
gsk_handle envir;
CURLcode result;
- const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
- const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
- const char * const keyringlabel = SSL_SET_OPTION(primary.clientcert);
- const long int ssl_version = SSL_CONN_CONFIG(version);
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const char * const hostname = SSL_HOST_NAME();
+ const char * const keyringfile = conn_config->CAfile;
+ const char * const keyringpwd = conn_config->key_passwd;
+ const char * const keyringlabel = ssl_config->primary.clientcert;
+ const long int ssl_version = conn_config->version;
+ const bool verifypeer = conn_config->verifypeer;
+ const char *hostname = connssl->hostname;
const char *sni;
unsigned int protoflags = 0;
Qso_OverlappedIO_t commarea;
-#ifndef CURL_DISABLE_PROXY
int sockpair[2];
static const int sobufsize = CURL_MAX_WRITE_SIZE;
-#endif
/* Create SSL environment, start (preferably asynchronous) handshake. */
DEBUGASSERT(BACKEND);
BACKEND->handle = (gsk_handle) NULL;
BACKEND->iocport = -1;
-#ifndef CURL_DISABLE_PROXY
BACKEND->localfd = -1;
BACKEND->remotefd = -1;
-#endif
/* GSKit supports two ways of specifying an SSL context: either by
* application identifier (that should have been defined at the system
@@ -769,9 +772,8 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
if(result)
return result;
-#ifndef CURL_DISABLE_PROXY
/* Establish a pipelining socket pair for SSL over SSL. */
- if(conn->proxy_ssl[sockindex].use) {
+ if(connssl_next) {
if(Curl_socketpair(0, 0, 0, sockpair))
return CURLE_SSL_CONNECT_ERROR;
BACKEND->localfd = sockpair[0];
@@ -787,7 +789,6 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
curlx_nonblock(BACKEND->localfd, TRUE);
curlx_nonblock(BACKEND->remotefd, TRUE);
}
-#endif
/* Determine which SSL/TLS version should be enabled. */
sni = hostname;
@@ -809,7 +810,7 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
- result = set_ssl_version_min_max(&protoflags, data);
+ result = set_ssl_version_min_max(&protoflags, cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -845,15 +846,10 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
if(!result)
result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
if(!result)
-#ifndef CURL_DISABLE_PROXY
result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
- BACKEND->localfd: conn->sock[sockindex]);
-#else
- result = set_numeric(data, BACKEND->handle, GSK_FD,
- conn->sock[sockindex]);
-#endif
+ BACKEND->localfd: cf->conn->sock[cf->sockindex]);
if(!result)
- result = set_ciphers(data, BACKEND->handle, &protoflags);
+ result = set_ciphers(cf, data, BACKEND->handle, &protoflags);
if(!protoflags) {
failf(data, "No SSL protocol/cipher combination enabled");
result = CURLE_SSL_CIPHER;
@@ -920,12 +916,10 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
else if(errno != ENOBUFS)
result = gskit_status(data, GSK_ERROR_IO,
"QsoCreateIOCompletionPort()", 0);
-#ifndef CURL_DISABLE_PROXY
- else if(conn->proxy_ssl[sockindex].use) {
+ else if(connssl_next) {
/* Cannot pipeline while handshaking synchronously. */
result = CURLE_SSL_CONNECT_ERROR;
}
-#endif
else {
/* No more completion port available. Use synchronous IO. */
result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
@@ -943,11 +937,11 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
}
-static CURLcode gskit_connect_step2(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode gskit_connect_step2(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
Qso_OverlappedIO_t cstat;
struct timeval stmv;
CURLcode result;
@@ -975,7 +969,7 @@ static CURLcode gskit_connect_step2(struct Curl_easy *data,
char buffer[STRERROR_LEN];
failf(data, "QsoWaitForIOCompletion() I/O error: %s",
Curl_strerror(errno, buffer, sizeof(buffer)));
- cancel_async_handshake(conn, sockindex);
+ cancel_async_handshake(cf, data);
close_async_handshake(connssl);
return CURLE_SSL_CONNECT_ERROR;
}
@@ -983,7 +977,7 @@ static CURLcode gskit_connect_step2(struct Curl_easy *data,
case 0: /* Handshake in progress, timeout occurred. */
if(nonblocking)
return CURLE_OK;
- cancel_async_handshake(conn, sockindex);
+ cancel_async_handshake(cf, data);
close_async_handshake(connssl);
return CURLE_OPERATION_TIMEDOUT;
}
@@ -998,15 +992,15 @@ static CURLcode gskit_connect_step2(struct Curl_easy *data,
}
-static CURLcode gskit_connect_step3(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode gskit_connect_step3(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
const gsk_cert_data_elem *cdev;
int cdec;
const gsk_cert_data_elem *p;
const char *cert = (const char *) NULL;
- const char *certend;
+ const char *certend = (const char *) NULL;
const char *ptr;
CURLcode result;
@@ -1044,7 +1038,7 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
}
/* Verify host. */
- result = Curl_verifyhost(data, conn, cert, certend);
+ result = Curl_verifyhost(cf, data, cert, certend);
if(result)
return result;
@@ -1066,7 +1060,9 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
}
/* Check pinned public key. */
- ptr = SSL_PINNED_PUB_KEY();
+ ptr = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
if(!result && ptr) {
struct Curl_X509certificate x509;
struct Curl_asn1Element *p;
@@ -1087,11 +1083,11 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
}
-static CURLcode gskit_connect_common(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode gskit_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking, bool *done)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
timediff_t timeout_ms;
CURLcode result = CURLE_OK;
@@ -1110,12 +1106,12 @@ static CURLcode gskit_connect_common(struct Curl_easy *data,
result = CURLE_OPERATION_TIMEDOUT;
}
else
- result = gskit_connect_step1(data, conn, sockindex);
+ result = gskit_connect_step1(cf, data);
}
/* Handle handshake pipelining. */
if(!result)
- if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
+ if(pipe_ssloverssl(cf, SOS_READ | SOS_WRITE) < 0)
result = CURLE_SSL_CONNECT_ERROR;
/* Step 2: check if handshake is over. */
@@ -1129,25 +1125,23 @@ static CURLcode gskit_connect_common(struct Curl_easy *data,
result = CURLE_OPERATION_TIMEDOUT;
}
else
- result = gskit_connect_step2(data, conn, sockindex, nonblocking);
+ result = gskit_connect_step2(cf, data, nonblocking);
}
/* Handle handshake pipelining. */
if(!result)
- if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
+ if(pipe_ssloverssl(cf, SOS_READ | SOS_WRITE) < 0)
result = CURLE_SSL_CONNECT_ERROR;
/* Step 3: gather certificate info, verify host. */
if(!result && connssl->connecting_state == ssl_connect_3)
- result = gskit_connect_step3(data, conn, sockindex);
+ result = gskit_connect_step3(cf, data);
if(result)
close_one(connssl, data, conn, sockindex);
else if(connssl->connecting_state == ssl_connect_done) {
connssl->state = ssl_connection_complete;
connssl->connecting_state = ssl_connect_1;
- conn->recv[sockindex] = gskit_recv;
- conn->send[sockindex] = gskit_send;
*done = TRUE;
}
@@ -1155,27 +1149,29 @@ static CURLcode gskit_connect_common(struct Curl_easy *data,
}
-static CURLcode gskit_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode gskit_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
+ struct ssl_connect_data *connssl = cf->ctx;
CURLcode result;
- result = gskit_connect_common(data, conn, sockindex, TRUE, done);
+ result = gskit_connect_common(cf, data, TRUE, done);
if(*done || result)
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
+ connssl->connecting_state = ssl_connect_1;
return result;
}
-static CURLcode gskit_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode gskit_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
CURLcode result;
bool done;
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
- result = gskit_connect_common(data, conn, sockindex, FALSE, &done);
+ connssl->connecting_state = ssl_connect_1;
+ result = gskit_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -1185,20 +1181,16 @@ static CURLcode gskit_connect(struct Curl_easy *data,
}
-static void gskit_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void gskit_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- close_one(&conn->ssl[sockindex], data, conn, sockindex);
-#ifndef CURL_DISABLE_PROXY
- close_one(&conn->proxy_ssl[sockindex], data, conn, sockindex);
-#endif
+ close_one(cf, data);
}
-static int gskit_shutdown(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static int gskit_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
int what;
int rc;
char buf[120];
@@ -1214,9 +1206,9 @@ static int gskit_shutdown(struct Curl_easy *data,
return 0;
#endif
- close_one(connssl, data, conn, sockindex);
+ close_one(cf, data);
rc = 0;
- what = SOCKET_READABLE(conn->sock[sockindex],
+ what = SOCKET_READABLE(cf->conn->sock[cf->sockindex],
SSL_SHUTDOWN_TIMEOUT);
while(loop--) {
@@ -1238,7 +1230,7 @@ static int gskit_shutdown(struct Curl_easy *data,
notify alert from the server. No way to gsk_secure_soc_read() now, so
use read(). */
- nread = read(conn->sock[sockindex], buf, sizeof(buf));
+ nread = read(cf->conn->sock[cf->sockindex], buf, sizeof(buf));
if(nread < 0) {
char buffer[STRERROR_LEN];
@@ -1249,7 +1241,7 @@ static int gskit_shutdown(struct Curl_easy *data,
if(nread <= 0)
break;
- what = SOCKET_READABLE(conn->sock[sockindex], 0);
+ what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], 0);
}
return rc;
@@ -1262,12 +1254,14 @@ static size_t gskit_version(char *buffer, size_t size)
}
-static int gskit_check_cxn(struct connectdata *cxn)
+static int gskit_check_cxn(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET];
+ struct ssl_connect_data *connssl = cf->ctx;
int err;
int errlen;
+ (void)data;
/* The only thing that can be tested here is at the socket level. */
DEBUGASSERT(BACKEND);
@@ -1311,7 +1305,7 @@ const struct Curl_ssl Curl_ssl_gskit = {
Curl_none_cert_status_request, /* cert_status_request */
gskit_connect, /* connect */
gskit_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
gskit_get_internals, /* get_internals */
gskit_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1323,7 +1317,10 @@ const struct Curl_ssl Curl_ssl_gskit = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ gskit_recv, /* recv decrypted data */
+ gskit_send, /* send data to encrypt */
};
#endif /* USE_GSKIT */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index cf3dbc5238..104dce6093 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -45,6 +45,7 @@
#include "inet_pton.h"
#include "gtls.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "vauth/vauth.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
@@ -58,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 */
@@ -84,35 +77,43 @@ 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 len)
+static ssize_t gtls_push(void *s, const void *buf, size_t blen)
{
- curl_socket_t sock = *(curl_socket_t *)s;
- ssize_t ret = swrite(sock, buf, len);
- return ret;
-}
+ struct Curl_cfilter *cf = s;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result;
-static ssize_t gtls_pull(void *s, void *buf, size_t len)
-{
- curl_socket_t sock = *(curl_socket_t *)s;
- ssize_t ret = sread(sock, buf, len);
- return ret;
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ if(nwritten < 0) {
+ gnutls_transport_set_errno(connssl->backend->gtls.session,
+ (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+ nwritten = -1;
+ }
+ return nwritten;
}
-static ssize_t gtls_push_ssl(void *s, const void *buf, size_t len)
+static ssize_t gtls_pull(void *s, void *buf, size_t blen)
{
- return gnutls_record_send((gnutls_session_t) s, buf, len);
-}
+ struct Curl_cfilter *cf = s;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result;
-static ssize_t gtls_pull_ssl(void *s, void *buf, size_t len)
-{
- return gnutls_record_recv((gnutls_session_t) s, buf, len);
+ DEBUGASSERT(data);
+ nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ if(nread < 0) {
+ gnutls_transport_set_errno(connssl->backend->gtls.session,
+ (CURLE_AGAIN == result)? EAGAIN : EINVAL);
+ nread = -1;
+ }
+ return nread;
}
/* gtls_init()
@@ -205,19 +206,18 @@ static void unload_file(gnutls_datum_t data)
/* this function does a SSL/TLS (re-)handshake */
-static CURLcode handshake(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+static CURLcode handshake(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool duringconnect,
bool nonblocking)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
gnutls_session_t session;
- curl_socket_t sockfd = conn->sock[sockindex];
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
DEBUGASSERT(backend);
- session = backend->session;
+ session = backend->gtls.session;
for(;;) {
timediff_t timeout_ms;
@@ -323,12 +323,12 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
static CURLcode
set_ssl_version_min_max(struct Curl_easy *data,
+ struct ssl_primary_config *conn_config,
const char **prioritylist,
const char *tls13support)
{
- struct connectdata *conn = data->conn;
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
(ssl_version == CURL_SSLVERSION_TLSv1))
@@ -394,20 +394,16 @@ set_ssl_version_min_max(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
-static CURLcode
-gtls_connect_step1(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+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 = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
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
@@ -415,54 +411,44 @@ gtls_connect_step1(struct Curl_easy *data,
#endif
const char *prioritylist;
const char *err = NULL;
- const char * const hostname = SSL_HOST_NAME();
- long * const certverifyresult = &SSL_SET_OPTION_LVALUE(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(SSL_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(SSL_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(&gtls->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_SET_OPTION(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_SET_OPTION(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(
+ &gtls->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_SET_OPTION(primary.username),
- SSL_SET_OPTION(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));
@@ -471,67 +457,63 @@ gtls_connect_step1(struct Curl_easy *data,
}
#endif
- if(SSL_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,
- SSL_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)",
- SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
- if(SSL_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,
- SSL_CONN_CONFIG(CAfile));
+ infof(data, "found %d certificates in %s", rc, config->CAfile);
}
- if(SSL_CONN_CONFIG(CApath)) {
+ if(config->CApath) {
/* set the trusted CA cert directory */
- rc = gnutls_certificate_set_x509_trust_dir(backend->cred,
- SSL_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)",
- SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
- if(SSL_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, SSL_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(SSL_CONN_CONFIG(verifypeer) &&
- !(SSL_CONN_CONFIG(CAfile) || SSL_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_SET_OPTION(primary.CRLfile)) {
+ if(config->CRLfile) {
/* set the CRL list file */
- rc = gnutls_certificate_set_x509_crl_file(backend->cred,
- SSL_SET_OPTION(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_SET_OPTION(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_SET_OPTION(primary.CRLfile));
+ infof(data, "found %d CRL in %s", rc, config->CRLfile);
}
/* Initialize TLS session as a client */
@@ -546,15 +528,12 @@ gtls_connect_step1(struct Curl_easy *data,
init_flags |= GNUTLS_NO_TICKETS;
#endif
- rc = gnutls_init(&backend->session, init_flags);
+ rc = gnutls_init(&gtls->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)) &&
@@ -562,15 +541,15 @@ gtls_connect_step1(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;
@@ -581,13 +560,13 @@ gtls_connect_step1(struct Curl_easy *data,
* removed if a run-time error indicates that SRP is not supported by this
* GnuTLS version */
- if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2 ||
- SSL_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(SSL_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;
@@ -595,14 +574,14 @@ gtls_connect_step1(struct Curl_easy *data,
}
/* At this point we know we have a supported TLS version, so set it */
- result = set_ssl_version_min_max(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_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) {
+ if(config->authtype == CURL_TLSAUTH_SRP) {
size_t len = strlen(prioritylist);
char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1);
@@ -610,7 +589,7 @@ gtls_connect_step1(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) {
@@ -620,7 +599,7 @@ gtls_connect_step1(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
@@ -631,48 +610,19 @@ gtls_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- if(conn->bits.tls_enable_alpn) {
- int cur = 0;
- gnutls_datum_t protocols[2];
-
-#ifdef USE_HTTP2
- if(data->state.httpwant >= CURL_HTTP_VERSION_2
-#ifndef CURL_DISABLE_PROXY
- && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
-#endif
- ) {
- protocols[cur].data = (unsigned char *)ALPN_H2;
- protocols[cur].size = ALPN_H2_LENGTH;
- cur++;
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2);
- }
-#endif
-
- protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
- protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
- cur++;
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1);
-
- if(gnutls_alpn_set_protocols(session, protocols, cur, 0)) {
- failf(data, "failed setting ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- if(SSL_SET_OPTION(primary.clientcert)) {
- if(SSL_SET_OPTION(key_passwd)) {
+ 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(
- backend->cred,
- SSL_SET_OPTION(primary.clientcert),
- SSL_SET_OPTION(key) ?
- SSL_SET_OPTION(key) : SSL_SET_OPTION(primary.clientcert),
- do_file_type(SSL_SET_OPTION(cert_type)),
- SSL_SET_OPTION(key_passwd),
+ 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,
@@ -683,11 +633,10 @@ gtls_connect_step1(struct Curl_easy *data,
}
else {
if(gnutls_certificate_set_x509_key_file(
- backend->cred,
- SSL_SET_OPTION(primary.clientcert),
- SSL_SET_OPTION(key) ?
- SSL_SET_OPTION(key) : SSL_SET_OPTION(primary.clientcert),
- do_file_type(SSL_SET_OPTION(cert_type)) ) !=
+ 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;
@@ -697,9 +646,9 @@ gtls_connect_step1(struct Curl_easy *data,
#ifdef USE_GNUTLS_SRP
/* put the credentials to the current session */
- if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) {
- rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
- backend->srp_client_cred);
+ 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;
@@ -708,59 +657,88 @@ gtls_connect_step1(struct Curl_easy *data,
else
#endif
{
- rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
- backend->cred);
+ 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;
}
}
-#ifndef CURL_DISABLE_PROXY
- if(conn->proxy_ssl[sockindex].use) {
- struct ssl_backend_data *proxy_backend;
- proxy_backend = conn->proxy_ssl[sockindex].backend;
- DEBUGASSERT(proxy_backend);
- transport_ptr = proxy_backend->session;
- gnutls_transport_push = gtls_push_ssl;
- gnutls_transport_pull = gtls_pull_ssl;
- }
- else
-#endif
- {
- /* file descriptor for the socket */
- transport_ptr = &conn->sock[sockindex];
- gnutls_transport_push = gtls_push;
- gnutls_transport_pull = gtls_pull;
+ 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;
+ }
}
- /* set the connection handle */
- gnutls_transport_set_ptr(session, transport_ptr);
+ 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;
- /* 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);
+ DEBUGASSERT(backend);
- if(SSL_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);
+ 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];
+
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2
+#ifndef CURL_DISABLE_PROXY
+ && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy)
+#endif
+ ) {
+ protocols[cur].data = (unsigned char *)ALPN_H2;
+ protocols[cur].size = ALPN_H2_LENGTH;
+ cur++;
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_H2);
+ }
+#endif
+
+ protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
+ protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
+ cur++;
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, ALPN_HTTP_1_1);
+
+ if(gnutls_alpn_set_protocols(backend->gtls.session, protocols, cur, 0)) {
+ failf(data, "failed setting ALPN");
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_SET_OPTION(primary.sessionid)) {
+ if(conn_config->sessionid) {
void *ssl_sessionid;
size_t ssl_idsize;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &ssl_sessionid, &ssl_idsize, sockindex)) {
+ 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");
@@ -768,6 +746,11 @@ gtls_connect_step1(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;
}
@@ -829,14 +812,14 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
return result;
}
-static Curl_recv gtls_recv;
-static Curl_send gtls_send;
-
CURLcode
Curl_gtls_verifyserver(struct Curl_easy *data,
- struct connectdata *conn,
gnutls_session_t session,
- int sockindex)
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ const char *hostname,
+ const char *dispname,
+ const char *pinned_key)
{
unsigned int cert_list_size;
const gnutls_datum_t *chainp;
@@ -849,15 +832,13 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
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 * const hostname = SSL_HOST_NAME();
- long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
+ long * const certverifyresult = &ssl_config->certverifyresult;
/* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
@@ -875,13 +856,13 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
chainp = gnutls_certificate_get_peers(session, &cert_list_size);
if(!chainp) {
- if(SSL_CONN_CONFIG(verifypeer) ||
- SSL_CONN_CONFIG(verifyhost) ||
- SSL_CONN_CONFIG(issuercert)) {
+ if(config->verifypeer ||
+ config->verifyhost ||
+ config->issuercert) {
#ifdef USE_GNUTLS_SRP
- if(SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP
- && SSL_SET_OPTION(primary.username)
- && !SSL_CONN_CONFIG(verifypeer)
+ if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP
+ && ssl_config->primary.username
+ && !config->verifypeer
&& gnutls_cipher_get(session)) {
/* no peer cert, but auth is ok if we have SRP user and cipher and no
peer verify */
@@ -915,7 +896,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
}
- if(SSL_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
@@ -934,12 +915,12 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
/* verify_status is a bitmask of gnutls_certificate_status bits */
if(verify_status & GNUTLS_CERT_INVALID) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
failf(data, "server certificate verification failed. CAfile: %s "
- "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
+ "CRLfile: %s", config->CAfile ? config->CAfile:
"none",
- SSL_SET_OPTION(primary.CRLfile) ?
- SSL_SET_OPTION(primary.CRLfile) : "none");
+ ssl_config->primary.CRLfile ?
+ ssl_config->primary.CRLfile : "none");
return CURLE_PEER_FAILED_VERIFICATION;
}
else
@@ -951,7 +932,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
else
infof(data, " server certificate verification SKIPPED");
- if(SSL_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;
@@ -1062,21 +1043,21 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_x509_crt_t format */
gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
- if(SSL_CONN_CONFIG(issuercert)) {
+ if(config->issuercert) {
gnutls_x509_crt_init(&x509_issuer);
- issuerp = load_file(SSL_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)",
- SSL_CONN_CONFIG(issuercert)?SSL_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)",
- SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none");
+ config->issuercert?config->issuercert:"none");
}
size = sizeof(certname);
@@ -1139,15 +1120,15 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
#endif
if(!rc) {
- if(SSL_CONN_CONFIG(verifyhost)) {
+ if(config->verifyhost) {
failf(data, "SSL: certificate subject name (%s) does not match "
- "target host name '%s'", certname, SSL_HOST_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, SSL_HOST_DISPNAME());
+ certname, dispname);
}
else
infof(data, " common name: %s (matched)", certname);
@@ -1156,7 +1137,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
if(certclock == (time_t)-1) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
failf(data, "server cert expiration date verify failed");
*certverifyresult = GNUTLS_CERT_EXPIRED;
gnutls_x509_crt_deinit(x509_cert);
@@ -1167,7 +1148,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
else {
if(certclock < time(NULL)) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
failf(data, "server certificate expiration date has passed.");
*certverifyresult = GNUTLS_CERT_EXPIRED;
gnutls_x509_crt_deinit(x509_cert);
@@ -1183,7 +1164,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
certclock = gnutls_x509_crt_get_activation_time(x509_cert);
if(certclock == (time_t)-1) {
- if(SSL_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);
@@ -1194,7 +1175,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
else {
if(certclock > time(NULL)) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(config->verifypeer) {
failf(data, "server certificate not activated yet.");
*certverifyresult = GNUTLS_CERT_NOT_ACTIVATED;
gnutls_x509_crt_deinit(x509_cert);
@@ -1207,9 +1188,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
infof(data, " server certificate activation date OK");
}
- ptr = SSL_PINNED_PUB_KEY();
- 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);
@@ -1265,7 +1245,31 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_x509_crt_deinit(x509_cert);
- if(conn->bits.tls_enable_alpn) {
+ 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,
@@ -1275,25 +1279,23 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
if(proto.size == ALPN_H2_LENGTH &&
!memcmp(ALPN_H2, proto.data,
ALPN_H2_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(proto.size == ALPN_HTTP_1_1_LENGTH &&
!memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
}
else
infof(data, VTLS_INFOF_NO_ALPN);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
- conn->ssl[sockindex].state = ssl_connection_complete;
-
- if(SSL_SET_OPTION(primary.sessionid)) {
+ 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
might've been rejected and then a new one is in use now and we need to
@@ -1314,9 +1316,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &ssl_sessionid, NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL));
if(incache) {
/* there was one before in the cache, so instead of risking that the
previous one was rejected, we just kill that and store the new */
@@ -1324,10 +1324,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
/* store this session id */
- result = Curl_ssl_addsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- connect_sessionid, connect_idsize,
- sockindex, &added);
+ result = Curl_ssl_addsessionid(cf, data, connect_sessionid,
+ connect_idsize, &added);
Curl_ssl_sessionid_unlock(data);
if(!added)
free(connect_sessionid);
@@ -1339,10 +1337,10 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
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.
@@ -1353,59 +1351,65 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
'ssl_connect_2_writing' (waiting to be able to write).
*/
static CURLcode
-gtls_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+gtls_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking,
bool *done)
{
+ struct ssl_connect_data *connssl = cf->ctx;
int rc;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ CURLcode result = CURLE_OK;
/* Initiate the connection, if not already done */
if(ssl_connect_1 == connssl->connecting_state) {
- rc = gtls_connect_step1(data, conn, sockindex);
- if(rc)
- return rc;
+ rc = gtls_connect_step1(cf, data);
+ if(rc) {
+ result = rc;
+ goto out;
+ }
}
- rc = handshake(data, conn, sockindex, TRUE, nonblocking);
- if(rc)
+ rc = handshake(cf, data, TRUE, nonblocking);
+ if(rc) {
/* handshake() sets its own error message with failf() */
- return rc;
+ result = rc;
+ goto out;
+ }
/* Finish connecting once the handshake is done */
if(ssl_connect_1 == connssl->connecting_state) {
struct ssl_backend_data *backend = connssl->backend;
gnutls_session_t session;
DEBUGASSERT(backend);
- session = backend->session;
- rc = Curl_gtls_verifyserver(data, conn, session, sockindex);
- if(rc)
- return rc;
- conn->recv[sockindex] = gtls_recv;
- conn->send[sockindex] = gtls_send;
+ session = backend->gtls.session;
+ rc = gtls_verifyserver(cf, data, session);
+ if(rc) {
+ result = rc;
+ goto out;
+ }
+ connssl->state = ssl_connection_complete;
}
+out:
*done = ssl_connect_1 == connssl->connecting_state;
- return CURLE_OK;
+ return result;
}
-static CURLcode gtls_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return gtls_connect_common(data, conn, sockindex, TRUE, done);
+ return gtls_connect_common(cf, data, TRUE, done);
}
-static CURLcode gtls_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode gtls_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = gtls_connect_common(data, conn, sockindex, FALSE, &done);
+ result = gtls_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -1414,44 +1418,32 @@ static CURLcode gtls_connect(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static bool gtls_data_pending(const struct connectdata *conn,
- int connindex)
+static bool gtls_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- bool res = FALSE;
- struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_connect_data *ctx = cf->ctx;
- DEBUGASSERT(backend);
-
- if(backend->session &&
- 0 != gnutls_record_check_pending(backend->session))
- res = TRUE;
-
-#ifndef CURL_DISABLE_PROXY
- connssl = &conn->proxy_ssl[connindex];
- backend = connssl->backend;
- DEBUGASSERT(backend);
- if(backend->session &&
- 0 != gnutls_record_check_pending(backend->session))
- res = TRUE;
-#endif
-
- return res;
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ if(ctx->backend->gtls.session &&
+ 0 != gnutls_record_check_pending(ctx->backend->gtls.session))
+ return TRUE;
+ return FALSE;
}
-static ssize_t gtls_send(struct Curl_easy *data,
- int sockindex,
+static ssize_t gtls_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const void *mem,
size_t len,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t rc;
+ (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)
@@ -1464,50 +1456,45 @@ static ssize_t gtls_send(struct Curl_easy *data,
return rc;
}
-static void close_one(struct ssl_connect_data *connssl)
+static void gtls_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+
+ (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
}
-static void gtls_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- (void) data;
- close_one(&conn->ssl[sockindex]);
-#ifndef CURL_DISABLE_PROXY
- close_one(&conn->proxy_ssl[sockindex]);
-#endif
-}
-
/*
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static int gtls_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_backend_data *backend = connssl->backend;
int retval = 0;
@@ -1520,21 +1507,21 @@ static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn,
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];
while(!done) {
- int what = SOCKET_READABLE(conn->sock[sockindex],
+ int what = SOCKET_READABLE(cf->conn->sock[cf->sockindex],
SSL_SHUTDOWN_TIMEOUT);
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:
@@ -1564,51 +1551,53 @@ static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn,
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_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP
- && SSL_SET_OPTION(primary.username) != NULL)
- gnutls_srp_free_client_credentials(backend->srp_client_cred);
+ if(ssl_config->primary.authtype == CURL_TLSAUTH_SRP
+ && ssl_config->primary.username != NULL)
+ 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;
}
-static ssize_t gtls_recv(struct Curl_easy *data, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
+static ssize_t gtls_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *buf,
+ size_t buffersize,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t ret;
+ (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;
- return -1;
+ ret = -1;
+ goto out;
}
if(ret == GNUTLS_E_REHANDSHAKE) {
/* BLOCKING call, this is bad but a work-around for now. Fixing this "the
proper way" takes a whole lot of work. */
- CURLcode result = handshake(data, conn, num, FALSE, FALSE);
+ CURLcode result = handshake(cf, data, FALSE, FALSE);
if(result)
/* handshake() writes error message on its own */
*curlcode = result;
else
*curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
- return -1;
+ ret = -1;
+ goto out;
}
if(ret < 0) {
@@ -1616,9 +1605,11 @@ static ssize_t gtls_recv(struct Curl_easy *data, /* connection data */
(int)ret, gnutls_strerror((int)ret));
*curlcode = CURLE_RECV_ERROR;
- return -1;
+ ret = -1;
+ goto out;
}
+out:
return ret;
}
@@ -1665,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 = {
@@ -1688,7 +1679,7 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_cert_status_request, /* cert_status_request */
gtls_connect, /* connect */
gtls_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
gtls_get_internals, /* get_internals */
gtls_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1699,7 +1690,10 @@ const struct Curl_ssl Curl_ssl_gnutls = {
Curl_none_false_start, /* false_start */
gtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ gtls_recv, /* recv decrypted data */
+ gtls_send, /* send data to encrypt */
};
#endif /* USE_GNUTLS */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h
index abade73f80..49c1c47637 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.h
+++ b/Utilities/cmcurl/lib/vtls/gtls.h
@@ -25,15 +25,50 @@
***************************************************************************/
#include "curl_setup.h"
+#include <curl/curl.h>
#ifdef USE_GNUTLS
-#include "urldata.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_easy *data, struct connectdata *conn,
+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,
- int sockindex);
+ 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 */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index fbde8976eb..0b81662b93 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -61,6 +61,7 @@
#include "inet_pton.h"
#include "mbedtls.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
@@ -155,6 +156,46 @@ static void mbed_debug(void *context, int level, const char *f_name,
#else
#endif
+static int bio_cf_write(void *bio, const unsigned char *buf, size_t blen)
+{
+ struct Curl_cfilter *cf = bio;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result;
+
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result);
+ /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_out_write(len=%d) -> %d, err=%d"),
+ blen, (int)nwritten, result)); */
+ if(nwritten < 0 && CURLE_AGAIN == result) {
+ nwritten = MBEDTLS_ERR_SSL_WANT_WRITE;
+ }
+ return (int)nwritten;
+}
+
+static int bio_cf_read(void *bio, unsigned char *buf, size_t blen)
+{
+ struct Curl_cfilter *cf = bio;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result;
+
+ DEBUGASSERT(data);
+ /* OpenSSL catches this case, so should we. */
+ if(!buf)
+ return 0;
+
+ nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result);
+ /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_in_read(len=%d) -> %d, err=%d"),
+ blen, (int)nread, result)); */
+ if(nread < 0 && CURLE_AGAIN == result) {
+ nread = MBEDTLS_ERR_SSL_WANT_READ;
+ }
+ return (int)nread;
+}
+
/*
* profile
*/
@@ -181,9 +222,6 @@ static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
-static Curl_recv mbed_recv;
-static Curl_send mbed_send;
-
static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
{
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
@@ -216,11 +254,11 @@ static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
}
static CURLcode
-set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ 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);
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
@@ -228,8 +266,8 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
#endif
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
CURLcode result = CURLE_OK;
DEBUGASSERT(backend);
@@ -268,31 +306,29 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
- char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
- const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
- const char * const ssl_crlfile = SSL_SET_OPTION(primary.CRLfile);
- const char * const hostname = SSL_HOST_NAME();
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- const long int port = SSL_HOST_PORT();
-#endif
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const bool verifypeer = conn_config->verifypeer;
+ const char * const ssl_capath = conn_config->CApath;
+ char * const ssl_cert = ssl_config->primary.clientcert;
+ const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
+ const char * const ssl_crlfile = ssl_config->primary.CRLfile;
+ const char *hostname = connssl->hostname;
int ret = -1;
char errorbuf[128];
DEBUGASSERT(backend);
- if((SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) ||
- (SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)) {
+ if((conn_config->version == CURL_SSLVERSION_SSLv2) ||
+ (conn_config->version == CURL_SSLVERSION_SSLv3)) {
failf(data, "Not supported SSL version");
return CURLE_NOT_BUILT_IN;
}
@@ -416,7 +452,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(ret) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
- SSL_SET_OPTION(key), -ret, errorbuf);
+ ssl_config->key, -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
}
@@ -424,23 +460,23 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* Load the client private key */
mbedtls_pk_init(&backend->pk);
- if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) {
- if(SSL_SET_OPTION(key)) {
+ if(ssl_config->key || ssl_config->key_blob) {
+ if(ssl_config->key) {
#ifdef MBEDTLS_FS_IO
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
- ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
- SSL_SET_OPTION(key_passwd),
+ ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key,
+ ssl_config->key_passwd,
mbedtls_ctr_drbg_random,
&backend->ctr_drbg);
#else
- ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
- SSL_SET_OPTION(key_passwd));
+ ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key,
+ ssl_config->key_passwd);
#endif
if(ret) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
- SSL_SET_OPTION(key), -ret, errorbuf);
+ ssl_config->key, -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
#else
@@ -449,10 +485,10 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
}
else {
- const struct curl_blob *ssl_key_blob = SSL_SET_OPTION(key_blob);
+ const struct curl_blob *ssl_key_blob = ssl_config->key_blob;
const unsigned char *key_data =
(const unsigned char *)ssl_key_blob->data;
- const char *passwd = SSL_SET_OPTION(key_passwd);
+ const char *passwd = ssl_config->key_passwd;
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len,
(const unsigned char *)passwd,
@@ -505,7 +541,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
#endif
- infof(data, "mbedTLS: Connecting to %s:%ld", hostname, port);
+ infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->port);
mbedtls_ssl_config_init(&backend->config);
ret = mbedtls_ssl_config_defaults(&backend->config,
@@ -527,7 +563,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
mbedtls_ssl_conf_cert_profile(&backend->config,
&mbedtls_x509_crt_profile_fr);
- switch(SSL_CONN_CONFIG(version)) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
#if MBEDTLS_VERSION_NUMBER < 0x03000000
@@ -541,7 +577,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
{
- CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
+ CURLcode result = set_ssl_version_min_max(cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -555,9 +591,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
&backend->ctr_drbg);
- mbedtls_ssl_set_bio(&backend->ssl, &conn->sock[sockindex],
- mbedtls_net_send,
- mbedtls_net_recv,
+ mbedtls_ssl_set_bio(&backend->ssl, cf, bio_cf_write, bio_cf_read,
NULL /* rev_timeout() */);
mbedtls_ssl_conf_ciphersuites(&backend->config,
@@ -574,13 +608,11 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
/* Check if there's a cached ID we can/should use here! */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &old_session, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, &old_session, NULL)) {
ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(data);
@@ -600,7 +632,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
NULL);
#endif
- if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) {
+ if(ssl_config->key || ssl_config->key_blob) {
mbedtls_ssl_conf_own_cert(&backend->config,
&backend->clicert, &backend->pk);
}
@@ -616,7 +648,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAS_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
const char **p = &backend->protocols[0];
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2)
@@ -664,20 +696,19 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
int ret;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ 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);
const mbedtls_x509_crt *peercert;
- const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
+ const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
DEBUGASSERT(backend);
- conn->recv[sockindex] = mbed_recv;
- conn->send[sockindex] = mbed_send;
-
ret = mbedtls_ssl_handshake(&backend->ssl);
if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
@@ -701,11 +732,11 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
ret = mbedtls_ssl_get_verify_result(&backend->ssl);
- if(!SSL_CONN_CONFIG(verifyhost))
+ if(!conn_config->verifyhost)
/* Ignore hostname errors if verifyhost is disabled */
ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
- if(ret && SSL_CONN_CONFIG(verifypeer)) {
+ if(ret && conn_config->verifypeer) {
if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
failf(data, "Cert verify failed: BADCERT_EXPIRED");
@@ -813,7 +844,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAS_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
if(next_protocol) {
@@ -821,19 +852,19 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
#ifdef USE_HTTP2
if(!strncmp(next_protocol, ALPN_H2, ALPN_H2_LENGTH) &&
!next_protocol[ALPN_H2_LENGTH]) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) &&
!next_protocol[ALPN_HTTP_1_1_LENGTH]) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
}
else {
infof(data, VTLS_INFOF_NO_ALPN);
}
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
#endif
@@ -845,21 +876,20 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURLcode retcode = CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
int ret;
mbedtls_ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
- bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
bool added = FALSE;
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
@@ -879,12 +909,11 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
/* If there's already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, isproxy, &old_ssl_sessionid, NULL,
- sockindex))
+ if(!Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL))
Curl_ssl_delsessionid(data, old_ssl_sessionid);
- retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
- 0, sockindex, &added);
+ retcode = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid,
+ 0, &added);
Curl_ssl_sessionid_unlock(data);
if(!added) {
mbedtls_ssl_session_free(our_ssl_sessionid);
@@ -901,17 +930,16 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static ssize_t mbed_send(struct Curl_easy *data, int sockindex,
+static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *mem, size_t len,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
int ret = -1;
+ (void)data;
DEBUGASSERT(backend);
-
ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
if(ret < 0) {
@@ -928,14 +956,13 @@ static void mbedtls_close_all(struct Curl_easy *data)
(void)data;
}
-static void mbedtls_close(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
char buf[32];
- (void) data;
+ (void)data;
DEBUGASSERT(backend);
/* Maybe the server has already sent a close notify alert.
@@ -956,16 +983,16 @@ static void mbedtls_close(struct Curl_easy *data,
#endif /* THREADING_SUPPORT */
}
-static ssize_t mbed_recv(struct Curl_easy *data, int num,
+static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t buffersize,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
int ret = -1;
ssize_t len = -1;
+ (void)data;
DEBUGASSERT(backend);
ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
@@ -1048,15 +1075,13 @@ static CURLcode mbedtls_random(struct Curl_easy *data,
}
static CURLcode
-mbed_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
bool nonblocking,
bool *done)
{
CURLcode retcode;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
timediff_t timeout_ms;
int what;
@@ -1075,7 +1100,7 @@ mbed_connect_common(struct Curl_easy *data,
failf(data, "SSL connection timeout");
return CURLE_OPERATION_TIMEDOUT;
}
- retcode = mbed_connect_step1(data, conn, sockindex);
+ retcode = mbed_connect_step1(cf, data);
if(retcode)
return retcode;
}
@@ -1130,7 +1155,7 @@ mbed_connect_common(struct Curl_easy *data,
* ensuring that a client using select() or epoll() will always
* have a valid fdset to wait on.
*/
- retcode = mbed_connect_step2(data, conn, sockindex);
+ retcode = mbed_connect_step2(cf, data);
if(retcode || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -1140,15 +1165,13 @@ mbed_connect_common(struct Curl_easy *data,
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- retcode = mbed_connect_step3(data, conn, sockindex);
+ retcode = mbed_connect_step3(cf, data);
if(retcode)
return retcode;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = mbed_recv;
- conn->send[sockindex] = mbed_send;
*done = TRUE;
}
else
@@ -1160,21 +1183,21 @@ mbed_connect_common(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode mbedtls_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode mbedtls_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return mbed_connect_common(data, conn, sockindex, TRUE, done);
+ return mbed_connect_common(cf, data, TRUE, done);
}
-static CURLcode mbedtls_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode mbedtls_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode retcode;
bool done = FALSE;
- retcode = mbed_connect_common(data, conn, sockindex, FALSE, &done);
+ retcode = mbed_connect_common(cf, data, FALSE, &done);
if(retcode)
return retcode;
@@ -1197,13 +1220,14 @@ static void mbedtls_cleanup(void)
(void)Curl_mbedtlsthreadlock_thread_cleanup();
}
-static bool mbedtls_data_pending(const struct connectdata *conn,
- int sockindex)
+static bool mbedtls_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- return mbedtls_ssl_get_bytes_avail(&backend->ssl) != 0;
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ return mbedtls_ssl_get_bytes_avail(&ctx->backend->ssl) != 0;
}
static CURLcode mbedtls_sha256sum(const unsigned char *input,
@@ -1242,7 +1266,8 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
SSLSUPP_PINNEDPUBKEY |
- SSLSUPP_SSL_CTX,
+ SSLSUPP_SSL_CTX |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
@@ -1256,7 +1281,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
Curl_none_cert_status_request, /* cert_status_request */
mbedtls_connect, /* connect */
mbedtls_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
mbedtls_get_internals, /* get_internals */
mbedtls_close, /* close_one */
mbedtls_close_all, /* close_all */
@@ -1267,7 +1292,10 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
Curl_none_false_start, /* false_start */
mbedtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ mbed_recv, /* recv decrypted data */
+ mbed_send, /* send data to encrypt */
};
#endif /* USE_MBEDTLS */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
index 3971e69b25..7d019ede53 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
@@ -26,13 +26,12 @@
#if defined(USE_MBEDTLS) && \
((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
- (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)))
+ defined(USE_THREADS_WIN32))
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
# include <pthread.h>
# define MBEDTLS_MUTEX_T pthread_mutex_t
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
-# include <process.h>
+#elif defined(USE_THREADS_WIN32)
# define MBEDTLS_MUTEX_T HANDLE
#endif
@@ -60,7 +59,7 @@ int Curl_mbedtlsthreadlock_thread_setup(void)
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
if(pthread_mutex_init(&mutex_buf[i], NULL))
return 0; /* pthread_mutex_init failed */
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
+#elif defined(USE_THREADS_WIN32)
mutex_buf[i] = CreateMutex(0, FALSE, 0);
if(mutex_buf[i] == 0)
return 0; /* CreateMutex failed */
@@ -81,7 +80,7 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void)
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
if(pthread_mutex_destroy(&mutex_buf[i]))
return 0; /* pthread_mutex_destroy failed */
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
+#elif defined(USE_THREADS_WIN32)
if(!CloseHandle(mutex_buf[i]))
return 0; /* CloseHandle failed */
#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
@@ -101,7 +100,7 @@ int Curl_mbedtlsthreadlock_lock_function(int n)
"Error: mbedtlsthreadlock_lock_function failed\n"));
return 0; /* pthread_mutex_lock failed */
}
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
+#elif defined(USE_THREADS_WIN32)
if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) {
DEBUGF(fprintf(stderr,
"Error: mbedtlsthreadlock_lock_function failed\n"));
@@ -121,7 +120,7 @@ int Curl_mbedtlsthreadlock_unlock_function(int n)
"Error: mbedtlsthreadlock_unlock_function failed\n"));
return 0; /* pthread_mutex_unlock failed */
}
-#elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H)
+#elif defined(USE_THREADS_WIN32)
if(!ReleaseMutex(mutex_buf[n])) {
DEBUGF(fprintf(stderr,
"Error: mbedtlsthreadlock_unlock_function failed\n"));
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h
index 3a50d03817..22e8725ab0 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h
+++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h
@@ -29,7 +29,7 @@
#ifdef USE_MBEDTLS
#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
- (defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H))
+ defined(USE_THREADS_WIN32)
int Curl_mbedtlsthreadlock_thread_setup(void);
int Curl_mbedtlsthreadlock_thread_cleanup(void);
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index 12cf618f56..03694d22ba 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -39,6 +39,7 @@
#include "strcase.h"
#include "select.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "llist.h"
#include "multiif.h"
#include "curl_printf.h"
@@ -68,7 +69,6 @@
#include <ocsp.h>
#endif
-#include "strcase.h"
#include "warnless.h"
#include "x509asn1.h"
@@ -696,17 +696,18 @@ fail:
return CURLE_SSL_CRL_BADFILE;
}
-static CURLcode nss_load_key(struct Curl_easy *data, struct connectdata *conn,
- int sockindex, char *key_file)
+static CURLcode nss_load_key(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *key_file)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
PK11SlotInfo *slot, *tmp;
SECStatus status;
CURLcode result;
- struct ssl_connect_data *ssl = conn->ssl;
-
- (void)sockindex; /* unused */
- result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
+ (void)data;
+ result = nss_create_object(connssl, CKO_PRIVATE_KEY, key_file, FALSE);
if(result) {
PR_SetError(SEC_ERROR_BAD_KEY, 0);
return result;
@@ -725,7 +726,7 @@ static CURLcode nss_load_key(struct Curl_easy *data, struct connectdata *conn,
return CURLE_SSL_CERTPROBLEM;
}
- status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd));
+ status = PK11_Authenticate(slot, PR_TRUE, ssl_config->key_passwd);
PK11_FreeSlot(slot);
return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
@@ -747,13 +748,15 @@ static int display_error(struct Curl_easy *data, PRInt32 err,
return 0; /* The caller will print a generic error */
}
-static CURLcode cert_stuff(struct Curl_easy *data, struct connectdata *conn,
- int sockindex, char *cert_file, char *key_file)
+static CURLcode cert_stuff(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *cert_file, char *key_file)
{
+ struct ssl_connect_data *connssl = cf->ctx;
CURLcode result;
if(cert_file) {
- result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
+ result = nss_load_cert(connssl, cert_file, PR_FALSE);
if(result) {
const PRErrorCode err = PR_GetError();
if(!display_error(data, err, cert_file)) {
@@ -767,10 +770,10 @@ static CURLcode cert_stuff(struct Curl_easy *data, struct connectdata *conn,
if(key_file || (is_file(cert_file))) {
if(key_file)
- result = nss_load_key(data, conn, sockindex, key_file);
+ result = nss_load_key(cf, data, key_file);
else
/* In case the cert file also has the key */
- result = nss_load_key(data, conn, sockindex, cert_file);
+ result = nss_load_key(cf, data, cert_file);
if(result) {
const PRErrorCode err = PR_GetError();
if(!display_error(data, err, key_file)) {
@@ -800,11 +803,14 @@ static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
PRBool isServer)
{
- struct Curl_easy *data = (struct Curl_easy *)arg;
- struct connectdata *conn = data->conn;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct Curl_easy *data = connssl->backend->data;
+ DEBUGASSERT(data);
#ifdef SSL_ENABLE_OCSP_STAPLING
- if(SSL_CONN_CONFIG(verifystatus)) {
+ if(conn_config->verifystatus) {
SECStatus cacheResult;
const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
@@ -830,7 +836,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
}
#endif
- if(!SSL_CONN_CONFIG(verifypeer)) {
+ if(!conn_config->verifypeer) {
infof(data, "skipping SSL peer certificate verification");
return SECSuccess;
}
@@ -843,13 +849,16 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
*/
static void HandshakeCallback(PRFileDesc *sock, void *arg)
{
- struct Curl_easy *data = (struct Curl_easy *)arg;
- struct connectdata *conn = data->conn;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->backend->data;
+ struct connectdata *conn = cf->conn;
unsigned int buflenmax = 50;
unsigned char buf[50];
unsigned int buflen;
SSLNextProtoState state;
+ DEBUGASSERT(data);
if(!conn->bits.tls_enable_alpn) {
return;
}
@@ -879,13 +888,13 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
#ifdef USE_HTTP2
if(buflen == ALPN_H2_LENGTH &&
!memcmp(ALPN_H2, buf, ALPN_H2_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(buflen == ALPN_HTTP_1_1_LENGTH &&
!memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
/* This callback might get called when PR_Recv() is used within
@@ -893,7 +902,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
* be any "bundle" associated with the connection anymore.
*/
if(conn->bundle)
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
}
@@ -1064,15 +1073,20 @@ static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock)
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
- struct Curl_easy *data = (struct Curl_easy *)arg;
- struct connectdata *conn = data->conn;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)arg;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->backend->data;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config;
PRErrorCode err = PR_GetError();
CERTCertificate *cert;
+ DEBUGASSERT(data);
+ ssl_config = Curl_ssl_cf_get_config(cf, data);
/* remember the cert verification result */
- SSL_SET_OPTION_LVALUE(certverifyresult) = err;
+ ssl_config->certverifyresult = err;
- if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
+ if(err == SSL_ERROR_BAD_CERT_DOMAIN && !conn_config->verifyhost)
/* we are asked not to verify the host name */
return SECSuccess;
@@ -1549,13 +1563,14 @@ static void nss_cleanup(void)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-static int nss_check_cxn(struct connectdata *conn)
+static int nss_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
int rc;
char buf;
+ (void)data;
DEBUGASSERT(backend);
rc =
@@ -1612,41 +1627,20 @@ static void close_one(struct ssl_connect_data *connssl)
/*
* This function is called when an SSL connection is closed.
*/
-static void nss_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void nss_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-#ifndef CURL_DISABLE_PROXY
- struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
-#endif
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
(void)data;
-
DEBUGASSERT(backend);
-#ifndef CURL_DISABLE_PROXY
- DEBUGASSERT(connssl_proxy->backend != NULL);
-#endif
- if(backend->handle
-#ifndef CURL_DISABLE_PROXY
- || connssl_proxy->backend->handle
-#endif
- ) {
+ if(backend->handle) {
/* NSS closes the socket we previously handed to it, so we must mark it
as closed to avoid double close */
- fake_sclose(conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
+ fake_sclose(cf->conn->sock[cf->sockindex]);
+ cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
}
-#ifndef CURL_DISABLE_PROXY
- if(backend->handle)
- /* nss_close(connssl) will transitively close also
- connssl_proxy->backend->handle if both are used. Clear it to avoid
- a double close leading to crash. */
- connssl_proxy->backend->handle = NULL;
-
- close_one(connssl_proxy);
-#endif
close_one(connssl);
}
@@ -1680,15 +1674,13 @@ static bool is_cc_error(PRInt32 err)
}
}
-static Curl_recv nss_recv;
-static Curl_send nss_send;
-
-static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+static CURLcode nss_load_ca_certificates(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- const char *cafile = SSL_CONN_CONFIG(CAfile);
- const char *capath = SSL_CONN_CONFIG(CApath);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const char *cafile = conn_config->CAfile;
+ const char *capath = conn_config->CApath;
bool use_trust_module;
CURLcode result = CURLE_OK;
@@ -1723,7 +1715,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
PR_Unlock(nss_trustload_lock);
if(cafile)
- result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
+ result = nss_load_cert(connssl, cafile, PR_TRUE);
if(result)
return result;
@@ -1747,7 +1739,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
+ if(CURLE_OK != nss_load_cert(connssl, fullpath, PR_TRUE))
/* This is purposefully tolerant of errors so non-PEM files can
* be in the same directory */
infof(data, "failed to load '%s' from CURLOPT_CAPATH", fullpath);
@@ -1808,12 +1800,13 @@ static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
}
static CURLcode nss_init_sslver(SSLVersionRange *sslver,
- struct Curl_easy *data,
- struct connectdata *conn)
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
CURLcode result;
- const long min = SSL_CONN_CONFIG(version);
- const long max = SSL_CONN_CONFIG(version_max);
+ const long min = conn_config->version;
+ const long max = conn_config->version_max;
SSLVersionRange vrange;
switch(min) {
@@ -1848,10 +1841,11 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver,
return CURLE_OK;
}
-static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
+static CURLcode nss_fail_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
CURLcode curlerr)
{
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
@@ -1876,10 +1870,11 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
}
/* Switch the SSL socket into blocking or non-blocking mode. */
-static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
+static CURLcode nss_set_blocking(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool blocking)
{
+ struct ssl_connect_data *connssl = cf->ctx;
PRSocketOptionData sock_opt;
struct ssl_backend_data *backend = connssl->backend;
@@ -1889,22 +1884,27 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
sock_opt.value.non_blocking = !blocking;
if(PR_SetSocketOption(backend->handle, &sock_opt) != PR_SUCCESS)
- return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
+ return nss_fail_connect(cf, data, CURLE_SSL_CONNECT_ERROR);
return CURLE_OK;
}
-static CURLcode nss_setup_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode nss_setup_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
PRFileDesc *model = NULL;
PRFileDesc *nspr_io = NULL;
PRFileDesc *nspr_io_stub = NULL;
PRBool ssl_no_cache;
PRBool ssl_cbc_random_iv;
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
+ 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);
+ struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
+ struct ssl_connect_data *connssl_next = cf_ssl_next?
+ cf_ssl_next->ctx : NULL;
CURLcode result;
bool second_layer = FALSE;
SSLVersionRange sslver_supported;
@@ -1920,7 +1920,10 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
SSL_LIBRARY_VERSION_TLS_1_0
#endif
};
- char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
+ const char *hostname = connssl->hostname;
+ char *snihost;
+
+ snihost = Curl_ssl_snihost(data, hostname, NULL);
if(!snihost) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
@@ -1965,13 +1968,13 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
goto error;
/* do not use SSL cache if disabled or we are not going to verify peer */
- ssl_no_cache = (SSL_SET_OPTION(primary.sessionid)
- && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
+ ssl_no_cache = (ssl_config->primary.sessionid
+ && conn_config->verifypeer) ? PR_FALSE : PR_TRUE;
if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
goto error;
/* enable/disable the requested SSL version(s) */
- if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
+ if(nss_init_sslver(&sslver, cf, data) != CURLE_OK)
goto error;
if(SSL_VersionRangeGetSupported(ssl_variant_stream,
&sslver_supported) != SECSuccess)
@@ -1990,7 +1993,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
goto error;
- ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
+ ssl_cbc_random_iv = !ssl_config->enable_beast;
#ifdef SSL_CBC_RANDOM_IV
/* unless the user explicitly asks to allow the protocol vulnerability, we
use the work-around */
@@ -2002,33 +2005,33 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
infof(data, "WARNING: support for SSL_CBC_RANDOM_IV not compiled in");
#endif
- if(SSL_CONN_CONFIG(cipher_list)) {
- if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
+ if(conn_config->cipher_list) {
+ if(set_ciphers(data, model, conn_config->cipher_list) != SECSuccess) {
result = CURLE_SSL_CIPHER;
goto error;
}
}
- if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
+ if(!conn_config->verifypeer && conn_config->verifyhost)
infof(data, "WARNING: ignoring value of ssl.verifyhost");
/* bypass the default SSL_AuthCertificate() hook in case we do not want to
* verify peer */
- if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, data) != SECSuccess)
+ if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, cf) != SECSuccess)
goto error;
/* not checked yet */
- SSL_SET_OPTION_LVALUE(certverifyresult) = 0;
+ ssl_config->certverifyresult = 0;
- if(SSL_BadCertHook(model, BadCertHandler, data) != SECSuccess)
+ if(SSL_BadCertHook(model, BadCertHandler, cf) != SECSuccess)
goto error;
- if(SSL_HandshakeCallback(model, HandshakeCallback, data) != SECSuccess)
+ if(SSL_HandshakeCallback(model, HandshakeCallback, cf) != SECSuccess)
goto error;
{
- const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex);
- if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
+ const CURLcode rv = nss_load_ca_certificates(cf, data);
+ if((rv == CURLE_SSL_CACERT_BADFILE) && !conn_config->verifypeer)
/* not a fatal error because we are not going to verify the peer */
infof(data, "WARNING: CA certificates failed to load");
else if(rv) {
@@ -2037,25 +2040,25 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
}
}
- if(SSL_SET_OPTION(primary.CRLfile)) {
- const CURLcode rv = nss_load_crl(SSL_SET_OPTION(primary.CRLfile));
+ if(ssl_config->primary.CRLfile) {
+ const CURLcode rv = nss_load_crl(ssl_config->primary.CRLfile);
if(rv) {
result = rv;
goto error;
}
- infof(data, " CRLfile: %s", SSL_SET_OPTION(primary.CRLfile));
+ infof(data, " CRLfile: %s", ssl_config->primary.CRLfile);
}
- if(SSL_SET_OPTION(primary.clientcert)) {
- char *nickname = dup_nickname(data, SSL_SET_OPTION(primary.clientcert));
+ if(ssl_config->primary.clientcert) {
+ char *nickname = dup_nickname(data, ssl_config->primary.clientcert);
if(nickname) {
/* we are not going to use libnsspem.so to read the client cert */
backend->obj_clicert = NULL;
}
else {
- CURLcode rv = cert_stuff(data, conn, sockindex,
- SSL_SET_OPTION(primary.clientcert),
- SSL_SET_OPTION(key));
+ CURLcode rv = cert_stuff(cf, data,
+ ssl_config->primary.clientcert,
+ ssl_config->key);
if(rv) {
/* failf() is already done in cert_stuff() */
result = rv;
@@ -2075,17 +2078,19 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
goto error;
}
-#ifndef CURL_DISABLE_PROXY
- if(conn->proxy_ssl[sockindex].use) {
- struct ssl_backend_data *proxy_backend;
- proxy_backend = conn->proxy_ssl[sockindex].backend;
- DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
- DEBUGASSERT(proxy_backend);
- DEBUGASSERT(proxy_backend->handle);
- nspr_io = proxy_backend->handle;
+ /* Is there an SSL filter "in front" of us or are we writing directly
+ * to the socket? */
+ if(connssl_next) {
+ /* The filter should be connected by now, with full handshake */
+ DEBUGASSERT(connssl_next->backend->handle);
+ DEBUGASSERT(ssl_connection_complete == connssl_next->state);
+ /* We tell our NSS instance to use do IO with the 'next' NSS
+ * instance. This NSS instance will take ownership of the next
+ * one, including its destruction. We therefore need to `disown`
+ * the next filter's handle, once import succeeds. */
+ nspr_io = connssl_next->backend->handle;
second_layer = TRUE;
}
-#endif
else {
/* wrap OS file descriptor by NSPR's file descriptor abstraction */
nspr_io = PR_ImportTCPSocket(sockfd);
@@ -2122,14 +2127,16 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
PR_Close(model); /* We don't need this any more */
model = NULL;
+ if(connssl_next) /* steal the NSS handle we just imported successfully */
+ connssl_next->backend->handle = NULL;
/* This is the password associated with the cert that we're using */
- if(SSL_SET_OPTION(key_passwd)) {
- SSL_SetPKCS11PinArg(backend->handle, SSL_SET_OPTION(key_passwd));
+ if(ssl_config->key_passwd) {
+ SSL_SetPKCS11PinArg(backend->handle, ssl_config->key_passwd);
}
#ifdef SSL_ENABLE_OCSP_STAPLING
- if(SSL_CONN_CONFIG(verifystatus)) {
+ if(conn_config->verifystatus) {
if(SSL_OptionSet(backend->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
!= SECSuccess)
goto error;
@@ -2137,8 +2144,9 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
#endif
#ifdef SSL_ENABLE_ALPN
- if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
- ? PR_TRUE : PR_FALSE) != SECSuccess)
+ if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN,
+ cf->conn->bits.tls_enable_alpn ? PR_TRUE : PR_FALSE)
+ != SECSuccess)
goto error;
#endif
@@ -2155,14 +2163,14 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
#endif
#if defined(SSL_ENABLE_ALPN)
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
int cur = 0;
unsigned char protocols[128];
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
- && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+ && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy)
#endif
) {
protocols[cur++] = ALPN_H2_LENGTH;
@@ -2199,14 +2207,16 @@ error:
if(model)
PR_Close(model);
- return nss_fail_connect(connssl, data, result);
+ return nss_fail_connect(cf, data, result);
}
-static CURLcode nss_do_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode nss_do_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ 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);
CURLcode result = CURLE_SSL_CONNECT_ERROR;
PRUint32 timeout;
@@ -2226,9 +2236,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
/* blocking direction is updated by nss_update_connecting_state() */
return CURLE_AGAIN;
- else if(SSL_SET_OPTION(certverifyresult) == SSL_ERROR_BAD_CERT_DOMAIN)
+ else if(ssl_config->certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
result = CURLE_PEER_FAILED_VERIFICATION;
- else if(SSL_SET_OPTION(certverifyresult) != 0)
+ else if(ssl_config->certverifyresult)
result = CURLE_PEER_FAILED_VERIFICATION;
goto error;
}
@@ -2237,9 +2247,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
if(result)
goto error;
- if(SSL_CONN_CONFIG(issuercert)) {
+ if(conn_config->issuercert) {
SECStatus ret = SECFailure;
- char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert));
+ char *nickname = dup_nickname(data, conn_config->issuercert);
if(nickname) {
/* we support only nicknames in case of issuercert for now */
ret = check_issuer_cert(backend->handle, nickname);
@@ -2256,7 +2266,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
}
}
- result = cmp_peer_pubkey(connssl, SSL_PINNED_PUB_KEY());
+ result = cmp_peer_pubkey(connssl, Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
if(result)
/* status already printed */
goto error;
@@ -2264,14 +2276,14 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
return CURLE_OK;
error:
- return nss_fail_connect(connssl, data, result);
+ return nss_fail_connect(cf, data, result);
}
-static CURLcode nss_connect_common(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode nss_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool *done)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
const bool blocking = (done == NULL);
CURLcode result;
@@ -2282,7 +2294,7 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
}
if(connssl->connecting_state == ssl_connect_1) {
- result = nss_setup_connect(data, conn, sockindex);
+ result = nss_setup_connect(cf, data);
if(result)
/* we do not expect CURLE_AGAIN from nss_setup_connect() */
return result;
@@ -2291,11 +2303,11 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
}
/* enable/disable blocking mode before handshake */
- result = nss_set_blocking(connssl, data, blocking);
+ result = nss_set_blocking(cf, data, blocking);
if(result)
return result;
- result = nss_do_connect(data, conn, sockindex);
+ result = nss_do_connect(cf, data);
switch(result) {
case CURLE_OK:
break;
@@ -2311,7 +2323,7 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
if(blocking) {
/* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
- result = nss_set_blocking(connssl, data, /* blocking */ FALSE);
+ result = nss_set_blocking(cf, data, /* blocking */ FALSE);
if(result)
return result;
}
@@ -2320,8 +2332,6 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
*done = TRUE;
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = nss_recv;
- conn->send[sockindex] = nss_send;
/* ssl_connect_done is never used outside, go back to the initial state */
connssl->connecting_state = ssl_connect_1;
@@ -2329,30 +2339,30 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode nss_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode nss_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- return nss_connect_common(data, conn, sockindex, /* blocking */ NULL);
+ return nss_connect_common(cf, data, /* blocking */ NULL);
}
-static CURLcode nss_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode nss_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return nss_connect_common(data, conn, sockindex, done);
+ return nss_connect_common(cf, data, done);
}
-static ssize_t nss_send(struct Curl_easy *data, /* transfer */
- int sockindex, /* socketindex */
+static ssize_t nss_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data, /* transfer */
const void *mem, /* send this data */
size_t len, /* amount to write */
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t rc;
+ (void)data;
DEBUGASSERT(backend);
/* The SelectClientCert() hook uses this for infof() and failf() but the
@@ -2383,17 +2393,17 @@ static ssize_t nss_send(struct Curl_easy *data, /* transfer */
return rc; /* number of bytes */
}
-static ssize_t nss_recv(struct Curl_easy *data, /* transfer */
- int sockindex, /* socketindex */
+static ssize_t nss_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data, /* transfer */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t nread;
+ (void)data;
DEBUGASSERT(backend);
/* The SelectClientCert() hook uses this for infof() and failf() but the
@@ -2498,6 +2508,25 @@ static void *nss_get_internals(struct ssl_connect_data *connssl,
return backend->handle;
}
+static bool nss_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+
+ if(!connssl->backend->data)
+ connssl->backend->data = data;
+ return TRUE;
+}
+
+static void nss_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+
+ if(connssl->backend->data == data)
+ connssl->backend->data = NULL;
+}
+
const struct Curl_ssl Curl_ssl_nss = {
{ CURLSSLBACKEND_NSS, "nss" }, /* info */
@@ -2519,7 +2548,7 @@ const struct Curl_ssl Curl_ssl_nss = {
nss_cert_status_request, /* cert_status_request */
nss_connect, /* connect */
nss_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
nss_get_internals, /* get_internals */
nss_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -2530,8 +2559,11 @@ const struct Curl_ssl Curl_ssl_nss = {
Curl_none_engines_list, /* engines_list */
nss_false_start, /* false_start */
nss_sha256sum, /* sha256sum */
- NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ nss_attach_data, /* associate_connection */
+ nss_detach_data, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ nss_recv, /* recv decrypted data */
+ nss_send, /* send data to encrypt */
};
#endif /* USE_NSS */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 0dc695d7f4..d86e4b7f5c 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -55,6 +55,7 @@
#include "slist.h"
#include "select.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "vauth/vauth.h"
#include "keylog.h"
#include "strcase.h"
@@ -261,6 +262,22 @@
#define HAVE_OPENSSL_VERSION
#endif
+/*
+ * Whether the OpenSSL version has the API needed to support sharing an
+ * X509_STORE between connections. The API is:
+ * * `X509_STORE_up_ref` -- Introduced: OpenSSL 1.1.0.
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* OpenSSL >= 1.1.0 */
+#define HAVE_SSL_X509_STORE_SHARE
+#endif
+
+/* What API version do we use? */
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define USE_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2070000f)
+#else /* !LIBRESSL_VERSION_NUMBER */
+#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#endif /* !LIBRESSL_VERSION_NUMBER */
+
struct ssl_backend_data {
struct Curl_easy *logger; /* transfer handle to pass trace logs to, only
using sockindex 0 */
@@ -268,12 +285,21 @@ struct ssl_backend_data {
SSL_CTX* ctx;
SSL* handle;
X509* server_cert;
+ CURLcode io_result; /* result of last BIO cfilter operation */
#ifndef HAVE_KEYLOG_CALLBACK
/* Set to true once a valid keylog entry has been created to avoid dupes. */
bool keylog_done;
#endif
};
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+struct multi_ssl_backend_data {
+ char *CAfile; /* CAfile path used to generate X509 store */
+ X509_STORE *store; /* cached X509 store or NULL if none */
+ struct curltime time; /* when the cached store was created */
+};
+#endif /* HAVE_SSL_X509_STORE_SHARE */
+
#define push_certinfo(_label, _num) \
do { \
long info_len = BIO_get_mem_data(mem, &ptr); \
@@ -612,9 +638,160 @@ CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
#ifdef USE_OPENSSL
-static bool ossl_associate_connection(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex);
+#if USE_PRE_1_1_API
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
+#define BIO_set_init(x,v) ((x)->init=(v))
+#define BIO_get_data(x) ((x)->ptr)
+#define BIO_set_data(x,v) ((x)->ptr=(v))
+#endif
+#define BIO_get_shutdown(x) ((x)->shutdown)
+#define BIO_set_shutdown(x,v) ((x)->shutdown=(v))
+#endif /* USE_PRE_1_1_API */
+
+static int bio_cf_create(BIO *bio)
+{
+ BIO_set_shutdown(bio, 1);
+ BIO_set_init(bio, 1);
+#if USE_PRE_1_1_API
+ bio->num = -1;
+#endif
+ BIO_set_data(bio, NULL);
+ return 1;
+}
+
+static int bio_cf_destroy(BIO *bio)
+{
+ if(!bio)
+ return 0;
+ return 1;
+}
+
+static long bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+ struct Curl_cfilter *cf = BIO_get_data(bio);
+ long ret = 1;
+
+ (void)cf;
+ (void)ptr;
+ switch(cmd) {
+ case BIO_CTRL_GET_CLOSE:
+ ret = (long)BIO_get_shutdown(bio);
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ BIO_set_shutdown(bio, (int)num);
+ break;
+ case BIO_CTRL_FLUSH:
+ /* we do no delayed writes, but if we ever would, this
+ * needs to trigger it. */
+ ret = 1;
+ break;
+ case BIO_CTRL_DUP:
+ ret = 1;
+ break;
+#ifdef BIO_CTRL_EOF
+ case BIO_CTRL_EOF:
+ /* EOF has been reached on input? */
+ return (!cf->next || !cf->next->connected);
+#endif
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int bio_cf_out_write(BIO *bio, const char *buf, int blen)
+{
+ struct Curl_cfilter *cf = BIO_get_data(bio);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result = CURLE_SEND_ERROR;
+
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_out_write(len=%d) -> %d, err=%d"),
+ blen, (int)nwritten, result)); */
+ BIO_clear_retry_flags(bio);
+ connssl->backend->io_result = result;
+ if(nwritten < 0) {
+ if(CURLE_AGAIN == result)
+ BIO_set_retry_write(bio);
+ }
+ return (int)nwritten;
+}
+
+static int bio_cf_in_read(BIO *bio, char *buf, int blen)
+{
+ struct Curl_cfilter *cf = BIO_get_data(bio);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result = CURLE_RECV_ERROR;
+
+ DEBUGASSERT(data);
+ /* OpenSSL catches this case, so should we. */
+ if(!buf)
+ return 0;
+
+ nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ /* DEBUGF(infof(data, CFMSG(cf, "bio_cf_in_read(len=%d) -> %d, err=%d"),
+ blen, (int)nread, result)); */
+ BIO_clear_retry_flags(bio);
+ connssl->backend->io_result = result;
+ if(nread < 0) {
+ if(CURLE_AGAIN == result)
+ BIO_set_retry_read(bio);
+ }
+ return (int)nread;
+}
+
+static BIO_METHOD *bio_cf_method = NULL;
+
+#if USE_PRE_1_1_API
+
+static BIO_METHOD bio_cf_meth_1_0 = {
+ BIO_TYPE_MEM,
+ "OpenSSL CF BIO",
+ bio_cf_out_write,
+ bio_cf_in_read,
+ NULL, /* puts is never called */
+ NULL, /* gets is never called */
+ bio_cf_ctrl,
+ bio_cf_create,
+ bio_cf_destroy,
+ NULL
+};
+
+static void bio_cf_init_methods(void)
+{
+ bio_cf_method = &bio_cf_meth_1_0;
+}
+
+#define bio_cf_free_methods() Curl_nop_stmt
+
+#else
+
+static void bio_cf_init_methods(void)
+{
+ bio_cf_method = BIO_meth_new(BIO_TYPE_MEM, "OpenSSL CF BIO");
+ BIO_meth_set_write(bio_cf_method, &bio_cf_out_write);
+ BIO_meth_set_read(bio_cf_method, &bio_cf_in_read);
+ BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl);
+ BIO_meth_set_create(bio_cf_method, &bio_cf_create);
+ BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy);
+}
+
+static void bio_cf_free_methods(void)
+{
+ BIO_meth_free(bio_cf_method);
+}
+
+#endif
+
+
+static bool ossl_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
/*
* Number of bytes to read from the random number seed file. This must be
@@ -713,12 +890,25 @@ static const char *SSL_ERROR_to_str(int err)
}
}
+static size_t ossl_version(char *buffer, size_t size);
+
/* Return error string for last OpenSSL error
*/
static char *ossl_strerror(unsigned long error, char *buf, size_t size)
{
- if(size)
+ size_t len;
+ DEBUGASSERT(size);
+ *buf = '\0';
+
+ len = ossl_version(buf, size);
+ DEBUGASSERT(len < (size - 2));
+ if(len < (size - 2)) {
+ buf += len;
+ size -= (len + 2);
+ *buf++ = ':';
+ *buf++ = ' ';
*buf = '\0';
+ }
#ifdef OPENSSL_IS_BORINGSSL
ERR_error_string_n((uint32_t)error, buf, size);
@@ -726,7 +916,7 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size)
ERR_error_string_n(error, buf, size);
#endif
- if(size > 1 && !*buf) {
+ if(!*buf) {
strncpy(buf, (error ? "Unknown error" : "No error"), size);
buf[size - 1] = '\0';
}
@@ -746,16 +936,16 @@ static int ossl_get_ssl_data_index(void)
return ssl_ex_data_data_index;
}
-/* Return an extra data index for the connection data.
+/* Return an extra data index for the associated Curl_cfilter instance.
* This index can be used with SSL_get_ex_data() and SSL_set_ex_data().
*/
-static int ossl_get_ssl_conn_index(void)
+static int ossl_get_ssl_cf_index(void)
{
- static int ssl_ex_data_conn_index = -1;
- if(ssl_ex_data_conn_index < 0) {
- ssl_ex_data_conn_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ static int ssl_ex_data_cf_index = -1;
+ if(ssl_ex_data_cf_index < 0) {
+ ssl_ex_data_cf_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
}
- return ssl_ex_data_conn_index;
+ return ssl_ex_data_cf_index;
}
/* Return an extra data index for the sockindex.
@@ -1580,10 +1770,11 @@ static int ossl_init(void)
OpenSSL_add_all_algorithms();
#endif
+ bio_cf_init_methods();
Curl_tls_keylog_open();
/* Initialize the extra data indexes */
- if(ossl_get_ssl_data_index() < 0 || ossl_get_ssl_conn_index() < 0 ||
+ if(ossl_get_ssl_data_index() < 0 || ossl_get_ssl_cf_index() < 0 ||
ossl_get_ssl_sockindex_index() < 0 || ossl_get_proxy_index() < 0)
return 0;
@@ -1625,6 +1816,7 @@ static void ossl_cleanup(void)
#endif
Curl_tls_keylog_close();
+ bio_cf_free_methods();
}
/*
@@ -1635,15 +1827,16 @@ static void ossl_cleanup(void)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-static int ossl_check_cxn(struct connectdata *conn)
+static int ossl_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
{
/* SSL_peek takes data out of the raw recv buffer without peeking so we use
recv MSG_PEEK instead. Bug #795 */
#ifdef MSG_PEEK
char buf;
ssize_t nread;
- nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
- (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK);
+ nread = recv((RECV_TYPE_ARG1)cf->conn->sock[cf->sockindex],
+ (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1,
+ (RECV_TYPE_ARG4)MSG_PEEK);
if(nread == 0)
return 0; /* connection has been closed */
if(nread == 1)
@@ -1676,6 +1869,7 @@ static int ossl_check_cxn(struct connectdata *conn)
return 0; /* connection has been closed */
}
#endif
+ (void)data;
return -1; /* connection status unknown */
}
@@ -1768,33 +1962,28 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
return list;
}
-#define set_logger(conn, data) \
- conn->ssl[0].backend->logger = data
+#define set_logger(connssl, data) \
+ connssl->backend->logger = data
-static void ossl_closeone(struct Curl_easy *data,
- struct connectdata *conn,
- struct ssl_connect_data *connssl)
+static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
if(backend->handle) {
- char buf[32];
- set_logger(conn, data);
- /*
- * The conn->sock[0] socket is passed to openssl with SSL_set_fd(). Make
- * sure the socket is not closed before calling OpenSSL functions that
- * will use it.
- */
- DEBUGASSERT(conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD);
+ set_logger(connssl, data);
- /* Maybe the server has already sent a close notify alert.
- Read it to avoid an RST on the TCP connection. */
- (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
+ if(cf->next && cf->next->connected) {
+ char buf[32];
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
- (void)SSL_shutdown(backend->handle);
- SSL_set_connect_state(backend->handle);
+ (void)SSL_shutdown(backend->handle);
+ SSL_set_connect_state(backend->handle);
+ }
SSL_free(backend->handle);
backend->handle = NULL;
@@ -1806,30 +1995,18 @@ static void ossl_closeone(struct Curl_easy *data,
}
/*
- * This function is called when an SSL connection is closed.
- */
-static void ossl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- ossl_closeone(data, conn, &conn->ssl[sockindex]);
-#ifndef CURL_DISABLE_PROXY
- ossl_closeone(data, conn, &conn->proxy_ssl[sockindex]);
-#endif
-}
-
-/*
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-static int ossl_shutdown(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static int ossl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
int retval = 0;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
to be at least 256 bytes long. */
unsigned long sslerror;
- ssize_t nread;
+ int nread;
int buffsize;
int err;
bool done = FALSE;
@@ -1851,15 +2028,15 @@ static int ossl_shutdown(struct Curl_easy *data,
if(backend->handle) {
buffsize = (int)sizeof(buf);
while(!done && loop--) {
- int what = SOCKET_READABLE(conn->sock[sockindex],
+ int what = SOCKET_READABLE(cf->conn->sock[cf->sockindex],
SSL_SHUTDOWN_TIMEOUT);
if(what > 0) {
ERR_clear_error();
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
- nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
- err = SSL_get_error(backend->handle, (int)nread);
+ nread = SSL_read(backend->handle, buf, buffsize);
+ err = SSL_get_error(backend->handle, nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -2017,9 +2194,18 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
CURLcode result = CURLE_OK;
bool dNSName = FALSE; /* if a dNSName field exists in the cert */
bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
- const char * const hostname = SSL_HOST_NAME();
- const char * const dispname = SSL_HOST_DISPNAME();
- size_t hostlen = strlen(hostname);
+ const char *hostname, *dispname;
+ int port;
+ size_t hostlen;
+
+ (void)conn;
+ Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &dispname, &port);
+ hostlen = strlen(hostname);
+
+#ifndef ENABLE_IPV6
+ /* Silence compiler warnings for unused params */
+ (void) conn;
+#endif
#ifdef ENABLE_IPV6
if(conn->bits.ipv6_ip &&
@@ -2195,9 +2381,10 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
-static CURLcode verifystatus(struct Curl_easy *data,
- struct ssl_connect_data *connssl)
+static CURLcode verifystatus(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
int i, ocsp_status;
unsigned char *status;
const unsigned char *p;
@@ -2478,18 +2665,24 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
char unknown[32];
const char *verstr = NULL;
struct connectdata *conn = userp;
- struct ssl_connect_data *connssl = &conn->ssl[0];
- struct ssl_backend_data *backend = connssl->backend;
+ int cf_idx = ossl_get_ssl_cf_index();
+ struct ssl_connect_data *connssl;
struct Curl_easy *data = NULL;
+ struct Curl_cfilter *cf;
- DEBUGASSERT(backend);
- data = backend->logger;
+ DEBUGASSERT(cf_idx >= 0);
+ cf = (struct Curl_cfilter*) SSL_get_ex_data(ssl, cf_idx);
+ DEBUGASSERT(cf);
+ connssl = cf->ctx;
+ DEBUGASSERT(connssl);
+ DEBUGASSERT(connssl->backend);
+ data = connssl->backend->logger;
if(!conn || !data || !data->set.fdebug ||
(direction != 0 && direction != 1))
return;
- switch(ssl_ver) {
+ switch(ssl_ver) {
#ifdef SSL2_VERSION /* removed in recent versions */
case SSL2_VERSION:
verstr = "SSLv2";
@@ -2565,7 +2758,8 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
msg_name = ssl_msg_type(ssl_ver, msg_type);
}
- txt_len = msnprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n",
+ txt_len = msnprintf(ssl_buf, sizeof(ssl_buf),
+ CFMSG(cf, "%s (%s), %s, %s (%d):\n"),
verstr, direction?"OUT":"IN",
tls_rt_name, msg_name, msg_type);
if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) {
@@ -2605,10 +2799,11 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
#ifdef HAS_MODERN_SET_PROTO_VER
static CURLcode
-set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn)
+set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
/* first, TLS min version... */
- long curl_ssl_version_min = SSL_CONN_CONFIG(version);
+ long curl_ssl_version_min = conn_config->version;
long curl_ssl_version_max;
/* convert curl min SSL version option to OpenSSL constant */
@@ -2652,7 +2847,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn)
}
/* ... then, TLS max version */
- curl_ssl_version_max = SSL_CONN_CONFIG(version_max);
+ curl_ssl_version_max = conn_config->version_max;
/* convert curl max SSL version option to OpenSSL constant */
switch(curl_ssl_version_max) {
@@ -2700,11 +2895,12 @@ typedef long ctx_option_t;
#if !defined(HAS_MODERN_SET_PROTO_VER)
static CURLcode
set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
- struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ 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;
(void) data; /* In case it's unused. */
@@ -2712,14 +2908,12 @@ set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
case CURL_SSLVERSION_TLSv1_3:
#ifdef TLS1_3_VERSION
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
+ struct ssl_connect_data *connssl = cf->ctx;
+ DEBUGASSERT(connssl->backend);
+ SSL_CTX_set_max_proto_version(connssl->backend->ctx, TLS1_3_VERSION);
*ctx_options |= SSL_OP_NO_TLSv1_2;
}
#else
- (void)sockindex;
(void)ctx_options;
failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
return CURLE_NOT_BUILT_IN;
@@ -2780,31 +2974,30 @@ set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
{
int res = 0;
- struct connectdata *conn;
struct Curl_easy *data;
- int sockindex;
+ struct Curl_cfilter *cf;
+ const struct ssl_config_data *config;
curl_socket_t *sockindex_ptr;
int data_idx = ossl_get_ssl_data_index();
- int connectdata_idx = ossl_get_ssl_conn_index();
+ int cf_idx = ossl_get_ssl_cf_index();
int sockindex_idx = ossl_get_ssl_sockindex_index();
int proxy_idx = ossl_get_proxy_index();
bool isproxy;
- if(data_idx < 0 || connectdata_idx < 0 || sockindex_idx < 0 || proxy_idx < 0)
+ if(data_idx < 0 || cf_idx < 0 || sockindex_idx < 0 || proxy_idx < 0)
return 0;
- conn = (struct connectdata*) SSL_get_ex_data(ssl, connectdata_idx);
+ cf = (struct Curl_cfilter*) SSL_get_ex_data(ssl, cf_idx);
data = (struct Curl_easy *) SSL_get_ex_data(ssl, data_idx);
/* The sockindex has been stored as a pointer to an array element */
sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx);
- if(!conn || !data || !sockindex_ptr)
+ if(!cf || !data || !sockindex_ptr)
return 0;
- sockindex = (int)(sockindex_ptr - conn->sock);
-
- isproxy = SSL_get_ex_data(ssl, proxy_idx) ? TRUE : FALSE;
+ isproxy = Curl_ssl_cf_is_proxy(cf);
- if(SSL_SET_OPTION(primary.sessionid)) {
+ config = Curl_ssl_cf_get_config(cf, data);
+ if(config->primary.sessionid) {
bool incache;
bool added = FALSE;
void *old_ssl_sessionid = NULL;
@@ -2813,8 +3006,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
if(isproxy)
incache = FALSE;
else
- incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
- &old_ssl_sessionid, NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
if(incache) {
if(old_ssl_sessionid != ssl_sessionid) {
infof(data, "old SSL session ID is stale, removing");
@@ -2824,8 +3016,8 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
}
if(!incache) {
- if(!Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
- 0 /* unknown size */, sockindex, &added)) {
+ if(!Curl_ssl_addsessionid(cf, data, ssl_sessionid,
+ 0 /* unknown size */, &added)) {
if(added) {
/* the session has been put into the session cache */
res = 1;
@@ -2840,7 +3032,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
return res;
}
-static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
+static CURLcode load_cacert_from_memory(X509_STORE *store,
const struct curl_blob *ca_info_blob)
{
/* these need to be freed at the end */
@@ -2849,16 +3041,11 @@ static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
/* everything else is just a reference */
int i, count = 0;
- X509_STORE *cts = NULL;
X509_INFO *itmp = NULL;
if(ca_info_blob->len > (size_t)INT_MAX)
return CURLE_SSL_CACERT_BADFILE;
- cts = SSL_CTX_get_cert_store(ctx);
- if(!cts)
- return CURLE_OUT_OF_MEMORY;
-
cbio = BIO_new_mem_buf(ca_info_blob->data, (int)ca_info_blob->len);
if(!cbio)
return CURLE_OUT_OF_MEMORY;
@@ -2873,7 +3060,7 @@ static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) {
itmp = sk_X509_INFO_value(inf, i);
if(itmp->x509) {
- if(X509_STORE_add_cert(cts, itmp->x509)) {
+ if(X509_STORE_add_cert(store, itmp->x509)) {
++count;
}
else {
@@ -2883,7 +3070,7 @@ static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
}
}
if(itmp->crl) {
- if(X509_STORE_add_crl(cts, itmp->crl)) {
+ if(X509_STORE_add_crl(store, itmp->crl)) {
++count;
}
else {
@@ -2901,21 +3088,414 @@ static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
return (count > 0 ? CURLE_OK : CURLE_SSL_CACERT_BADFILE);
}
-static CURLcode ossl_connect_step1(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode populate_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ X509_STORE *store)
+{
+ 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);
+ CURLcode result = CURLE_OK;
+ X509_LOOKUP *lookup = NULL;
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
+ const char * const ssl_cafile =
+ /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const char * const ssl_capath = conn_config->CApath;
+ const char * const ssl_crlfile = ssl_config->primary.CRLfile;
+ const bool verifypeer = conn_config->verifypeer;
+ bool imported_native_ca = false;
+
+ if(!store)
+ return CURLE_OUT_OF_MEMORY;
+
+#if defined(USE_WIN32_CRYPTO)
+ /* Import certificates from the Windows root certificate store if requested.
+ https://stackoverflow.com/questions/9507184/
+ https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037
+ https://datatracker.ietf.org/doc/html/rfc5280 */
+ if((conn_config->verifypeer || conn_config->verifyhost) &&
+ (ssl_config->native_ca_store)) {
+ HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT"));
+
+ if(hStore) {
+ PCCERT_CONTEXT pContext = NULL;
+ /* The array of enhanced key usage OIDs will vary per certificate and is
+ declared outside of the loop so that rather than malloc/free each
+ iteration we can grow it with realloc, when necessary. */
+ CERT_ENHKEY_USAGE *enhkey_usage = NULL;
+ DWORD enhkey_usage_size = 0;
+
+ /* This loop makes a best effort to import all valid certificates from
+ the MS root store. If a certificate cannot be imported it is skipped.
+ 'result' is used to store only hard-fail conditions (such as out of
+ memory) that cause an early break. */
+ result = CURLE_OK;
+ for(;;) {
+ X509 *x509;
+ FILETIME now;
+ BYTE key_usage[2];
+ DWORD req_size;
+ const unsigned char *encoded_cert;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ char cert_name[256];
+#endif
+
+ pContext = CertEnumCertificatesInStore(hStore, pContext);
+ if(!pContext)
+ break;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
+ NULL, cert_name, sizeof(cert_name))) {
+ strcpy(cert_name, "Unknown");
+ }
+ infof(data, "SSL: Checking cert \"%s\"", cert_name);
+#endif
+
+ encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
+ if(!encoded_cert)
+ continue;
+
+ GetSystemTimeAsFileTime(&now);
+ if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 ||
+ CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0)
+ continue;
+
+ /* If key usage exists check for signing attribute */
+ if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType,
+ pContext->pCertInfo,
+ key_usage, sizeof(key_usage))) {
+ if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
+ continue;
+ }
+ else if(GetLastError())
+ continue;
+
+ /* If enhanced key usage exists check for server auth attribute.
+ *
+ * Note "In a Microsoft environment, a certificate might also have EKU
+ * extended properties that specify valid uses for the certificate."
+ * The call below checks both, and behavior varies depending on what is
+ * found. For more details see CertGetEnhancedKeyUsage doc.
+ */
+ if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) {
+ if(req_size && req_size > enhkey_usage_size) {
+ void *tmp = realloc(enhkey_usage, req_size);
+
+ if(!tmp) {
+ failf(data, "SSL: Out of memory allocating for OID list");
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ enhkey_usage = (CERT_ENHKEY_USAGE *)tmp;
+ enhkey_usage_size = req_size;
+ }
+
+ if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) {
+ if(!enhkey_usage->cUsageIdentifier) {
+ /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is
+ good for all uses. If it returns zero, the certificate has no
+ valid uses." */
+ if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
+ continue;
+ }
+ else {
+ DWORD i;
+ bool found = false;
+
+ for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
+ if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
+ enhkey_usage->rgpszUsageIdentifier[i])) {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ continue;
+ }
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
+ if(!x509)
+ continue;
+
+ /* Try to import the certificate. This may fail for legitimate reasons
+ such as duplicate certificate, which is allowed by MS but not
+ OpenSSL. */
+ if(X509_STORE_add_cert(store, x509) == 1) {
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ infof(data, "SSL: Imported cert \"%s\"", cert_name);
+#endif
+ imported_native_ca = true;
+ }
+ X509_free(x509);
+ }
+
+ free(enhkey_usage);
+ CertFreeCertificateContext(pContext);
+ CertCloseStore(hStore, 0);
+
+ if(result)
+ return result;
+ }
+ if(imported_native_ca)
+ infof(data, "successfully imported Windows CA store");
+ else
+ infof(data, "error importing Windows CA store, continuing anyway");
+ }
+#endif
+
+ if(ca_info_blob) {
+ result = load_cacert_from_memory(store, ca_info_blob);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY ||
+ (verifypeer && !imported_native_ca)) {
+ failf(data, "error importing CA certificate blob");
+ return result;
+ }
+ /* Only warn if no certificate verification is required. */
+ infof(data, "error importing CA certificate blob, continuing anyway");
+ }
+ }
+
+ if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) {
+#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
+ /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
+ if(ssl_cafile &&
+ !X509_STORE_load_file(store, ssl_cafile)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate file: %s", ssl_cafile);
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ if(ssl_capath &&
+ !X509_STORE_load_path(store, ssl_capath)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate path: %s", ssl_capath);
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+#else
+ /* tell OpenSSL where to find CA certificates that are used to verify the
+ server's certificate. */
+ if(!X509_STORE_load_locations(store, 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 CURLE_SSL_CACERT_BADFILE;
+ }
+#endif
+ infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+ infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+ }
+
+#ifdef CURL_CA_FALLBACK
+ if(verifypeer &&
+ !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) {
+ /* verifying the peer without any CA certificates won't
+ work so use openssl's built-in default as fallback */
+ X509_STORE_set_default_paths(store);
+ }
+#endif
+
+ if(ssl_crlfile) {
+ /* tell OpenSSL where to find CRL file that is used to check certificate
+ * revocation */
+ lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
+ if(!lookup ||
+ (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) {
+ failf(data, "error loading CRL file: %s", ssl_crlfile);
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ /* Everything is fine. */
+ infof(data, "successfully loaded CRL file:");
+ X509_STORE_set_flags(store,
+ X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+
+ infof(data, " CRLfile: %s", ssl_crlfile);
+ }
+
+ if(verifypeer) {
+ /* Try building a chain using issuers in the trusted store first to avoid
+ problems with server-sent legacy intermediates. Newer versions of
+ OpenSSL do alternate chain checking by default but we do not know how to
+ determine that in a reliable manner.
+ https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
+ */
+#if defined(X509_V_FLAG_TRUSTED_FIRST)
+ X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);
+#endif
+#ifdef X509_V_FLAG_PARTIAL_CHAIN
+ if(!ssl_config->no_partialchain && !ssl_crlfile) {
+ /* Have intermediate certificates in the trust store be treated as
+ trust-anchors, in the same way as self-signed root CA certificates
+ are. This allows users to verify servers using the intermediate cert
+ only, instead of needing the whole chain.
+
+ Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we
+ cannot do partial chains with a CRL check.
+ */
+ X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN);
+ }
+#endif
+ }
+
+ return result;
+}
+
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+static bool cached_x509_store_expired(const struct Curl_easy *data,
+ const struct multi_ssl_backend_data *mb)
+{
+ const struct ssl_general_config *cfg = &data->set.general_ssl;
+ struct curltime now = Curl_now();
+ timediff_t elapsed_ms = Curl_timediff(now, mb->time);
+ timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
+
+ if(timeout_ms < 0)
+ return false;
+
+ return elapsed_ms >= timeout_ms;
+}
+
+static bool cached_x509_store_different(
+ struct Curl_cfilter *cf,
+ const struct multi_ssl_backend_data *mb)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!mb->CAfile || !conn_config->CAfile)
+ return mb->CAfile != conn_config->CAfile;
+
+ return strcmp(mb->CAfile, conn_config->CAfile);
+}
+
+static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
+{
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ X509_STORE *store = NULL;
+
+ if(multi &&
+ multi->ssl_backend_data &&
+ multi->ssl_backend_data->store &&
+ !cached_x509_store_expired(data, multi->ssl_backend_data) &&
+ !cached_x509_store_different(cf, multi->ssl_backend_data)) {
+ store = multi->ssl_backend_data->store;
+ }
+
+ return store;
+}
+
+static void set_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data,
+ X509_STORE *store)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct multi_ssl_backend_data *mbackend;
+
+ if(!multi)
+ return;
+
+ if(!multi->ssl_backend_data) {
+ multi->ssl_backend_data = calloc(1, sizeof(struct multi_ssl_backend_data));
+ if(!multi->ssl_backend_data)
+ return;
+ }
+
+ mbackend = multi->ssl_backend_data;
+
+ if(X509_STORE_up_ref(store)) {
+ char *CAfile = NULL;
+
+ if(conn_config->CAfile) {
+ CAfile = strdup(conn_config->CAfile);
+ if(!CAfile) {
+ X509_STORE_free(store);
+ return;
+ }
+ }
+
+ if(mbackend->store) {
+ X509_STORE_free(mbackend->store);
+ free(mbackend->CAfile);
+ }
+
+ mbackend->time = Curl_now();
+ mbackend->store = store;
+ mbackend->CAfile = CAfile;
+ }
+}
+
+static CURLcode set_up_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_backend_data *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);
+ CURLcode result = CURLE_OK;
+ X509_STORE *cached_store;
+ bool cache_criteria_met;
+
+ /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
+ or no source is provided and we are falling back to openssl's built-in
+ default. */
+ cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
+ conn_config->verifypeer &&
+ !conn_config->CApath &&
+ !conn_config->ca_info_blob &&
+ !ssl_config->primary.CRLfile &&
+ !ssl_config->native_ca_store;
+
+ cached_store = get_cached_x509_store(cf, data);
+ if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) {
+ SSL_CTX_set_cert_store(backend->ctx, cached_store);
+ }
+ else {
+ X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
+
+ result = populate_x509_store(cf, data, store);
+ if(result == CURLE_OK && cache_criteria_met) {
+ set_cached_x509_store(cf, data, store);
+ }
+ }
+
+ return result;
+}
+#else /* HAVE_SSL_X509_STORE_SHARE */
+static CURLcode set_up_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_backend_data *backend)
+{
+ X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
+
+ return populate_x509_store(cf, data, store);
+}
+#endif /* HAVE_SSL_X509_STORE_SHARE */
+
+static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
char *ciphers;
SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
- X509_LOOKUP *lookup = NULL;
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
ctx_option_t ctx_options = 0;
void *ssl_sessionid = NULL;
+ 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);
+ BIO *bio;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
bool sni;
- const char * const hostname = SSL_HOST_NAME();
+ const char *hostname = connssl->hostname;
#ifdef ENABLE_IPV6
struct in6_addr addr;
@@ -2923,23 +3503,16 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
struct in_addr addr;
#endif
#endif
- const long int ssl_version = SSL_CONN_CONFIG(version);
+ const long int ssl_version = conn_config->version;
#ifdef USE_OPENSSL_SRP
- const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(primary.authtype);
+ const enum CURL_TLSAUTH ssl_authtype = ssl_config->primary.authtype;
#endif
- char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
- const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
- const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
- const char * const ssl_cafile =
- /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
- const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const char * const ssl_crlfile = SSL_SET_OPTION(primary.CRLfile);
+ char * const ssl_cert = ssl_config->primary.clientcert;
+ const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
+ const char * const ssl_cert_type = ssl_config->cert_type;
+ const bool verifypeer = conn_config->verifypeer;
char error_buffer[256];
struct ssl_backend_data *backend = connssl->backend;
- bool imported_native_ca = false;
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
DEBUGASSERT(backend);
@@ -2949,7 +3522,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
if(result)
return result;
- SSL_SET_OPTION_LVALUE(certverifyresult) = !X509_V_OK;
+ ssl_config->certverifyresult = !X509_V_OK;
/* check to see if we've been told to use an explicit SSL/TLS version */
@@ -2979,7 +3552,12 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- DEBUGASSERT(!backend->ctx);
+ if(backend->ctx) {
+ /* This happens when an error was encountered before in this
+ * step and we are called to do it again. Get rid of any leftover
+ * from the previous call. */
+ ossl_close(cf, data);
+ }
backend->ctx = SSL_CTX_new(req_method);
if(!backend->ctx) {
@@ -2996,8 +3574,8 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
if(data->set.fdebug && data->set.verbose) {
/* the SSL trace callback is only used for verbose logging */
SSL_CTX_set_msg_callback(backend->ctx, ossl_trace);
- SSL_CTX_set_msg_callback_arg(backend->ctx, conn);
- set_logger(conn, data);
+ SSL_CTX_set_msg_callback_arg(backend->ctx, cf->conn);
+ set_logger(connssl, data);
}
#endif
@@ -3055,7 +3633,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
/* unless the user explicitly asks to allow the protocol vulnerability we
use the work-around */
- if(!SSL_SET_OPTION(enable_beast))
+ if(!ssl_config->enable_beast)
ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#endif
@@ -3077,10 +3655,9 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
ctx_options |= SSL_OP_NO_SSLv3;
#if HAS_MODERN_SET_PROTO_VER /* 1.1.0 */
- result = set_ssl_version_min_max(backend->ctx, conn);
+ result = set_ssl_version_min_max(cf, backend->ctx);
#else
- result = set_ssl_version_min_max_legacy(&ctx_options, data, conn,
- sockindex);
+ result = set_ssl_version_min_max_legacy(&ctx_options, cf, data);
#endif
if(result != CURLE_OK)
return result;
@@ -3094,14 +3671,14 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
SSL_CTX_set_options(backend->ctx, ctx_options);
#ifdef HAS_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
int cur = 0;
unsigned char protocols[128];
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
- && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+ && (!Curl_ssl_cf_is_proxy(cf) || !cf->conn->bits.tunnel_proxy)
#endif
) {
protocols[cur++] = ALPN_H2_LENGTH;
@@ -3131,15 +3708,15 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
if(!result &&
!cert_stuff(data, backend->ctx,
ssl_cert, ssl_cert_blob, ssl_cert_type,
- SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob),
- SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd)))
+ ssl_config->key, ssl_config->key_blob,
+ ssl_config->key_type, ssl_config->key_passwd))
result = CURLE_SSL_CERTPROBLEM;
if(result)
/* failf() is already done in cert_stuff() */
return result;
}
- ciphers = SSL_CONN_CONFIG(cipher_list);
+ ciphers = conn_config->cipher_list;
if(!ciphers)
ciphers = (char *)DEFAULT_CIPHER_SELECTION;
if(ciphers) {
@@ -3152,7 +3729,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
{
- char *ciphers13 = SSL_CONN_CONFIG(cipher_list13);
+ char *ciphers13 = conn_config->cipher_list13;
if(ciphers13) {
if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) {
failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
@@ -3170,7 +3747,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#ifdef HAVE_SSL_CTX_SET_EC_CURVES
{
- char *curves = SSL_CONN_CONFIG(curves);
+ char *curves = conn_config->curves;
if(curves) {
if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
failf(data, "failed setting curves list: '%s'", curves);
@@ -3183,8 +3760,8 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#ifdef USE_OPENSSL_SRP
if((ssl_authtype == CURL_TLSAUTH_SRP) &&
Curl_auth_allowed_to_host(data)) {
- char * const ssl_username = SSL_SET_OPTION(primary.username);
- char * const ssl_password = SSL_SET_OPTION(primary.password);
+ char * const ssl_username = ssl_config->primary.username;
+ char * const ssl_password = ssl_config->primary.password;
infof(data, "Using TLS-SRP username: %s", ssl_username);
if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) {
@@ -3195,7 +3772,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
failf(data, "failed setting SRP password");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!SSL_CONN_CONFIG(cipher_list)) {
+ if(!conn_config->cipher_list) {
infof(data, "Setting cipher list SRP");
if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) {
@@ -3206,249 +3783,9 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
}
#endif
-
-#if defined(USE_WIN32_CRYPTO)
- /* Import certificates from the Windows root certificate store if requested.
- https://stackoverflow.com/questions/9507184/
- https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037
- https://datatracker.ietf.org/doc/html/rfc5280 */
- if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) &&
- (SSL_SET_OPTION(native_ca_store))) {
- X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
- HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT"));
-
- if(hStore) {
- PCCERT_CONTEXT pContext = NULL;
- /* The array of enhanced key usage OIDs will vary per certificate and is
- declared outside of the loop so that rather than malloc/free each
- iteration we can grow it with realloc, when necessary. */
- CERT_ENHKEY_USAGE *enhkey_usage = NULL;
- DWORD enhkey_usage_size = 0;
-
- /* This loop makes a best effort to import all valid certificates from
- the MS root store. If a certificate cannot be imported it is skipped.
- 'result' is used to store only hard-fail conditions (such as out of
- memory) that cause an early break. */
- result = CURLE_OK;
- for(;;) {
- X509 *x509;
- FILETIME now;
- BYTE key_usage[2];
- DWORD req_size;
- const unsigned char *encoded_cert;
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- char cert_name[256];
-#endif
-
- pContext = CertEnumCertificatesInStore(hStore, pContext);
- if(!pContext)
- break;
-
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
- NULL, cert_name, sizeof(cert_name))) {
- strcpy(cert_name, "Unknown");
- }
- infof(data, "SSL: Checking cert \"%s\"", cert_name);
-#endif
-
- encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
- if(!encoded_cert)
- continue;
-
- GetSystemTimeAsFileTime(&now);
- if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 ||
- CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0)
- continue;
-
- /* If key usage exists check for signing attribute */
- if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType,
- pContext->pCertInfo,
- key_usage, sizeof(key_usage))) {
- if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
- continue;
- }
- else if(GetLastError())
- continue;
-
- /* If enhanced key usage exists check for server auth attribute.
- *
- * Note "In a Microsoft environment, a certificate might also have EKU
- * extended properties that specify valid uses for the certificate."
- * The call below checks both, and behavior varies depending on what is
- * found. For more details see CertGetEnhancedKeyUsage doc.
- */
- if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) {
- if(req_size && req_size > enhkey_usage_size) {
- void *tmp = realloc(enhkey_usage, req_size);
-
- if(!tmp) {
- failf(data, "SSL: Out of memory allocating for OID list");
- result = CURLE_OUT_OF_MEMORY;
- break;
- }
-
- enhkey_usage = (CERT_ENHKEY_USAGE *)tmp;
- enhkey_usage_size = req_size;
- }
-
- if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) {
- if(!enhkey_usage->cUsageIdentifier) {
- /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is
- good for all uses. If it returns zero, the certificate has no
- valid uses." */
- if((HRESULT)GetLastError() != CRYPT_E_NOT_FOUND)
- continue;
- }
- else {
- DWORD i;
- bool found = false;
-
- for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
- if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
- enhkey_usage->rgpszUsageIdentifier[i])) {
- found = true;
- break;
- }
- }
-
- if(!found)
- continue;
- }
- }
- else
- continue;
- }
- else
- continue;
-
- x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
- if(!x509)
- continue;
-
- /* Try to import the certificate. This may fail for legitimate reasons
- such as duplicate certificate, which is allowed by MS but not
- OpenSSL. */
- if(X509_STORE_add_cert(store, x509) == 1) {
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- infof(data, "SSL: Imported cert \"%s\"", cert_name);
-#endif
- imported_native_ca = true;
- }
- X509_free(x509);
- }
-
- free(enhkey_usage);
- CertFreeCertificateContext(pContext);
- CertCloseStore(hStore, 0);
-
- if(result)
- return result;
- }
- if(imported_native_ca)
- infof(data, "successfully imported Windows CA store");
- else
- infof(data, "error importing Windows CA store, continuing anyway");
- }
-#endif
-
- if(ca_info_blob) {
- result = load_cacert_from_memory(backend->ctx, ca_info_blob);
- if(result) {
- if(result == CURLE_OUT_OF_MEMORY ||
- (verifypeer && !imported_native_ca)) {
- failf(data, "error importing CA certificate blob");
- return result;
- }
- /* Only warn if no certificate verification is required. */
- infof(data, "error importing CA certificate blob, continuing anyway");
- }
- }
-
- if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) {
-#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
- /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
- if(ssl_cafile &&
- !SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate file: %s", ssl_cafile);
- return CURLE_SSL_CACERT_BADFILE;
- }
- if(ssl_capath &&
- !SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate path: %s", ssl_capath);
- return CURLE_SSL_CACERT_BADFILE;
- }
-#else
- /* tell OpenSSL where to find CA certificates that are used to verify the
- server's certificate. */
- if(!SSL_CTX_load_verify_locations(backend->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 CURLE_SSL_CACERT_BADFILE;
- }
-#endif
- infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
- infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
- }
-
-#ifdef CURL_CA_FALLBACK
- if(verifypeer &&
- !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) {
- /* verifying the peer without any CA certificates won't
- work so use openssl's built-in default as fallback */
- SSL_CTX_set_default_verify_paths(backend->ctx);
- }
-#endif
-
- if(ssl_crlfile) {
- /* tell OpenSSL where to find CRL file that is used to check certificate
- * revocation */
- lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx),
- X509_LOOKUP_file());
- if(!lookup ||
- (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) {
- failf(data, "error loading CRL file: %s", ssl_crlfile);
- return CURLE_SSL_CRL_BADFILE;
- }
- /* Everything is fine. */
- infof(data, "successfully loaded CRL file:");
- X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
- X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
-
- infof(data, " CRLfile: %s", ssl_crlfile);
- }
-
- if(verifypeer) {
- /* Try building a chain using issuers in the trusted store first to avoid
- problems with server-sent legacy intermediates. Newer versions of
- OpenSSL do alternate chain checking by default but we do not know how to
- determine that in a reliable manner.
- https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
- */
-#if defined(X509_V_FLAG_TRUSTED_FIRST)
- X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
- X509_V_FLAG_TRUSTED_FIRST);
-#endif
-#ifdef X509_V_FLAG_PARTIAL_CHAIN
- if(!SSL_SET_OPTION(no_partialchain) && !ssl_crlfile) {
- /* Have intermediate certificates in the trust store be treated as
- trust-anchors, in the same way as self-signed root CA certificates
- are. This allows users to verify servers using the intermediate cert
- only, instead of needing the whole chain.
-
- Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we
- cannot do partial chains with a CRL check.
- */
- X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
- X509_V_FLAG_PARTIAL_CHAIN);
- }
-#endif
- }
+ result = set_up_x509_store(cf, data, backend);
+ if(result)
+ return result;
/* OpenSSL always tries to verify the peer, this only says whether it should
* fail to connect if the verification fails, or if it should continue
@@ -3495,7 +3832,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(SSL_CONN_CONFIG(verifystatus))
+ if(conn_config->verifystatus)
SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp);
#endif
@@ -3520,18 +3857,17 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
}
#endif
- if(!ossl_associate_connection(data, conn, sockindex)) {
+ if(!ossl_attach_data(cf, data)) {
/* Maybe the internal errors of SSL_get_ex_new_index or SSL_set_ex_data */
- failf(data, "SSL: ossl_associate_connection failed: %s",
+ failf(data, "SSL: ossl_attach_data failed: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
- &ssl_sessionid, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(data);
@@ -3546,40 +3882,25 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
Curl_ssl_sessionid_unlock(data);
}
-#ifndef CURL_DISABLE_PROXY
- if(conn->proxy_ssl[sockindex].use) {
- BIO *const bio = BIO_new(BIO_f_ssl());
- struct ssl_backend_data *proxy_backend;
- SSL* handle = NULL;
- proxy_backend = conn->proxy_ssl[sockindex].backend;
- DEBUGASSERT(proxy_backend);
- handle = proxy_backend->handle;
- DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
- DEBUGASSERT(handle != NULL);
- DEBUGASSERT(bio != NULL);
- BIO_set_ssl(bio, handle, FALSE);
- SSL_set_bio(backend->handle, bio, bio);
- }
- else
-#endif
- if(!SSL_set_fd(backend->handle, (int)sockfd)) {
- /* pass the raw socket into the SSL layers */
- failf(data, "SSL: SSL_set_fd failed: %s",
- ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)));
- return CURLE_SSL_CONNECT_ERROR;
- }
+ bio = BIO_new(bio_cf_method);
+ if(!bio)
+ return CURLE_OUT_OF_MEMORY;
+
+ BIO_set_data(bio, cf);
+ SSL_set_bio(backend->handle, bio, bio);
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
}
-static CURLcode ossl_connect_step2(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
int err;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state
|| ssl_connect_2_writing == connssl->connecting_state);
@@ -3617,6 +3938,9 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
return CURLE_OK;
}
#endif
+ else if(backend->io_result == CURLE_AGAIN) {
+ return CURLE_OK;
+ }
else {
/* untreated error */
unsigned long errdetail;
@@ -3644,7 +3968,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
lerr = SSL_get_verify_result(backend->handle);
if(lerr != X509_V_OK) {
- SSL_SET_OPTION_LVALUE(certverifyresult) = lerr;
+ ssl_config->certverifyresult = lerr;
msnprintf(error_buffer, sizeof(error_buffer),
"SSL certificate problem: %s",
X509_verify_cert_error_string(lerr));
@@ -3679,15 +4003,14 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
* the SO_ERROR is also lost.
*/
if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
- const char * const hostname = SSL_HOST_NAME();
- const long int port = SSL_HOST_PORT();
char extramsg[80]="";
int sockerr = SOCKERRNO;
+
if(sockerr && detail == SSL_ERROR_SYSCALL)
Curl_strerror(sockerr, extramsg, sizeof(extramsg));
- failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%ld ",
+ failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
- hostname, port);
+ connssl->hostname, connssl->port);
return result;
}
@@ -3710,7 +4033,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
* negotiated
*/
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
const unsigned char *neg_protocol;
unsigned int len;
SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len);
@@ -3720,19 +4043,19 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
#ifdef USE_HTTP2
if(len == ALPN_H2_LENGTH &&
!memcmp(ALPN_H2, neg_protocol, len)) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(len == ALPN_HTTP_1_1_LENGTH &&
!memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
}
else
infof(data, VTLS_INFOF_NO_ALPN);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
#endif
@@ -3807,11 +4130,14 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
* We check certificates to authenticate the server; otherwise we risk
* man-in-the-middle attack.
*/
-static CURLcode servercert(struct Curl_easy *data,
- struct connectdata *conn,
- struct ssl_connect_data *connssl,
+static CURLcode servercert(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool strict)
{
+ struct connectdata *conn = cf->conn;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
CURLcode result = CURLE_OK;
int rc;
long lerr;
@@ -3848,7 +4174,8 @@ static CURLcode servercert(struct Curl_easy *data,
return CURLE_PEER_FAILED_VERIFICATION;
}
- infof(data, "%s certificate:", SSL_IS_PROXY() ? "Proxy" : "Server");
+ infof(data, "%s certificate:",
+ Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");
rc = x509_name_oneline(X509_get_subject_name(backend->server_cert),
buffer, sizeof(buffer));
@@ -3871,7 +4198,7 @@ static CURLcode servercert(struct Curl_easy *data,
BIO_free(mem);
- if(SSL_CONN_CONFIG(verifyhost)) {
+ if(conn_config->verifyhost) {
result = Curl_ossl_verifyhost(data, conn, backend->server_cert);
if(result) {
X509_free(backend->server_cert);
@@ -3894,10 +4221,10 @@ static CURLcode servercert(struct Curl_easy *data,
deallocating the certificate. */
/* e.g. match issuer name with provided issuer certificate */
- if(SSL_CONN_CONFIG(issuercert) || SSL_CONN_CONFIG(issuercert_blob)) {
- if(SSL_CONN_CONFIG(issuercert_blob)) {
- fp = BIO_new_mem_buf(SSL_CONN_CONFIG(issuercert_blob)->data,
- (int)SSL_CONN_CONFIG(issuercert_blob)->len);
+ if(conn_config->issuercert || conn_config->issuercert_blob) {
+ if(conn_config->issuercert_blob) {
+ fp = BIO_new_mem_buf(conn_config->issuercert_blob->data,
+ (int)conn_config->issuercert_blob->len);
if(!fp) {
failf(data,
"BIO_new_mem_buf NULL, " OSSL_PACKAGE
@@ -3922,10 +4249,10 @@ static CURLcode servercert(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- if(BIO_read_filename(fp, SSL_CONN_CONFIG(issuercert)) <= 0) {
+ if(BIO_read_filename(fp, conn_config->issuercert) <= 0) {
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
- SSL_CONN_CONFIG(issuercert));
+ conn_config->issuercert);
BIO_free(fp);
X509_free(backend->server_cert);
backend->server_cert = NULL;
@@ -3937,7 +4264,7 @@ static CURLcode servercert(struct Curl_easy *data,
if(!issuer) {
if(strict)
failf(data, "SSL: Unable to read issuer cert (%s)",
- SSL_CONN_CONFIG(issuercert));
+ conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
X509_free(backend->server_cert);
@@ -3948,7 +4275,7 @@ static CURLcode servercert(struct Curl_easy *data,
if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
- SSL_CONN_CONFIG(issuercert));
+ conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
X509_free(backend->server_cert);
@@ -3957,15 +4284,15 @@ static CURLcode servercert(struct Curl_easy *data,
}
infof(data, " SSL certificate issuer check ok (%s)",
- SSL_CONN_CONFIG(issuercert));
+ conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
}
lerr = SSL_get_verify_result(backend->handle);
- SSL_SET_OPTION_LVALUE(certverifyresult) = lerr;
+ ssl_config->certverifyresult = lerr;
if(lerr != X509_V_OK) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(conn_config->verifypeer) {
/* We probably never reach this, because SSL_connect() will fail
and we return earlier if verifypeer is set? */
if(strict)
@@ -3984,8 +4311,8 @@ static CURLcode servercert(struct Curl_easy *data,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(SSL_CONN_CONFIG(verifystatus)) {
- result = verifystatus(data, connssl);
+ if(conn_config->verifystatus) {
+ result = verifystatus(cf, data);
if(result) {
X509_free(backend->server_cert);
backend->server_cert = NULL;
@@ -3998,7 +4325,9 @@ static CURLcode servercert(struct Curl_easy *data,
/* when not strict, we don't bother about the verify cert problems */
result = CURLE_OK;
- ptr = SSL_PINNED_PUB_KEY();
+ ptr = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
if(!result && ptr) {
result = pkp_pin_peer_pubkey(data, backend->server_cert, ptr);
if(result)
@@ -4012,11 +4341,12 @@ static CURLcode servercert(struct Curl_easy *data,
return result;
}
-static CURLcode ossl_connect_step3(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
@@ -4027,8 +4357,8 @@ static CURLcode ossl_connect_step3(struct Curl_easy *data,
* operations.
*/
- result = servercert(data, conn, connssl, (SSL_CONN_CONFIG(verifypeer) ||
- SSL_CONN_CONFIG(verifyhost)));
+ result = servercert(cf, data, conn_config->verifypeer ||
+ conn_config->verifyhost);
if(!result)
connssl->connecting_state = ssl_connect_done;
@@ -4036,18 +4366,14 @@ static CURLcode ossl_connect_step3(struct Curl_easy *data,
return result;
}
-static Curl_recv ossl_recv;
-static Curl_send ossl_send;
-
-static CURLcode ossl_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool nonblocking,
bool *done)
{
- CURLcode result;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ CURLcode result = CURLE_OK;
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
int what;
/* check if the connection has already been established */
@@ -4066,9 +4392,9 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- result = ossl_connect_step1(data, conn, sockindex);
+ result = ossl_connect_step1(cf, data);
if(result)
- return result;
+ goto out;
}
while(ssl_connect_2 == connssl->connecting_state ||
@@ -4081,7 +4407,8 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
if(timeout_ms < 0) {
/* no need to continue if time already is up */
failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
}
/* if ssl is expecting something, check if it's available. */
@@ -4098,16 +4425,19 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(0 == what) {
if(nonblocking) {
*done = FALSE;
- return CURLE_OK;
+ result = CURLE_OK;
+ goto out;
}
/* timeout */
failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
}
/* socket is readable or writable */
}
@@ -4118,25 +4448,23 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
- result = ossl_connect_step2(data, conn, sockindex);
+ result = ossl_connect_step2(cf, data);
if(result || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
ssl_connect_2_writing == connssl->connecting_state)))
- return result;
+ goto out;
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- result = ossl_connect_step3(data, conn, sockindex);
+ result = ossl_connect_step3(cf, data);
if(result)
- return result;
+ goto out;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = ossl_recv;
- conn->send[sockindex] = ossl_send;
*done = TRUE;
}
else
@@ -4145,24 +4473,24 @@ static CURLcode ossl_connect_common(struct Curl_easy *data,
/* Reset our connect state machine */
connssl->connecting_state = ssl_connect_1;
- return CURLE_OK;
+out:
+ return result;
}
-static CURLcode ossl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+static CURLcode ossl_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
bool *done)
{
- return ossl_connect_common(data, conn, sockindex, TRUE, done);
+ return ossl_connect_common(cf, data, TRUE, done);
}
-static CURLcode ossl_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode ossl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = ossl_connect_common(data, conn, sockindex, FALSE, &done);
+ result = ossl_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -4171,28 +4499,20 @@ static CURLcode ossl_connect(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static bool ossl_data_pending(const struct connectdata *conn,
- int connindex)
+static bool ossl_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- DEBUGASSERT(connssl->backend);
- if(connssl->backend->handle && SSL_pending(connssl->backend->handle))
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ if(ctx->backend->handle && SSL_pending(ctx->backend->handle))
return TRUE;
-#ifndef CURL_DISABLE_PROXY
- {
- const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex];
- DEBUGASSERT(proxyssl->backend);
- if(proxyssl->backend->handle && SSL_pending(proxyssl->backend->handle))
- return TRUE;
- }
-#endif
return FALSE;
}
-static size_t ossl_version(char *buffer, size_t size);
-
-static ssize_t ossl_send(struct Curl_easy *data,
- int sockindex,
+static ssize_t ossl_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const void *mem,
size_t len,
CURLcode *curlcode)
@@ -4204,16 +4524,16 @@ static ssize_t ossl_send(struct Curl_easy *data,
unsigned long sslerror;
int memlen;
int rc;
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ (void)data;
DEBUGASSERT(backend);
ERR_clear_error();
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- set_logger(conn, data);
+ set_logger(connssl, data);
rc = SSL_write(backend->handle, mem, memlen);
if(rc <= 0) {
@@ -4226,10 +4546,17 @@ static ssize_t ossl_send(struct Curl_easy *data,
should be called again later. This is basically an EWOULDBLOCK
equivalent. */
*curlcode = CURLE_AGAIN;
- return -1;
+ rc = -1;
+ goto out;
case SSL_ERROR_SYSCALL:
{
int sockerr = SOCKERRNO;
+
+ if(backend->io_result == CURLE_AGAIN) {
+ *curlcode = CURLE_AGAIN;
+ rc = -1;
+ goto out;
+ }
sslerror = ERR_get_error();
if(sslerror)
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
@@ -4242,18 +4569,20 @@ static ssize_t ossl_send(struct Curl_easy *data,
failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
error_buffer, sockerr);
*curlcode = CURLE_SEND_ERROR;
- return -1;
+ rc = -1;
+ goto out;
}
- case SSL_ERROR_SSL:
+ case SSL_ERROR_SSL: {
/* A failure in the SSL library occurred, usually a protocol error.
The OpenSSL error queue contains more information on the error. */
+ struct Curl_cfilter *cf_ssl_next = Curl_ssl_cf_get_ssl(cf->next);
+ struct ssl_connect_data *connssl_next = cf_ssl_next?
+ cf_ssl_next->ctx : NULL;
sslerror = ERR_get_error();
if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL &&
ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET &&
- conn->ssl[sockindex].state == ssl_connection_complete
-#ifndef CURL_DISABLE_PROXY
- && conn->proxy_ssl[sockindex].state == ssl_connection_complete
-#endif
+ connssl->state == ssl_connection_complete &&
+ (connssl_next && connssl_next->state == ssl_connection_complete)
) {
char ver[120];
(void)ossl_version(ver, sizeof(ver));
@@ -4263,20 +4592,26 @@ static ssize_t ossl_send(struct Curl_easy *data,
failf(data, "SSL_write() error: %s",
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
*curlcode = CURLE_SEND_ERROR;
- return -1;
+ rc = -1;
+ goto out;
+ }
+ default:
+ /* a true error */
+ failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
+ SSL_ERROR_to_str(err), SOCKERRNO);
+ *curlcode = CURLE_SEND_ERROR;
+ rc = -1;
+ goto out;
}
- /* a true error */
- failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
- SSL_ERROR_to_str(err), SOCKERRNO);
- *curlcode = CURLE_SEND_ERROR;
- return -1;
}
*curlcode = CURLE_OK;
+
+out:
return (ssize_t)rc; /* number of bytes */
}
-static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
- int num, /* socketindex */
+static ssize_t ossl_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data, /* transfer */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
CURLcode *curlcode)
@@ -4285,17 +4620,19 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
unsigned long sslerror;
ssize_t nread;
int buffsize;
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct connectdata *conn = cf->conn;
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ (void)data;
DEBUGASSERT(backend);
ERR_clear_error();
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- set_logger(conn, data);
+ set_logger(connssl, data);
nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
+
if(nread <= 0) {
/* failed SSL_read */
int err = SSL_get_error(backend->handle, (int)nread);
@@ -4305,7 +4642,7 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
break;
case SSL_ERROR_ZERO_RETURN: /* no more data */
/* close_notify alert */
- if(num == FIRSTSOCKET)
+ if(cf->sockindex == FIRSTSOCKET)
/* mark the connection for close if it is indeed the control
connection */
connclose(conn, "TLS close_notify");
@@ -4314,11 +4651,17 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
case SSL_ERROR_WANT_WRITE:
/* there's data pending, re-invoke SSL_read() */
*curlcode = CURLE_AGAIN;
- return -1;
+ nread = -1;
+ goto out;
default:
/* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
value/errno" */
/* https://www.openssl.org/docs/crypto/ERR_get_error.html */
+ if(backend->io_result == CURLE_AGAIN) {
+ *curlcode = CURLE_AGAIN;
+ nread = -1;
+ goto out;
+ }
sslerror = ERR_get_error();
if((nread < 0) || sslerror) {
/* If the return code was negative or there actually is an error in the
@@ -4335,7 +4678,8 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
error_buffer, sockerr);
*curlcode = CURLE_RECV_ERROR;
- return -1;
+ nread = -1;
+ goto out;
}
/* For debug builds be a little stricter and error on any
SSL_ERROR_SYSCALL. For example a server may have closed the connection
@@ -4358,11 +4702,14 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
" (Fatal because this is a curl debug build)",
error_buffer, sockerr);
*curlcode = CURLE_RECV_ERROR;
- return -1;
+ nread = -1;
+ goto out;
}
#endif
}
}
+
+out:
return nread;
}
@@ -4374,7 +4721,7 @@ static size_t ossl_version(char *buffer, size_t size)
int count;
const char *ver = OpenSSL_version(OPENSSL_VERSION);
const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */
- if(Curl_strncasecompare(ver, expected, sizeof(expected) - 1)) {
+ if(strncasecompare(ver, expected, sizeof(expected) - 1)) {
ver += sizeof(expected) - 1;
}
count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver);
@@ -4501,41 +4848,44 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl,
(void *)backend->ctx : (void *)backend->handle;
}
-static bool ossl_associate_connection(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+static bool ossl_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ const struct ssl_config_data *config;
+
DEBUGASSERT(backend);
/* If we don't have SSL context, do nothing. */
if(!backend->handle)
return FALSE;
- if(SSL_SET_OPTION(primary.sessionid)) {
+ config = Curl_ssl_cf_get_config(cf, data);
+ if(config->primary.sessionid) {
int data_idx = ossl_get_ssl_data_index();
- int connectdata_idx = ossl_get_ssl_conn_index();
+ int cf_idx = ossl_get_ssl_cf_index();
int sockindex_idx = ossl_get_ssl_sockindex_index();
int proxy_idx = ossl_get_proxy_index();
- if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 &&
+ if(data_idx >= 0 && cf_idx >= 0 && sockindex_idx >= 0 &&
proxy_idx >= 0) {
- int data_status, conn_status, sockindex_status, proxy_status;
+ int data_status, cf_status, sockindex_status, proxy_status;
/* Store the data needed for the "new session" callback.
* The sockindex is stored as a pointer to an array element. */
data_status = SSL_set_ex_data(backend->handle, data_idx, data);
- conn_status = SSL_set_ex_data(backend->handle, connectdata_idx, conn);
+ cf_status = SSL_set_ex_data(backend->handle, cf_idx, cf);
sockindex_status = SSL_set_ex_data(backend->handle, sockindex_idx,
- conn->sock + sockindex);
+ cf->conn->sock + cf->sockindex);
#ifndef CURL_DISABLE_PROXY
proxy_status = SSL_set_ex_data(backend->handle, proxy_idx,
- SSL_IS_PROXY() ? (void *) 1 : NULL);
+ Curl_ssl_cf_is_proxy(cf)?
+ (void *) 1 : NULL);
#else
proxy_status = SSL_set_ex_data(backend->handle, proxy_idx, NULL);
#endif
- if(data_status && conn_status && sockindex_status && proxy_status)
+ if(data_status && cf_status && sockindex_status && proxy_status)
return TRUE;
}
return FALSE;
@@ -4551,11 +4901,11 @@ static bool ossl_associate_connection(struct Curl_easy *data,
* transfer that might still be using the same connection.
*/
-static void ossl_disassociate_connection(struct Curl_easy *data,
- int sockindex)
+static void ossl_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
@@ -4563,24 +4913,38 @@ static void ossl_disassociate_connection(struct Curl_easy *data,
if(!backend->handle)
return;
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
int data_idx = ossl_get_ssl_data_index();
- int connectdata_idx = ossl_get_ssl_conn_index();
+ int cf_idx = ossl_get_ssl_cf_index();
int sockindex_idx = ossl_get_ssl_sockindex_index();
int proxy_idx = ossl_get_proxy_index();
- if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 &&
+ if(data_idx >= 0 && cf_idx >= 0 && sockindex_idx >= 0 &&
proxy_idx >= 0) {
/* Disable references to data in "new session" callback to avoid
* accessing a stale pointer. */
SSL_set_ex_data(backend->handle, data_idx, NULL);
- SSL_set_ex_data(backend->handle, connectdata_idx, NULL);
+ SSL_set_ex_data(backend->handle, cf_idx, NULL);
SSL_set_ex_data(backend->handle, sockindex_idx, NULL);
SSL_set_ex_data(backend->handle, proxy_idx, NULL);
}
}
}
+static void ossl_free_multi_ssl_backend_data(
+ struct multi_ssl_backend_data *mbackend)
+{
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+ if(mbackend->store) {
+ X509_STORE_free(mbackend->store);
+ }
+ free(mbackend->CAfile);
+ free(mbackend);
+#else /* HAVE_SSL_X509_STORE_SHARE */
+ (void)mbackend;
+#endif /* HAVE_SSL_X509_STORE_SHARE */
+}
+
const struct Curl_ssl Curl_ssl_openssl = {
{ CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
@@ -4606,7 +4970,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_cert_status_request, /* cert_status_request */
ossl_connect, /* connect */
ossl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks,/* getsock */
ossl_get_internals, /* get_internals */
ossl_close, /* close_one */
ossl_close_all, /* close_all */
@@ -4620,8 +4984,11 @@ const struct Curl_ssl Curl_ssl_openssl = {
#else
NULL, /* sha256sum */
#endif
- ossl_associate_connection, /* associate_connection */
- ossl_disassociate_connection /* disassociate_connection */
+ ossl_attach_data, /* use of data in this connection */
+ ossl_detach_data, /* remote of data from this connection */
+ ossl_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
+ ossl_recv, /* recv decrypted data */
+ ossl_send, /* send data to encrypt */
};
#endif /* USE_OPENSSL */
diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c
index 77a49f1ab4..27f4ec8d8c 100644
--- a/Utilities/cmcurl/lib/vtls/rustls.c
+++ b/Utilities/cmcurl/lib/vtls/rustls.c
@@ -35,6 +35,7 @@
#include "urldata.h"
#include "sendf.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "select.h"
#include "strerror.h"
#include "multiif.h"
@@ -63,43 +64,64 @@ static CURLcode map_error(rustls_result r)
}
static bool
-cr_data_pending(const struct connectdata *conn, int sockindex)
+cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- return backend->data_pending;
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ return ctx->backend->data_pending;
}
static CURLcode
-cr_connect(struct Curl_easy *data UNUSED_PARAM,
- struct connectdata *conn UNUSED_PARAM,
- int sockindex UNUSED_PARAM)
+cr_connect(struct Curl_cfilter *cf UNUSED_PARAM,
+ struct Curl_easy *data UNUSED_PARAM)
{
infof(data, "rustls_connect: unimplemented");
return CURLE_SSL_CONNECT_ERROR;
}
+struct io_ctx {
+ struct Curl_cfilter *cf;
+ struct Curl_easy *data;
+};
+
static int
read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
- ssize_t n = sread(*(int *)userdata, buf, len);
- if(n < 0) {
- return SOCKERRNO;
+ struct io_ctx *io_ctx = userdata;
+ CURLcode result;
+ int ret = 0;
+ ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
+ (char *)buf, len, &result);
+ if(nread < 0) {
+ nread = 0;
+ if(CURLE_AGAIN == result)
+ ret = EAGAIN;
+ else
+ ret = EINVAL;
}
- *out_n = n;
- return 0;
+ *out_n = (int)nread;
+ return ret;
}
static int
write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
- ssize_t n = swrite(*(int *)userdata, buf, len);
- if(n < 0) {
- return SOCKERRNO;
+ struct io_ctx *io_ctx = userdata;
+ CURLcode result;
+ int ret = 0;
+ ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
+ (const char *)buf, len, &result);
+ if(nwritten < 0) {
+ nwritten = 0;
+ if(CURLE_AGAIN == result)
+ ret = EAGAIN;
+ else
+ ret = EINVAL;
}
- *out_n = n;
- return 0;
+ *out_n = (int)nwritten;
+ return ret;
}
/*
@@ -115,13 +137,13 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
* output buffer.
*/
static ssize_t
-cr_recv(struct Curl_easy *data, int sockindex,
+cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *plainbuf, size_t plainlen, CURLcode *err)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *const connssl = cf->ctx;
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
+ struct io_ctx io_ctx;
size_t n = 0;
size_t tls_bytes_read = 0;
@@ -133,10 +155,13 @@ cr_recv(struct Curl_easy *data, int sockindex,
DEBUGASSERT(backend);
rconn = backend->conn;
- io_error = rustls_connection_read_tls(rconn, read_cb,
- &conn->sock[sockindex], &tls_bytes_read);
+ io_ctx.cf = cf;
+ io_ctx.data = data;
+
+ io_error = rustls_connection_read_tls(rconn, read_cb, &io_ctx,
+ &tls_bytes_read);
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
- infof(data, "sread: EAGAIN or EWOULDBLOCK");
+ infof(data, CFMSG(cf, "cr_recv: EAGAIN or EWOULDBLOCK"));
}
else if(io_error) {
char buffer[STRERROR_LEN];
@@ -146,7 +171,7 @@ cr_recv(struct Curl_easy *data, int sockindex,
return -1;
}
- infof(data, "cr_recv read %ld bytes from the network", tls_bytes_read);
+ infof(data, CFMSG(cf, "cr_recv: read %ld TLS bytes"), tls_bytes_read);
rresult = rustls_connection_process_new_packets(rconn);
if(rresult != RUSTLS_RESULT_OK) {
@@ -164,7 +189,8 @@ cr_recv(struct Curl_easy *data, int sockindex,
plainlen - plain_bytes_copied,
&n);
if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
- infof(data, "cr_recv got PLAINTEXT_EMPTY. will try again later.");
+ infof(data, CFMSG(cf, "cr_recv: got PLAINTEXT_EMPTY. "
+ "will try again later."));
backend->data_pending = FALSE;
break;
}
@@ -181,7 +207,7 @@ cr_recv(struct Curl_easy *data, int sockindex,
break;
}
else {
- infof(data, "cr_recv copied out %ld bytes of plaintext", n);
+ infof(data, CFMSG(cf, "cr_recv: got %ld plain bytes"), n);
plain_bytes_copied += n;
}
}
@@ -216,13 +242,13 @@ cr_recv(struct Curl_easy *data, int sockindex,
* It will only drain rustls' plaintext output buffer into the socket.
*/
static ssize_t
-cr_send(struct Curl_easy *data, int sockindex,
+cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *plainbuf, size_t plainlen, CURLcode *err)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *const connssl = cf->ctx;
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
+ struct io_ctx io_ctx;
size_t plainwritten = 0;
size_t tlswritten = 0;
size_t tlswritten_total = 0;
@@ -232,7 +258,7 @@ cr_send(struct Curl_easy *data, int sockindex,
DEBUGASSERT(backend);
rconn = backend->conn;
- infof(data, "cr_send %ld bytes of plaintext", plainlen);
+ infof(data, CFMSG(cf, "cr_send: %ld plain bytes"), plainlen);
if(plainlen > 0) {
rresult = rustls_connection_write(rconn, plainbuf, plainlen,
@@ -249,11 +275,15 @@ cr_send(struct Curl_easy *data, int sockindex,
}
}
+ io_ctx.cf = cf;
+ io_ctx.data = data;
+
while(rustls_connection_wants_write(rconn)) {
- io_error = rustls_connection_write_tls(rconn, write_cb,
- &conn->sock[sockindex], &tlswritten);
+ io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
+ &tlswritten);
if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
- infof(data, "swrite: EAGAIN after %ld bytes", tlswritten_total);
+ infof(data, CFMSG(cf, "cr_send: EAGAIN after %ld bytes"),
+ tlswritten_total);
*err = CURLE_AGAIN;
return -1;
}
@@ -269,7 +299,7 @@ cr_send(struct Curl_easy *data, int sockindex,
*err = CURLE_WRITE_ERROR;
return -1;
}
- infof(data, "cr_send wrote %ld bytes to network", tlswritten);
+ infof(data, CFMSG(cf, "cr_send: wrote %ld TLS bytes"), tlswritten);
tlswritten_total += tlswritten;
}
@@ -302,18 +332,20 @@ cr_hostname_is_ip(const char *hostname)
}
static CURLcode
-cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
+cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
struct ssl_backend_data *const backend)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct rustls_connection *rconn = NULL;
struct rustls_client_config_builder *config_builder = NULL;
struct rustls_root_cert_store *roots = NULL;
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const char *hostname = conn->host.name;
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const bool verifypeer = conn_config->verifypeer;
+ const char *hostname = connssl->hostname;
char errorbuf[256];
size_t errorlen;
int result;
@@ -400,7 +432,7 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
}
static void
-cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
+cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data,
const struct rustls_connection *rconn)
{
const uint8_t *protocol = NULL;
@@ -415,29 +447,29 @@ cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
#ifdef USE_HTTP2
if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) {
infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_H2);
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(len == ALPN_HTTP_1_1_LENGTH &&
0 == memcmp(ALPN_HTTP_1_1, protocol, len)) {
infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_HTTP_1_1);
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
else {
infof(data, "ALPN, negotiated an unrecognized protocol");
}
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == 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)
+cr_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data, bool *done)
{
- struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *const connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
CURLcode tmperr = CURLE_OK;
@@ -451,7 +483,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
DEBUGASSERT(backend);
if(ssl_connection_none == connssl->state) {
- result = cr_init_backend(data, conn, connssl->backend);
+ result = cr_init_backend(cf, data, connssl->backend);
if(result != CURLE_OK) {
return result;
}
@@ -471,10 +503,8 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
/* Done with the handshake. Set up callbacks to send/receive data. */
connssl->state = ssl_connection_complete;
- cr_set_negotiated_alpn(data, conn, rconn);
+ cr_set_negotiated_alpn(cf, data, rconn);
- conn->recv[sockindex] = cr_recv;
- conn->send[sockindex] = cr_send;
*done = TRUE;
return CURLE_OK;
}
@@ -502,7 +532,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
if(wants_write) {
infof(data, "rustls_connection wants us to write_tls.");
- cr_send(data, sockindex, NULL, 0, &tmperr);
+ cr_send(cf, data, NULL, 0, &tmperr);
if(tmperr == CURLE_AGAIN) {
infof(data, "writing would block");
/* fall through */
@@ -515,7 +545,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
if(wants_read) {
infof(data, "rustls_connection wants us to read_tls.");
- cr_recv(data, sockindex, NULL, 0, &tmperr);
+ cr_recv(cf, data, NULL, 0, &tmperr);
if(tmperr == CURLE_AGAIN) {
infof(data, "reading would block");
/* fall through */
@@ -539,13 +569,15 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
/* returns a bitmap of flags for this connection's first socket indicating
whether we want to read or write */
static int
-cr_getsock(struct connectdata *conn, curl_socket_t *socks)
+cr_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
+ curl_socket_t *socks)
{
- struct ssl_connect_data *const connssl = &conn->ssl[FIRSTSOCKET];
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+ struct ssl_connect_data *const connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
struct ssl_backend_data *const backend = connssl->backend;
struct rustls_connection *rconn = NULL;
+ (void)data;
DEBUGASSERT(backend);
rconn = backend->conn;
@@ -571,10 +603,9 @@ cr_get_internals(struct ssl_connect_data *connssl,
}
static void
-cr_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
CURLcode tmperr = CURLE_OK;
ssize_t n = 0;
@@ -583,7 +614,7 @@ cr_close(struct Curl_easy *data, struct connectdata *conn,
if(backend->conn) {
rustls_connection_send_close_notify(backend->conn);
- n = cr_send(data, sockindex, NULL, 0, &tmperr);
+ n = cr_send(cf, data, NULL, 0, &tmperr);
if(n < 0) {
failf(data, "error sending close notify: %d", tmperr);
}
@@ -606,7 +637,8 @@ static size_t cr_version(char *buffer, size_t size)
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_CAINFO_BLOB | /* supports */
- SSLSUPP_TLS13_CIPHERSUITES,
+ SSLSUPP_TLS13_CIPHERSUITES |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
Curl_none_init, /* init */
@@ -619,7 +651,7 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_cert_status_request, /* cert_status_request */
cr_connect, /* connect */
cr_connect_nonblocking, /* connect_nonblocking */
- cr_getsock, /* cr_getsock */
+ cr_get_select_socks, /* get_select_socks */
cr_get_internals, /* get_internals */
cr_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -630,7 +662,10 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ cr_recv, /* recv decrypted data */
+ cr_send, /* send data to encrypt */
};
#endif /* USE_RUSTLS */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index e022a2ce82..90a6fe6426 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -41,6 +41,7 @@
#include "schannel.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "strcase.h"
#include "sendf.h"
#include "connect.h" /* for the connect timeout */
@@ -185,11 +186,8 @@
#define PKCS12_NO_PERSIST_KEY 0x00008000
#endif
-static Curl_recv schannel_recv;
-static Curl_send schannel_send;
-
-static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const char *pinnedpubkey);
static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
@@ -209,11 +207,13 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
}
static CURLcode
-set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data,
- struct connectdata *conn)
+set_ssl_version_min_max(DWORD *enabled_protocols,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ 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;
long i = ssl_version;
switch(ssl_version_max) {
@@ -269,7 +269,7 @@ set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data,
return CURLE_OK;
}
-/*longest is 26, buffer is slightly bigger*/
+/* longest is 26, buffer is slightly bigger */
#define LONGEST_ALG_ID 32
#define CIPHEROPTION(X) \
if(strcmp(#X, tmp) == 0) \
@@ -296,7 +296,7 @@ get_alg_id_by_name(char *name)
CIPHEROPTION(CALG_MAC);
CIPHEROPTION(CALG_RSA_SIGN);
CIPHEROPTION(CALG_DSS_SIGN);
-/*ifdefs for the options that are defined conditionally in wincrypt.h*/
+/* ifdefs for the options that are defined conditionally in wincrypt.h */
#ifdef CALG_NO_SIGN
CIPHEROPTION(CALG_NO_SIGN);
#endif
@@ -484,11 +484,12 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
}
#endif
static CURLcode
-schannel_acquire_credential_handle(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+schannel_acquire_credential_handle(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ 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);
#ifdef HAS_CLIENT_CERT_PATH
PCCERT_CONTEXT client_certs[1] = { NULL };
@@ -505,7 +506,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
DEBUGASSERT(backend);
- if(conn->ssl_config.verifypeer) {
+ if(conn_config->verifypeer) {
#ifdef HAS_MANUAL_VERIFY_API
if(backend->use_manual_cred_validation)
flags = SCH_CRED_MANUAL_CRED_VALIDATION;
@@ -513,14 +514,14 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
#endif
flags = SCH_CRED_AUTO_CRED_VALIDATION;
- if(SSL_SET_OPTION(no_revoke)) {
+ if(ssl_config->no_revoke) {
flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
SCH_CRED_IGNORE_REVOCATION_OFFLINE;
DEBUGF(infof(data, "schannel: disabled server certificate revocation "
"checks"));
}
- else if(SSL_SET_OPTION(revoke_best_effort)) {
+ else if(ssl_config->revoke_best_effort) {
flags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
@@ -541,14 +542,14 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
"schannel: disabled server cert revocation checks"));
}
- if(!conn->ssl_config.verifyhost) {
+ if(!conn_config->verifyhost) {
flags |= SCH_CRED_NO_SERVERNAME_CHECK;
DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
"comparing the supplied target name with the subject "
"names in server certificates."));
}
- if(!SSL_SET_OPTION(auto_client_cert)) {
+ if(!ssl_config->auto_client_cert) {
flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
flags |= SCH_CRED_NO_DEFAULT_CREDS;
infof(data, "schannel: disabled automatic use of client certificate");
@@ -556,7 +557,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
else
infof(data, "schannel: enabled automatic use of client certificate");
- switch(conn->ssl_config.version) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
@@ -564,7 +565,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
{
- result = set_ssl_version_min_max(&enabled_protocols, data, conn);
+ result = set_ssl_version_min_max(&enabled_protocols, cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -819,7 +820,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
* disable all the ciphers and re-enable which
* ciphers the user has provided.
*/
- ciphers13 = SSL_CONN_CONFIG(cipher_list13);
+ ciphers13 = conn_config->cipher_list13;
if(ciphers13) {
const int remaining_ciphers = 5;
@@ -1013,7 +1014,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
else {
/* Pre-Windows 10 1809 */
ALG_ID algIds[NUM_CIPHERS];
- char *ciphers = SSL_CONN_CONFIG(cipher_list);
+ char *ciphers = conn_config->cipher_list;
SCHANNEL_CRED schannel_cred = { 0 };
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
schannel_cred.dwFlags = flags;
@@ -1022,7 +1023,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
if(ciphers) {
result = set_ssl_ciphers(&schannel_cred, ciphers, algIds);
if(CURLE_OK != result) {
- failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
+ failf(data, "Unable to set ciphers to from connection ssl config");
return result;
}
}
@@ -1072,11 +1073,13 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
}
static CURLcode
-schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
ssize_t written = -1;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ 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);
SecBuffer outbuf;
SecBufferDesc outbuf_desc;
SecBuffer inbuf;
@@ -1091,14 +1094,12 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
struct in6_addr addr6;
#endif
CURLcode result;
- char * const hostname = SSL_HOST_NAME();
- struct ssl_backend_data *backend = connssl->backend;
+ const char *hostname = connssl->hostname;
DEBUGASSERT(backend);
-
DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 1/3)",
- hostname, conn->remote_port));
+ "schannel: SSL/TLS connection with %s port %d (step 1/3)",
+ hostname, connssl->port));
if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
@@ -1111,7 +1112,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
Also it doesn't seem to be supported for Wine, see curl bug #983. */
- backend->use_alpn = conn->bits.tls_enable_alpn &&
+ backend->use_alpn = cf->conn->bits.tls_enable_alpn &&
!GetProcAddress(GetModuleHandle(TEXT("ntdll")),
"wine_get_version") &&
curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
@@ -1130,7 +1131,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
#else
#ifdef HAS_MANUAL_VERIFY_API
- if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
+ if(conn_config->CAfile || conn_config->ca_info_blob) {
if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
backend->use_manual_cred_validation = true;
@@ -1144,7 +1145,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
else
backend->use_manual_cred_validation = false;
#else
- if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
+ if(conn_config->CAfile || conn_config->ca_info_blob) {
failf(data, "schannel: CA cert support not built in");
return CURLE_NOT_BUILT_IN;
}
@@ -1154,11 +1155,9 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
backend->cred = NULL;
/* check for an existing re-usable credential handle */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- (void **)&old_cred, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
backend->cred = old_cred;
DEBUGF(infof(data, "schannel: re-using existing credential handle"));
@@ -1173,13 +1172,13 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(!backend->cred) {
char *snihost;
- result = schannel_acquire_credential_handle(data, conn, sockindex);
+ result = schannel_acquire_credential_handle(cf, data);
if(result != CURLE_OK) {
return result;
}
/* A hostname associated with the credential is needed by
InitializeSecurityContext for SNI and other reasons. */
- snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
+ snihost = Curl_ssl_snihost(data, hostname, NULL);
if(!snihost) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
@@ -1207,18 +1206,18 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* The first four bytes will be an unsigned int indicating number
of bytes of data in the rest of the buffer. */
- extension_len = (unsigned int *)(&alpn_buffer[cur]);
+ extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]);
cur += sizeof(unsigned int);
/* The next four bytes are an indicator that this buffer will contain
ALPN data, as opposed to NPN, for example. */
- *(unsigned int *)&alpn_buffer[cur] =
+ *(unsigned int *)(void *)&alpn_buffer[cur] =
SecApplicationProtocolNegotiationExt_ALPN;
cur += sizeof(unsigned int);
/* The next two bytes will be an unsigned short indicating the number
of bytes used to list the preferred protocols. */
- list_len = (unsigned short*)(&alpn_buffer[cur]);
+ list_len = (unsigned short*)(void *)(&alpn_buffer[cur]);
cur += sizeof(unsigned short);
list_start_index = cur;
@@ -1261,7 +1260,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
- if(!SSL_SET_OPTION(auto_client_cert)) {
+ if(!ssl_config->auto_client_cert) {
backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
}
@@ -1321,8 +1320,9 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
"sending %lu bytes.", outbuf.cbBuffer));
/* send initial handshake data which is now stored in output buffer */
- result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
- outbuf.cbBuffer, &written);
+ written = Curl_conn_cf_send(cf->next, data,
+ outbuf.pvBuffer, outbuf.cbBuffer,
+ &result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
failf(data, "schannel: failed to send initial handshake data: "
@@ -1346,12 +1346,13 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+schannel_connect_step2(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);
int i;
ssize_t nread = -1, written = -1;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
unsigned char *reallocated_buffer;
SecBuffer outbuf[3];
SecBufferDesc outbuf_desc;
@@ -1361,15 +1362,14 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
CURLcode result;
bool doread;
const char *pubkey_ptr;
- struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 2/3)",
- SSL_HOST_NAME(), conn->remote_port));
+ "schannel: SSL/TLS connection with %s port %d (step 2/3)",
+ connssl->hostname, connssl->port));
if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR;
@@ -1419,12 +1419,12 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
for(;;) {
if(doread) {
/* read encrypted handshake data from socket */
- result = Curl_read_plain(conn->sock[sockindex],
+ nread = Curl_conn_cf_recv(cf->next, data,
(char *) (backend->encdata_buffer +
backend->encdata_offset),
backend->encdata_length -
backend->encdata_offset,
- &nread);
+ &result);
if(result == CURLE_AGAIN) {
if(connssl->connecting_state != ssl_connect_2_writing)
connssl->connecting_state = ssl_connect_2_reading;
@@ -1508,9 +1508,9 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
"sending %lu bytes.", outbuf[i].cbBuffer));
/* send handshake token to server */
- result = Curl_write_plain(data, conn->sock[sockindex],
- outbuf[i].pvBuffer, outbuf[i].cbBuffer,
- &written);
+ written = Curl_conn_cf_send(cf->next, data,
+ outbuf[i].pvBuffer, outbuf[i].cbBuffer,
+ &result);
if((result != CURLE_OK) ||
(outbuf[i].cbBuffer != (size_t) written)) {
failf(data, "schannel: failed to send next handshake data: "
@@ -1603,9 +1603,11 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
}
- pubkey_ptr = SSL_PINNED_PUB_KEY();
+ pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
if(pubkey_ptr) {
- result = pkp_pin_peer_pubkey(data, conn, sockindex, pubkey_ptr);
+ result = pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
if(result) {
failf(data, "SSL: public key does not match pinned public key");
return result;
@@ -1613,8 +1615,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAS_MANUAL_VERIFY_API
- if(conn->ssl_config.verifypeer && backend->use_manual_cred_validation) {
- return Curl_verify_certificate(data, conn, sockindex);
+ if(conn_config->verifypeer && backend->use_manual_cred_validation) {
+ return Curl_verify_certificate(cf, data);
}
#endif
@@ -1681,28 +1683,24 @@ add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
}
static CURLcode
-schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_backend_data *backend = connssl->backend;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
CURLcode result = CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SECURITY_STATUS sspi_status = SEC_E_OK;
CERT_CONTEXT *ccert_context = NULL;
- bool isproxy = SSL_IS_PROXY();
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- const char * const hostname = SSL_HOST_NAME();
-#endif
#ifdef HAS_ALPN
SecPkgContext_ApplicationProtocol alpn_result;
#endif
- struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 3/3)",
- hostname, conn->remote_port));
+ "schannel: SSL/TLS connection with %s port %d (step 3/3)",
+ connssl->hostname, connssl->port));
if(!backend->cred)
return CURLE_SSL_CONNECT_ERROR;
@@ -1754,13 +1752,13 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
alpn = CURL_HTTP_VERSION_1_1;
}
if(backend->recv_renegotiating) {
- if(alpn != conn->alpn) {
+ if(alpn != cf->conn->alpn) {
failf(data, "schannel: server selected an ALPN protocol too late");
return CURLE_SSL_CONNECT_ERROR;
}
}
else
- conn->alpn = alpn;
+ cf->conn->alpn = alpn;
}
else {
if(!backend->recv_renegotiating)
@@ -1768,21 +1766,20 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
if(!backend->recv_renegotiating) {
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
}
#endif
/* save the current session data for possible re-use */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
bool incache;
bool added = FALSE;
struct Curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred,
- NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL));
if(incache) {
if(old_cred != backend->cred) {
DEBUGF(infof(data,
@@ -1793,9 +1790,9 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
}
if(!incache) {
- result = Curl_ssl_addsessionid(data, conn, isproxy, backend->cred,
+ result = Curl_ssl_addsessionid(cf, data, backend->cred,
sizeof(struct Curl_schannel_cred),
- sockindex, &added);
+ &added);
if(result) {
Curl_ssl_sessionid_unlock(data);
failf(data, "schannel: failed to store credential handle");
@@ -1845,12 +1842,13 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode
-schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
- int sockindex, bool nonblocking, bool *done)
+schannel_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool nonblocking, bool *done)
{
CURLcode result;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
timediff_t timeout_ms;
int what;
@@ -1870,7 +1868,7 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OPERATION_TIMEDOUT;
}
- result = schannel_connect_step1(data, conn, sockindex);
+ result = schannel_connect_step1(cf, data);
if(result)
return result;
}
@@ -1925,7 +1923,7 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
* ensuring that a client using select() or epoll() will always
* have a valid fdset to wait on.
*/
- result = schannel_connect_step2(data, conn, sockindex);
+ result = schannel_connect_step2(cf, data);
if(result || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -1935,22 +1933,13 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- result = schannel_connect_step3(data, conn, sockindex);
+ result = schannel_connect_step3(cf, data);
if(result)
return result;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- if(!connssl->backend->recv_renegotiating) {
- /* On renegotiation, we don't want to reset the existing recv/send
- * function pointers. They will have been set after the initial TLS
- * handshake was completed. If they were subsequently modified, as
- * is the case with HTTP/2, we don't want to override that change.
- */
- conn->recv[sockindex] = schannel_recv;
- conn->send[sockindex] = schannel_send;
- }
#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
/* When SSPI is used in combination with Schannel
@@ -1961,7 +1950,7 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
{
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(backend);
- conn->sslContext = &backend->ctxt->ctxt_handle;
+ cf->conn->sslContext = &backend->ctxt->ctxt_handle;
}
#endif
@@ -1977,14 +1966,13 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
}
static ssize_t
-schannel_send(struct Curl_easy *data, int sockindex,
+schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
ssize_t written = -1;
size_t data_len = 0;
unsigned char *ptr = NULL;
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
SecBuffer outbuf[4];
SecBufferDesc outbuf_desc;
SECURITY_STATUS sspi_status = SEC_E_OK;
@@ -2075,7 +2063,7 @@ schannel_send(struct Curl_easy *data, int sockindex,
}
else if(!timeout_ms)
timeout_ms = TIMEDIFF_T_MAX;
- what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms);
+ what = SOCKET_WRITABLE(cf->conn->sock[cf->sockindex], timeout_ms);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -2092,8 +2080,9 @@ schannel_send(struct Curl_easy *data, int sockindex,
}
/* socket is writable */
- result = Curl_write_plain(data, conn->sock[sockindex], ptr + written,
- len - written, &this_write);
+ this_write = Curl_conn_cf_send(cf->next, data,
+ ptr + written, len - written,
+ &result);
if(result == CURLE_AGAIN)
continue;
else if(result != CURLE_OK) {
@@ -2123,13 +2112,12 @@ schannel_send(struct Curl_easy *data, int sockindex,
}
static ssize_t
-schannel_recv(struct Curl_easy *data, int sockindex,
+schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
size_t size = 0;
ssize_t nread = -1;
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
unsigned char *reallocated_buffer;
size_t reallocated_length;
bool done = FALSE;
@@ -2205,19 +2193,19 @@ schannel_recv(struct Curl_easy *data, int sockindex,
backend->encdata_offset, backend->encdata_length));
/* read encrypted data from socket */
- *err = Curl_read_plain(conn->sock[sockindex],
- (char *)(backend->encdata_buffer +
+ nread = Curl_conn_cf_recv(cf->next, data,
+ (char *)(backend->encdata_buffer +
backend->encdata_offset),
- size, &nread);
+ size, err);
if(*err) {
nread = -1;
if(*err == CURLE_AGAIN)
DEBUGF(infof(data,
- "schannel: Curl_read_plain returned CURLE_AGAIN"));
+ "schannel: recv returned CURLE_AGAIN"));
else if(*err == CURLE_RECV_ERROR)
- infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR");
+ infof(data, "schannel: recv returned CURLE_RECV_ERROR");
else
- infof(data, "schannel: Curl_read_plain returned error %d", *err);
+ infof(data, "schannel: recv returned error %d", *err);
}
else if(nread == 0) {
backend->recv_connection_closed = true;
@@ -2338,7 +2326,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
connssl->state = ssl_connection_negotiating;
connssl->connecting_state = ssl_connect_2_writing;
backend->recv_renegotiating = true;
- *err = schannel_connect_common(data, conn, sockindex, FALSE, &done);
+ *err = schannel_connect_common(cf, data, FALSE, &done);
backend->recv_renegotiating = false;
if(*err) {
infof(data, "schannel: renegotiation failed");
@@ -2446,20 +2434,20 @@ schannel_recv(struct Curl_easy *data, int sockindex,
return *err ? -1 : 0;
}
-static CURLcode schannel_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return schannel_connect_common(data, conn, sockindex, TRUE, done);
+ return schannel_connect_common(cf, data, TRUE, done);
}
-static CURLcode schannel_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode schannel_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = schannel_connect_common(data, conn, sockindex, FALSE, &done);
+ result = schannel_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -2468,15 +2456,16 @@ static CURLcode schannel_connect(struct Curl_easy *data,
return CURLE_OK;
}
-static bool schannel_data_pending(const struct connectdata *conn,
- int sockindex)
+static bool schannel_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ const struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ (void)data;
DEBUGASSERT(backend);
- if(connssl->use) /* SSL/TLS is in use */
+ if(connssl->backend->ctxt) /* SSL/TLS is in use */
return (backend->decdata_offset > 0 ||
(backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
else
@@ -2507,25 +2496,24 @@ static void schannel_session_free(void *ptr)
/* shut down the SSL connection and clean up related memory.
this function can be called multiple times on the same connection including
if the SSL connection failed (eg connection made but failed handshake). */
-static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static int schannel_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
/* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
* Shutting Down an Schannel Connection
*/
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- char * const hostname = SSL_HOST_NAME();
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(data);
DEBUGASSERT(backend);
- if(connssl->use) {
- infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
- hostname, conn->remote_port);
+ if(connssl->backend->ctxt) {
+ infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
+ connssl->hostname, connssl->port);
}
- if(connssl->use && backend->cred && backend->ctxt) {
+ if(backend->cred && backend->ctxt) {
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_status;
@@ -2566,10 +2554,9 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
/* send close message which is in output buffer */
- ssize_t written;
- result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
- outbuf.cbBuffer, &written);
-
+ ssize_t written = Curl_conn_cf_send(cf->next, data,
+ outbuf.pvBuffer, outbuf.cbBuffer,
+ &result);
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
infof(data, "schannel: failed to send close msg: %s"
@@ -2611,14 +2598,9 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- if(conn->ssl[sockindex].use)
- /* Curl_ssl_shutdown resets the socket state and calls schannel_shutdown */
- Curl_ssl_shutdown(data, conn, sockindex);
- else
- schannel_shutdown(data, conn, sockindex);
+ schannel_shutdown(cf, data);
}
static int schannel_init(void)
@@ -2646,11 +2628,11 @@ static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
return Curl_win32_random(entropy, length);
}
-static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
+static CURLcode pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const char *pinnedpubkey)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
CERT_CONTEXT *pCertContextServer = NULL;
@@ -2791,7 +2773,8 @@ const struct Curl_ssl Curl_ssl_schannel = {
SSLSUPP_CAINFO_BLOB |
#endif
SSLSUPP_PINNEDPUBKEY |
- SSLSUPP_TLS13_CIPHERSUITES,
+ SSLSUPP_TLS13_CIPHERSUITES |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
@@ -2805,7 +2788,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
Curl_none_cert_status_request, /* cert_status_request */
schannel_connect, /* connect */
schannel_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
schannel_get_internals, /* get_internals */
schannel_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -2816,7 +2799,10 @@ const struct Curl_ssl Curl_ssl_schannel = {
Curl_none_false_start, /* false_start */
schannel_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ schannel_recv, /* recv decrypted data */
+ schannel_send, /* send data to encrypt */
};
#endif /* USE_SCHANNEL */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h
index 24d7eff25b..6d4235a96c 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.h
+++ b/Utilities/cmcurl/lib/vtls/schannel.h
@@ -54,6 +54,7 @@
#include <schannel.h>
#include "curl_sspi.h"
+#include "cfilters.h"
#include "urldata.h"
/* <wincrypt.h> has been included via the above <schnlsp.h>.
@@ -77,14 +78,12 @@
extern const struct Curl_ssl Curl_ssl_schannel;
-CURLcode Curl_verify_certificate(struct Curl_easy *data,
- struct connectdata *conn, int sockindex);
+CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
/* structs to expose only in schannel.c and schannel_verify.c */
#ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS
-#include <wincrypt.h>
-
#ifdef __MINGW32__
#ifdef __MINGW64_VERSION_MAJOR
#define HAS_MANUAL_VERIFY_API
diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
index 1ac1d3eaf5..e4992162e6 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_verify.c
+++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c
@@ -42,6 +42,7 @@
#ifdef HAS_MANUAL_VERIFY_API
#include "vtls.h"
+#include "vtls_int.h"
#include "sendf.h"
#include "strerror.h"
#include "curl_multibyte.h"
@@ -458,7 +459,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
static CURLcode verify_host(struct Curl_easy *data,
CERT_CONTEXT *pCertContextServer,
- const char * const conn_hostname)
+ const char *conn_hostname)
{
CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
TCHAR *cert_hostname_buff = NULL;
@@ -562,17 +563,18 @@ cleanup:
return result;
}
-CURLcode Curl_verify_certificate(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ 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);
SECURITY_STATUS sspi_status;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
CURLcode result = CURLE_OK;
CERT_CONTEXT *pCertContextServer = NULL;
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
HCERTCHAINENGINE cert_chain_engine = NULL;
HCERTSTORE trust_store = NULL;
- const char * const conn_hostname = SSL_HOST_NAME();
DEBUGASSERT(BACKEND);
@@ -589,7 +591,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
}
if(result == CURLE_OK &&
- (SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
+ (conn_config->CAfile || conn_config->ca_info_blob) &&
BACKEND->use_manual_cred_validation) {
/*
* Create a chain engine that uses the certificates in the CA file as
@@ -616,7 +618,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
result = CURLE_SSL_CACERT_BADFILE;
}
else {
- const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
if(ca_info_blob) {
result = add_certs_data_to_store(trust_store,
(const char *)ca_info_blob->data,
@@ -626,7 +628,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
}
else {
result = add_certs_file_to_store(trust_store,
- SSL_CONN_CONFIG(CAfile),
+ conn_config->CAfile,
data);
}
}
@@ -669,7 +671,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
NULL,
pCertContextServer->hCertStore,
&ChainPara,
- (SSL_SET_OPTION(no_revoke) ? 0 :
+ (ssl_config->no_revoke ? 0 :
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
NULL,
&pChainContext)) {
@@ -718,8 +720,8 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
}
if(result == CURLE_OK) {
- if(SSL_CONN_CONFIG(verifyhost)) {
- result = verify_host(data, pCertContextServer, conn_hostname);
+ if(conn_config->verifyhost) {
+ result = verify_host(data, pCertContextServer, connssl->hostname);
}
}
diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c
index c764e3631b..ab7965465f 100644
--- a/Utilities/cmcurl/lib/vtls/sectransp.c
+++ b/Utilities/cmcurl/lib/vtls/sectransp.c
@@ -122,12 +122,12 @@
#include <sys/sysctl.h>
#endif /* CURL_BUILD_MAC */
-#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
#include "connect.h"
#include "select.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "sectransp.h"
#include "curl_printf.h"
#include "strdup.h"
@@ -142,7 +142,6 @@
struct ssl_backend_data {
SSLContextRef ssl_ctx;
- curl_socket_t ssl_sockfd;
bool ssl_direction; /* true if writing, false if reading */
size_t ssl_write_buffered_length;
};
@@ -825,115 +824,62 @@ static const unsigned char ecDsaSecp384r1SpkiHeader[] = {
#endif /* SECTRANSP_PINNEDPUBKEY_V1 */
#endif /* SECTRANSP_PINNEDPUBKEY */
-/* The following two functions were ripped from Apple sample code,
- * with some modifications: */
-static OSStatus SocketRead(SSLConnectionRef connection,
- void *data, /* owned by
- * caller, data
- * RETURNED */
- size_t *dataLength) /* IN/OUT */
+static OSStatus bio_cf_in_read(SSLConnectionRef connection,
+ void *buf,
+ size_t *dataLength) /* IN/OUT */
{
- size_t bytesToGo = *dataLength;
- size_t initLen = bytesToGo;
- UInt8 *currData = (UInt8 *)data;
- /*int sock = *(int *)connection;*/
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- int sock;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result;
OSStatus rtn = noErr;
- size_t bytesRead;
- ssize_t rrtn;
- int theErr;
- DEBUGASSERT(backend);
- sock = backend->ssl_sockfd;
- *dataLength = 0;
-
- for(;;) {
- bytesRead = 0;
- rrtn = read(sock, currData, bytesToGo);
- if(rrtn <= 0) {
- /* this is guesswork... */
- theErr = errno;
- if(rrtn == 0) { /* EOF = server hung up */
- /* the framework will turn this into errSSLClosedNoNotify */
- rtn = errSSLClosedGraceful;
- }
- else /* do the switch */
- switch(theErr) {
- case ENOENT:
- /* connection closed */
- rtn = errSSLClosedGraceful;
- break;
- case ECONNRESET:
- rtn = errSSLClosedAbort;
- break;
- case EAGAIN:
- rtn = errSSLWouldBlock;
- backend->ssl_direction = false;
- break;
- default:
- rtn = ioErr;
- break;
- }
- break;
- }
- else {
- bytesRead = rrtn;
- }
- bytesToGo -= bytesRead;
- currData += bytesRead;
-
- if(bytesToGo == 0) {
- /* filled buffer with incoming data, done */
- break;
+ DEBUGASSERT(data);
+ nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result);
+ if(nread < 0) {
+ switch(result) {
+ case CURLE_OK:
+ case CURLE_AGAIN:
+ rtn = errSSLWouldBlock;
+ backend->ssl_direction = false;
+ break;
+ default:
+ rtn = ioErr;
+ break;
}
+ nread = 0;
}
- *dataLength = initLen - bytesToGo;
-
+ *dataLength = nread;
return rtn;
}
-static OSStatus SocketWrite(SSLConnectionRef connection,
- const void *data,
- size_t *dataLength) /* IN/OUT */
+static OSStatus bio_cf_out_write(SSLConnectionRef connection,
+ const void *buf,
+ size_t *dataLength) /* IN/OUT */
{
- size_t bytesSent = 0;
- /*int sock = *(int *)connection;*/
- struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+ struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- int sock;
- ssize_t length;
- size_t dataLen = *dataLength;
- const UInt8 *dataPtr = (UInt8 *)data;
- OSStatus ortn;
- int theErr;
-
- DEBUGASSERT(backend);
- sock = backend->ssl_sockfd;
- *dataLength = 0;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result;
+ OSStatus ortn = noErr;
- do {
- length = write(sock,
- (char *)dataPtr + bytesSent,
- dataLen - bytesSent);
- } while((length > 0) &&
- ( (bytesSent += length) < dataLen) );
-
- if(length <= 0) {
- theErr = errno;
- if(theErr == EAGAIN) {
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result);
+ if(nwritten <= 0) {
+ if(result == CURLE_AGAIN) {
ortn = errSSLWouldBlock;
backend->ssl_direction = true;
}
else {
ortn = ioErr;
}
+ nwritten = 0;
}
- else {
- ortn = noErr;
- }
- *dataLength = bytesSent;
+ *dataLength = nwritten;
return ortn;
}
@@ -1372,14 +1318,14 @@ static CURLcode sectransp_version_from_curl(SSLProtocol *darwinver,
}
#endif
-static CURLcode
-set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- long ssl_version = SSL_CONN_CONFIG(version);
- long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ 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;
long max_supported_version_by_os;
DEBUGASSERT(backend);
@@ -1665,23 +1611,21 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode sectransp_connect_step1(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- const struct curl_blob *ssl_cablob = SSL_CONN_CONFIG(ca_info_blob);
+ 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 struct curl_blob *ssl_cablob = conn_config->ca_info_blob;
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ssl_cablob ? NULL : SSL_CONN_CONFIG(CAfile));
- const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
- const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
- bool isproxy = SSL_IS_PROXY();
- const char * const hostname = SSL_HOST_NAME();
- const long int port = SSL_HOST_PORT();
+ (ssl_cablob ? NULL : conn_config->CAfile);
+ const bool verifypeer = conn_config->verifypeer;
+ char * const ssl_cert = ssl_config->primary.clientcert;
+ const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
+ bool isproxy = Curl_ssl_cf_is_proxy(cf);
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@@ -1733,7 +1677,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
/* check to see if we've been told to use an explicit SSL/TLS version */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLSetProtocolVersionMax) {
- switch(conn->ssl_config.version) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1);
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
@@ -1754,7 +1698,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
{
- CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
+ CURLcode result = set_ssl_version_min_max(cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -1773,7 +1717,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
(void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
kSSLProtocolAll,
false);
- switch(conn->ssl_config.version) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
@@ -1791,7 +1735,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
{
- CURLcode result = set_ssl_version_min_max(data, conn, sockindex);
+ CURLcode result = set_ssl_version_min_max(cf, data);
if(result != CURLE_OK)
return result;
break;
@@ -1807,13 +1751,13 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#endif /* CURL_SUPPORT_MAC_10_8 */
}
#else
- if(conn->ssl_config.version_max != CURL_SSLVERSION_MAX_NONE) {
+ if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
failf(data, "Your version of the OS does not support to set maximum"
" SSL/TLS version");
return CURLE_SSL_CONNECT_ERROR;
}
(void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false);
- switch(conn->ssl_config.version) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
@@ -1841,7 +1785,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0,
&kCFTypeArrayCallBacks);
@@ -1849,7 +1793,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#ifdef USE_HTTP2
if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
- && (!isproxy || !conn->bits.tunnel_proxy)
+ && (!isproxy || !cf->conn->bits.tunnel_proxy)
#endif
) {
CFArrayAppendValue(alpnArr, CFSTR(ALPN_H2));
@@ -1872,7 +1816,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
}
#endif
- if(SSL_SET_OPTION(key)) {
+ if(ssl_config->key) {
infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
"Transport. The private key must be in the Keychain.");
}
@@ -1891,17 +1835,17 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
else
err = !noErr;
if((err != noErr) && (is_cert_file || is_cert_data)) {
- if(!SSL_SET_OPTION(cert_type))
+ if(!ssl_config->cert_type)
infof(data, "SSL: Certificate type not set, assuming "
"PKCS#12 format.");
- else if(!strcasecompare(SSL_SET_OPTION(cert_type), "P12")) {
+ else if(!strcasecompare(ssl_config->cert_type, "P12")) {
failf(data, "SSL: The Security framework only supports "
"loading identities that are in PKCS#12 format.");
return CURLE_SSL_CERTPROBLEM;
}
err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob,
- SSL_SET_OPTION(key_passwd),
+ ssl_config->key_passwd,
&cert_and_key);
}
@@ -1994,7 +1938,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#else
if(SSLSetSessionOption) {
#endif /* CURL_BUILD_MAC */
- bool break_on_auth = !conn->ssl_config.verifypeer ||
+ bool break_on_auth = !conn_config->verifypeer ||
ssl_cafile || ssl_cablob;
err = SSLSetSessionOption(backend->ssl_ctx,
kSSLSessionOptionBreakOnServerAuth,
@@ -2007,7 +1951,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
else {
#if CURL_SUPPORT_MAC_10_8
err = SSLSetEnableCertVerify(backend->ssl_ctx,
- conn->ssl_config.verifypeer?true:false);
+ conn_config->verifypeer?true:false);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -2016,7 +1960,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
}
#else
err = SSLSetEnableCertVerify(backend->ssl_ctx,
- conn->ssl_config.verifypeer?true:false);
+ conn_config->verifypeer?true:false);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -2037,9 +1981,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
/* Configure hostname check. SNI is used if available.
* Both hostname check and SNI require SSLSetPeerDomainName().
* Also: the verifyhost setting influences SNI usage */
- if(conn->ssl_config.verifyhost) {
+ if(conn_config->verifyhost) {
size_t snilen;
- char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
+ char *snihost = Curl_ssl_snihost(data, connssl->hostname, &snilen);
if(!snihost) {
failf(data, "Failed to set SNI");
return CURLE_SSL_CONNECT_ERROR;
@@ -2052,9 +1996,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- if((Curl_inet_pton(AF_INET, hostname, &addr))
+ if((Curl_inet_pton(AF_INET, connssl->hostname, &addr))
#ifdef ENABLE_IPV6
- || (Curl_inet_pton(AF_INET6, hostname, &addr))
+ || (Curl_inet_pton(AF_INET6, connssl->hostname, &addr))
#endif
) {
infof(data, "WARNING: using IP address, SNI is being disabled by "
@@ -2065,7 +2009,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
infof(data, "WARNING: disabling hostname validation also disables SNI.");
}
- ciphers = SSL_CONN_CONFIG(cipher_list);
+ ciphers = conn_config->cipher_list;
if(ciphers) {
err = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
}
@@ -2083,20 +2027,20 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
specifically doesn't want us doing that: */
if(SSLSetSessionOption) {
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
- !SSL_SET_OPTION(enable_beast));
+ !ssl_config->enable_beast);
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
- data->set.ssl.falsestart); /* false start support */
+ ssl_config->falsestart); /* false start support */
}
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
/* Check if there's a cached ID we can/should use here! */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
char *ssl_sessionid;
size_t ssl_sessionid_len;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, isproxy, (void **)&ssl_sessionid,
- &ssl_sessionid_len, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, (void **)&ssl_sessionid,
+ &ssl_sessionid_len)) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(data);
@@ -2112,9 +2056,10 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
else {
CURLcode result;
ssl_sessionid =
- aprintf("%s:%d:%d:%s:%ld",
+ aprintf("%s:%d:%d:%s:%d",
ssl_cafile ? ssl_cafile : "(blob memory)",
- verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port);
+ verifypeer, conn_config->verifyhost, connssl->hostname,
+ connssl->port);
ssl_sessionid_len = strlen(ssl_sessionid);
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
@@ -2124,8 +2069,8 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- result = Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
- ssl_sessionid_len, sockindex, NULL);
+ result = Curl_ssl_addsessionid(cf, data, ssl_sessionid,
+ ssl_sessionid_len, NULL);
Curl_ssl_sessionid_unlock(data);
if(result) {
failf(data, "failed to store ssl session");
@@ -2134,18 +2079,13 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
}
}
- err = SSLSetIOFuncs(backend->ssl_ctx, SocketRead, SocketWrite);
+ err = SSLSetIOFuncs(backend->ssl_ctx, bio_cf_in_read, bio_cf_out_write);
if(err != noErr) {
failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
}
- /* pass the raw socket into the SSL layers */
- /* We need to store the FD in a constant memory address, because
- * SSLSetConnection() will not copy that address. I've found that
- * conn->sock[sockindex] may change on its own. */
- backend->ssl_sockfd = sockfd;
- err = SSLSetConnection(backend->ssl_ctx, connssl);
+ err = SSLSetConnection(backend->ssl_ctx, cf);
if(err != noErr) {
failf(data, "SSL: SSLSetConnection() failed: %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -2544,16 +2484,15 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
}
#endif /* SECTRANSP_PINNEDPUBKEY */
-static CURLcode
-sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ 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);
OSStatus err;
SSLCipherSuite cipher;
SSLProtocol protocol = 0;
- const char * const hostname = SSL_HOST_NAME();
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state
@@ -2573,16 +2512,16 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* The below is errSSLServerAuthCompleted; it's not defined in
Leopard's headers */
case -9841:
- if((SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
- SSL_CONN_CONFIG(verifypeer)) {
- CURLcode result = verify_cert(data, SSL_CONN_CONFIG(CAfile),
- SSL_CONN_CONFIG(ca_info_blob),
+ if((conn_config->CAfile || conn_config->ca_info_blob) &&
+ conn_config->verifypeer) {
+ CURLcode result = verify_cert(data, conn_config->CAfile,
+ conn_config->ca_info_blob,
backend->ssl_ctx);
if(result)
return result;
}
/* the documentation says we need to call SSLHandshake() again */
- return sectransp_connect_step2(data, conn, sockindex);
+ return sectransp_connect_step2(cf, data);
/* Problem with encrypt / decrypt */
case errSSLPeerDecodeError:
@@ -2684,7 +2623,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
host name: */
case errSSLHostNameMismatch:
failf(data, "SSL certificate peer verification failed, the "
- "certificate did not match \"%s\"\n", conn->host.dispname);
+ "certificate did not match \"%s\"\n", connssl->dispname);
return CURLE_PEER_FAILED_VERIFICATION;
/* Problem with SSL / TLS negotiation */
@@ -2776,7 +2715,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
default:
/* May also return codes listed in Security Framework Result Codes */
failf(data, "Unknown SSL protocol error in connection to %s:%d",
- hostname, err);
+ connssl->hostname, err);
break;
}
return CURLE_SSL_CONNECT_ERROR;
@@ -2835,7 +2774,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
#if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
CFArrayRef alpnArr = NULL;
CFStringRef chosenProtocol = NULL;
@@ -2847,18 +2786,18 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
#ifdef USE_HTTP2
if(chosenProtocol &&
!CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) {
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
}
else
#endif
if(chosenProtocol &&
!CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) {
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
}
else
infof(data, VTLS_INFOF_NO_ALPN);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
/* chosenProtocol is a reference to the string within alpnArr
@@ -2894,11 +2833,12 @@ add_cert_to_certinfo(struct Curl_easy *data,
}
static CURLcode
-collect_server_cert_single(struct Curl_easy *data,
+collect_server_cert_single(struct Curl_cfilter *cf, struct Curl_easy *data,
SecCertificateRef server_cert,
CFIndex idx)
{
CURLcode result = CURLE_OK;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(data->set.verbose) {
char *certp;
@@ -2909,25 +2849,24 @@ collect_server_cert_single(struct Curl_easy *data,
}
}
#endif
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = add_cert_to_certinfo(data, server_cert, (int)idx);
return result;
}
/* This should be called during step3 of the connection at the earliest */
-static CURLcode
-collect_server_cert(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+static CURLcode collect_server_cert(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
#ifndef CURL_DISABLE_VERBOSE_STRINGS
const bool show_verbose_server_cert = data->set.verbose;
#else
const bool show_verbose_server_cert = false;
#endif
- CURLcode result = data->set.ssl.certinfo ?
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ CURLcode result = ssl_config->certinfo ?
CURLE_PEER_FAILED_VERIFICATION : CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
CFArrayRef server_certs = NULL;
SecCertificateRef server_cert;
@@ -2937,7 +2876,7 @@ collect_server_cert(struct Curl_easy *data,
DEBUGASSERT(backend);
- if(!show_verbose_server_cert && !data->set.ssl.certinfo)
+ if(!show_verbose_server_cert && !ssl_config->certinfo)
return CURLE_OK;
if(!backend->ssl_ctx)
@@ -2951,11 +2890,11 @@ collect_server_cert(struct Curl_easy *data,
a null trust, so be on guard for that: */
if(err == noErr && trust) {
count = SecTrustGetCertificateCount(trust);
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
server_cert = SecTrustGetCertificateAtIndex(trust, i);
- result = collect_server_cert_single(data, server_cert, i);
+ result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(trust);
}
@@ -2973,11 +2912,11 @@ collect_server_cert(struct Curl_easy *data,
a null trust, so be on guard for that: */
if(err == noErr && trust) {
count = SecTrustGetCertificateCount(trust);
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
server_cert = SecTrustGetCertificateAtIndex(trust, i);
- result = collect_server_cert_single(data, server_cert, i);
+ result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(trust);
}
@@ -2988,12 +2927,12 @@ collect_server_cert(struct Curl_easy *data,
/* Just in case SSLCopyPeerCertificates() returns null too... */
if(err == noErr && server_certs) {
count = CFArrayGetCount(server_certs);
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
i);
- result = collect_server_cert_single(data, server_cert, i);
+ result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(server_certs);
}
@@ -3005,11 +2944,11 @@ collect_server_cert(struct Curl_easy *data,
err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs);
if(err == noErr) {
count = CFArrayGetCount(server_certs);
- if(data->set.ssl.certinfo)
+ if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
- result = collect_server_cert_single(data, server_cert, i);
+ result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(server_certs);
}
@@ -3017,16 +2956,15 @@ collect_server_cert(struct Curl_easy *data,
return result;
}
-static CURLcode
-sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
/* There is no step 3!
* Well, okay, let's collect server certificates, and if verbose mode is on,
* let's print the details of the server certificates. */
- const CURLcode result = collect_server_cert(data, conn, sockindex);
+ const CURLcode result = collect_server_cert(cf, data);
if(result)
return result;
@@ -3034,19 +2972,14 @@ sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OK;
}
-static Curl_recv sectransp_recv;
-static Curl_send sectransp_send;
-
static CURLcode
-sectransp_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
+sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
bool nonblocking,
bool *done)
{
CURLcode result;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
int what;
/* check if the connection has already been established */
@@ -3065,7 +2998,7 @@ sectransp_connect_common(struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- result = sectransp_connect_step1(data, conn, sockindex);
+ result = sectransp_connect_step1(cf, data);
if(result)
return result;
}
@@ -3119,7 +3052,7 @@ sectransp_connect_common(struct Curl_easy *data,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
- result = sectransp_connect_step2(data, conn, sockindex);
+ result = sectransp_connect_step2(cf, data);
if(result || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -3130,15 +3063,13 @@ sectransp_connect_common(struct Curl_easy *data,
if(ssl_connect_3 == connssl->connecting_state) {
- result = sectransp_connect_step3(data, conn, sockindex);
+ result = sectransp_connect_step3(cf, data);
if(result)
return result;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = sectransp_recv;
- conn->send[sockindex] = sectransp_send;
*done = TRUE;
}
else
@@ -3150,20 +3081,20 @@ sectransp_connect_common(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode sectransp_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode sectransp_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return sectransp_connect_common(data, conn, sockindex, TRUE, done);
+ return sectransp_connect_common(cf, data, TRUE, done);
}
-static CURLcode sectransp_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode sectransp_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = sectransp_connect_common(data, conn, sockindex, FALSE, &done);
+ result = sectransp_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -3173,10 +3104,9 @@ static CURLcode sectransp_connect(struct Curl_easy *data,
return CURLE_OK;
}
-static void sectransp_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
(void) data;
@@ -3197,19 +3127,19 @@ static void sectransp_close(struct Curl_easy *data, struct connectdata *conn,
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
backend->ssl_ctx = NULL;
}
- backend->ssl_sockfd = 0;
}
-static int sectransp_shutdown(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static int sectransp_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
ssize_t nread;
int what;
int rc;
char buf[120];
int loop = 10; /* avoid getting stuck */
+ CURLcode result;
DEBUGASSERT(backend);
@@ -3221,11 +3151,11 @@ static int sectransp_shutdown(struct Curl_easy *data,
return 0;
#endif
- sectransp_close(data, conn, sockindex);
+ sectransp_close(cf, data);
rc = 0;
- what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT);
+ what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], SSL_SHUTDOWN_TIMEOUT);
while(loop--) {
if(what < 0) {
@@ -3243,19 +3173,17 @@ static int sectransp_shutdown(struct Curl_easy *data,
/* Something to read, let's do it and hope that it is the close
notify alert from the server. No way to SSL_Read now, so use read(). */
- nread = read(conn->sock[sockindex], buf, sizeof(buf));
+ nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
if(nread < 0) {
- char buffer[STRERROR_LEN];
- failf(data, "read: %s",
- Curl_strerror(errno, buffer, sizeof(buffer)));
+ failf(data, "read: %s", curl_easy_strerror(result));
rc = -1;
}
if(nread <= 0)
break;
- what = SOCKET_READABLE(conn->sock[sockindex], 0);
+ what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], 0);
}
return rc;
@@ -3285,13 +3213,15 @@ static size_t sectransp_version(char *buffer, size_t size)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-static int sectransp_check_cxn(struct connectdata *conn)
+static int sectransp_check_cxn(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
OSStatus err;
SSLSessionState state;
+ (void)data;
DEBUGASSERT(backend);
if(backend->ssl_ctx) {
@@ -3303,14 +3233,15 @@ static int sectransp_check_cxn(struct connectdata *conn)
return 0;
}
-static bool sectransp_data_pending(const struct connectdata *conn,
- int connindex)
+static bool sectransp_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
+ const struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
OSStatus err;
size_t buffer;
+ (void)data;
DEBUGASSERT(backend);
if(backend->ssl_ctx) { /* SSL is in use */
@@ -3362,14 +3293,13 @@ static bool sectransp_false_start(void)
return FALSE;
}
-static ssize_t sectransp_send(struct Curl_easy *data,
- int sockindex,
+static ssize_t sectransp_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const void *mem,
size_t len,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
size_t processed = 0UL;
OSStatus err;
@@ -3431,15 +3361,15 @@ static ssize_t sectransp_send(struct Curl_easy *data,
return (ssize_t)processed;
}
-static ssize_t sectransp_recv(struct Curl_easy *data,
- int num,
+static ssize_t sectransp_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
char *buf,
size_t buffersize,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ 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);
size_t processed = 0UL;
OSStatus err;
@@ -3470,10 +3400,10 @@ static ssize_t sectransp_recv(struct Curl_easy *data,
/* The below is errSSLPeerAuthCompleted; it's not defined in
Leopard's headers */
case -9841:
- if((SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
- SSL_CONN_CONFIG(verifypeer)) {
- CURLcode result = verify_cert(data, SSL_CONN_CONFIG(CAfile),
- SSL_CONN_CONFIG(ca_info_blob),
+ if((conn_config->CAfile || conn_config->ca_info_blob) &&
+ conn_config->verifypeer) {
+ CURLcode result = verify_cert(data, conn_config->CAfile,
+ conn_config->ca_info_blob,
backend->ssl_ctx);
if(result)
return result;
@@ -3504,10 +3434,9 @@ const struct Curl_ssl Curl_ssl_sectransp = {
SSLSUPP_CAINFO_BLOB |
SSLSUPP_CERTINFO |
#ifdef SECTRANSP_PINNEDPUBKEY
- SSLSUPP_PINNEDPUBKEY,
-#else
- 0,
+ SSLSUPP_PINNEDPUBKEY |
#endif /* SECTRANSP_PINNEDPUBKEY */
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct ssl_backend_data),
@@ -3521,7 +3450,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
Curl_none_cert_status_request, /* cert_status_request */
sectransp_connect, /* connect */
sectransp_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
sectransp_get_internals, /* get_internals */
sectransp_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -3532,7 +3461,10 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_false_start, /* false_start */
sectransp_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ sectransp_recv, /* recv decrypted data */
+ sectransp_send, /* send data to encrypt */
};
#ifdef __clang__
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index 9dee5aa3b3..873ee6bac7 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -51,8 +51,10 @@
#endif
#include "urldata.h"
+#include "cfilters.h"
#include "vtls.h" /* generic SSL protos etc */
+#include "vtls_int.h"
#include "slist.h"
#include "sendf.h"
#include "strcase.h"
@@ -150,11 +152,11 @@ Curl_ssl_config_matches(struct ssl_primary_config *data,
!Curl_timestrcmp(data->password, needle->password) &&
(data->authtype == needle->authtype) &&
#endif
- Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) &&
- Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) &&
- Curl_safe_strcasecompare(data->curves, needle->curves) &&
- Curl_safe_strcasecompare(data->CRLfile, needle->CRLfile) &&
- Curl_safe_strcasecompare(data->pinned_key, needle->pinned_key))
+ strcasecompare(data->cipher_list, needle->cipher_list) &&
+ strcasecompare(data->cipher_list13, needle->cipher_list13) &&
+ strcasecompare(data->curves, needle->curves) &&
+ strcasecompare(data->CRLfile, needle->CRLfile) &&
+ strcasecompare(data->pinned_key, needle->pinned_key))
return TRUE;
return FALSE;
@@ -291,89 +293,68 @@ static bool ssl_prefs_check(struct Curl_easy *data)
return TRUE;
}
-#ifndef CURL_DISABLE_PROXY
-static CURLcode
-ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
+static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data)
{
- DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
- if(ssl_connection_complete == conn->ssl[sockindex].state &&
- !conn->proxy_ssl[sockindex].use) {
- struct ssl_backend_data *pbdata;
-
- if(!(Curl_ssl->supports & SSLSUPP_HTTPS_PROXY))
- return CURLE_NOT_BUILT_IN;
-
- /* The pointers to the ssl backend data, which is opaque here, are swapped
- rather than move the contents. */
- pbdata = conn->proxy_ssl[sockindex].backend;
- conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
+ struct ssl_connect_data *ctx;
- DEBUGASSERT(pbdata != NULL);
+ (void)data;
+ ctx = calloc(1, sizeof(*ctx));
+ if(!ctx)
+ return NULL;
- memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
- memset(pbdata, 0, Curl_ssl->sizeof_ssl_backend_data);
+ ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data);
+ if(!ctx->backend) {
+ free(ctx);
+ return NULL;
+ }
+ return ctx;
+}
- conn->ssl[sockindex].backend = pbdata;
+static void cf_ctx_free(struct ssl_connect_data *ctx)
+{
+ if(ctx) {
+ free(ctx->backend);
+ free(ctx);
}
- return CURLE_OK;
}
-#endif
-CURLcode
-Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void cf_ctx_set_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- CURLcode result;
+ if(cf->ctx)
+ ((struct ssl_connect_data *)cf->ctx)->call_data = data;
+}
-#ifndef CURL_DISABLE_PROXY
- if(conn->bits.proxy_ssl_connected[sockindex]) {
- result = ssl_connect_init_proxy(conn, sockindex);
- if(result)
- return result;
- }
-#endif
+static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result;
if(!ssl_prefs_check(data))
return CURLE_SSL_CONNECT_ERROR;
/* mark this is being ssl-enabled from here on. */
- conn->ssl[sockindex].use = TRUE;
- conn->ssl[sockindex].state = ssl_connection_negotiating;
+ connssl->state = ssl_connection_negotiating;
- result = Curl_ssl->connect_blocking(data, conn, sockindex);
+ result = Curl_ssl->connect_blocking(cf, data);
- if(!result)
+ if(!result) {
Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
- else
- conn->ssl[sockindex].use = FALSE;
+ DEBUGASSERT(connssl->state == ssl_connection_complete);
+ }
return result;
}
-CURLcode
-Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
- bool isproxy, int sockindex, bool *done)
+static CURLcode
+ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data,
+ bool *done)
{
- CURLcode result;
-
-#ifndef CURL_DISABLE_PROXY
- if(conn->bits.proxy_ssl_connected[sockindex]) {
- result = ssl_connect_init_proxy(conn, sockindex);
- if(result)
- return result;
- }
-#endif
if(!ssl_prefs_check(data))
return CURLE_SSL_CONNECT_ERROR;
/* mark this is being ssl requested from here on. */
- conn->ssl[sockindex].use = TRUE;
- result = Curl_ssl->connect_nonblocking(data, conn, sockindex, done);
- if(result)
- conn->ssl[sockindex].use = FALSE;
- else if(*done && !isproxy)
- Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
- return result;
+ return Curl_ssl->connect_nonblocking(cf, data, done);
}
/*
@@ -398,42 +379,26 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
* Check if there's a session ID for the given connection in the cache, and if
* there's one suitable, it is provided. Returns TRUE when no entry matched.
*/
-bool Curl_ssl_getsessionid(struct Curl_easy *data,
- struct connectdata *conn,
- const bool isProxy,
+bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
void **ssl_sessionid,
- size_t *idsize, /* set 0 if unknown */
- int sockindex)
+ size_t *idsize) /* set 0 if unknown */
{
+ 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);
struct Curl_ssl_session *check;
size_t i;
long *general_age;
bool no_match = TRUE;
-#ifndef CURL_DISABLE_PROXY
- struct ssl_primary_config * const ssl_config = isProxy ?
- &conn->proxy_ssl_config :
- &conn->ssl_config;
- const char * const name = isProxy ?
- conn->http_proxy.host.name : conn->host.name;
- int port = isProxy ? (int)conn->port : conn->remote_port;
-#else
- /* no proxy support */
- struct ssl_primary_config * const ssl_config = &conn->ssl_config;
- const char * const name = conn->host.name;
- int port = conn->remote_port;
-#endif
- (void)sockindex;
*ssl_sessionid = NULL;
-
-#ifdef CURL_DISABLE_PROXY
- if(isProxy)
+ if(!ssl_config)
return TRUE;
-#endif
- DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
+ DEBUGASSERT(ssl_config->primary.sessionid);
- if(!SSL_SET_OPTION(primary.sessionid) || !data->state.session)
+ if(!ssl_config->primary.sessionid || !data->state.session)
/* session ID re-use is disabled or the session cache has not been
setup */
return TRUE;
@@ -449,16 +414,16 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
if(!check->sessionid)
/* not session ID means blank entry */
continue;
- if(strcasecompare(name, check->name) &&
- ((!conn->bits.conn_to_host && !check->conn_to_host) ||
- (conn->bits.conn_to_host && check->conn_to_host &&
- strcasecompare(conn->conn_to_host.name, check->conn_to_host))) &&
- ((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
- (conn->bits.conn_to_port && check->conn_to_port != -1 &&
- conn->conn_to_port == check->conn_to_port)) &&
- (port == check->remote_port) &&
- strcasecompare(conn->handler->scheme, check->scheme) &&
- Curl_ssl_config_matches(ssl_config, &check->ssl_config)) {
+ if(strcasecompare(connssl->hostname, check->name) &&
+ ((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
+ (cf->conn->bits.conn_to_host && check->conn_to_host &&
+ strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
+ ((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) ||
+ (cf->conn->bits.conn_to_port && check->conn_to_port != -1 &&
+ cf->conn->conn_to_port == check->conn_to_port)) &&
+ (connssl->port == check->remote_port) &&
+ strcasecompare(cf->conn->handler->scheme, check->scheme) &&
+ Curl_ssl_config_matches(conn_config, &check->ssl_config)) {
/* yes, we have a session ID! */
(*general_age)++; /* increase general age */
check->age = *general_age; /* set this as used in this age */
@@ -470,10 +435,10 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
}
}
- DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
+ DEBUGF(infof(data, DMSG(data, "%s Session ID in cache for %s %s://%s:%d"),
no_match? "Didn't find": "Found",
- isProxy ? "proxy" : "host",
- conn->handler->scheme, name, port));
+ Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
+ cf->conn->handler->scheme, connssl->hostname, connssl->port));
return no_match;
}
@@ -521,14 +486,15 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
* layer. Curl_XXXX_session_free() will be called to free/kill the session ID
* later on.
*/
-CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
- struct connectdata *conn,
- const bool isProxy,
+CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
void *ssl_sessionid,
size_t idsize,
- int sockindex,
bool *added)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
size_t i;
struct Curl_ssl_session *store;
long oldest_age;
@@ -536,17 +502,6 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
char *clone_conn_to_host;
int conn_to_port;
long *general_age;
-#ifndef CURL_DISABLE_PROXY
- struct ssl_primary_config * const ssl_config = isProxy ?
- &conn->proxy_ssl_config :
- &conn->ssl_config;
- const char *hostname = isProxy ? conn->http_proxy.host.name :
- conn->host.name;
-#else
- struct ssl_primary_config * const ssl_config = &conn->ssl_config;
- const char *hostname = conn->host.name;
-#endif
- (void)sockindex;
if(added)
*added = FALSE;
@@ -556,14 +511,15 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
store = &data->state.session[0];
oldest_age = data->state.session[0].age; /* zero if unused */
- DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
+ (void)ssl_config;
+ DEBUGASSERT(ssl_config->primary.sessionid);
- clone_host = strdup(hostname);
+ clone_host = strdup(connssl->hostname);
if(!clone_host)
return CURLE_OUT_OF_MEMORY; /* bail out */
- if(conn->bits.conn_to_host) {
- clone_conn_to_host = strdup(conn->conn_to_host.name);
+ if(cf->conn->bits.conn_to_host) {
+ clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
if(!clone_conn_to_host) {
free(clone_host);
return CURLE_OUT_OF_MEMORY; /* bail out */
@@ -572,8 +528,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
else
clone_conn_to_host = NULL;
- if(conn->bits.conn_to_port)
- conn_to_port = conn->conn_to_port;
+ if(cf->conn->bits.conn_to_port)
+ conn_to_port = cf->conn->conn_to_port;
else
conn_to_port = -1;
@@ -613,10 +569,10 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
store->conn_to_port = conn_to_port; /* connect to port number */
/* port number */
- store->remote_port = isProxy ? (int)conn->port : conn->remote_port;
- store->scheme = conn->handler->scheme;
+ store->remote_port = connssl->port;
+ store->scheme = cf->conn->handler->scheme;
- if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) {
+ if(!Curl_clone_primary_ssl_config(conn_config, &store->ssl_config)) {
Curl_free_primary_ssl_config(&store->ssl_config);
store->sessionid = NULL; /* let caller free sessionid */
free(clone_host);
@@ -627,32 +583,16 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
if(added)
*added = TRUE;
- DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
- store->scheme, store->name, store->remote_port,
- isProxy ? "PROXY" : "server"));
+ DEBUGF(infof(data, DMSG(data, "Added Session ID to cache for %s://%s:%d"
+ " [%s]"), store->scheme, store->name, store->remote_port,
+ Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"));
return CURLE_OK;
}
-void Curl_ssl_associate_conn(struct Curl_easy *data,
- struct connectdata *conn)
+void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend)
{
- if(Curl_ssl->associate_connection) {
- Curl_ssl->associate_connection(data, conn, FIRSTSOCKET);
- if((conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) &&
- conn->bits.sock_accepted)
- Curl_ssl->associate_connection(data, conn, SECONDARYSOCKET);
- }
-}
-
-void Curl_ssl_detach_conn(struct Curl_easy *data,
- struct connectdata *conn)
-{
- if(Curl_ssl->disassociate_connection) {
- Curl_ssl->disassociate_connection(data, FIRSTSOCKET);
- if((conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) &&
- conn->bits.sock_accepted)
- Curl_ssl->disassociate_connection(data, SECONDARYSOCKET);
- }
+ if(Curl_ssl->free_multi_ssl_backend_data && mbackend)
+ Curl_ssl->free_multi_ssl_backend_data(mbackend);
}
void Curl_ssl_close_all(struct Curl_easy *data)
@@ -671,47 +611,26 @@ void Curl_ssl_close_all(struct Curl_easy *data)
Curl_ssl->close_all(data);
}
-int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks)
+int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
+ curl_socket_t *socks)
{
- struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+ struct ssl_connect_data *connssl = cf->ctx;
+ (void)data;
if(connssl->connecting_state == ssl_connect_2_writing) {
/* write mode */
- socks[0] = conn->sock[FIRSTSOCKET];
+ socks[0] = cf->conn->sock[FIRSTSOCKET];
return GETSOCK_WRITESOCK(0);
}
if(connssl->connecting_state == ssl_connect_2_reading) {
/* read mode */
- socks[0] = conn->sock[FIRSTSOCKET];
+ socks[0] = cf->conn->sock[FIRSTSOCKET];
return GETSOCK_READSOCK(0);
}
return GETSOCK_BLANK;
}
-void Curl_ssl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
- Curl_ssl->close_one(data, conn, sockindex);
- conn->ssl[sockindex].state = ssl_connection_none;
-}
-
-CURLcode Curl_ssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- if(Curl_ssl->shut_down(data, conn, sockindex))
- return CURLE_SSL_SHUTDOWN_FAILED;
-
- conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
- conn->ssl[sockindex].state = ssl_connection_none;
-
- conn->recv[sockindex] = Curl_recv_plain;
- conn->send[sockindex] = Curl_send_plain;
-
- return CURLE_OK;
-}
-
/* Selects an SSL crypto engine
*/
CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
@@ -774,15 +693,10 @@ void Curl_ssl_version(char *buffer, size_t size)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-int Curl_ssl_check_cxn(struct connectdata *conn)
+int Curl_ssl_check_cxn(struct Curl_easy *data, struct connectdata *conn)
{
- return Curl_ssl->check_cxn(conn);
-}
-
-bool Curl_ssl_data_pending(const struct connectdata *conn,
- int connindex)
-{
- return Curl_ssl->data_pending(conn, connindex);
+ struct Curl_cfilter *cf = Curl_ssl_cf_get_ssl(conn->cfilter[FIRSTSOCKET]);
+ return cf? Curl_ssl->check_cxn(cf, data) : -1;
}
void Curl_ssl_free_certinfo(struct Curl_easy *data)
@@ -1138,20 +1052,13 @@ bool Curl_ssl_cert_status_request(void)
/*
* Check whether the SSL backend supports false start.
*/
-bool Curl_ssl_false_start(void)
+bool Curl_ssl_false_start(struct Curl_easy *data)
{
+ (void)data;
return Curl_ssl->false_start();
}
/*
- * Check whether the SSL backend supports setting TLS 1.3 cipher suites
- */
-bool Curl_ssl_tls13_ciphersuites(void)
-{
- return Curl_ssl->supports & SSLSUPP_TLS13_CIPHERSUITES;
-}
-
-/*
* Default implementations for unsupported functions.
*/
@@ -1163,19 +1070,18 @@ int Curl_none_init(void)
void Curl_none_cleanup(void)
{ }
-int Curl_none_shutdown(struct Curl_easy *data UNUSED_PARAM,
- struct connectdata *conn UNUSED_PARAM,
- int sockindex UNUSED_PARAM)
+int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
+ struct Curl_easy *data UNUSED_PARAM)
{
(void)data;
- (void)conn;
- (void)sockindex;
+ (void)cf;
return 0;
}
-int Curl_none_check_cxn(struct connectdata *conn UNUSED_PARAM)
+int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- (void)conn;
+ (void)cf;
+ (void)data;
return -1;
}
@@ -1199,11 +1105,11 @@ void Curl_none_session_free(void *ptr UNUSED_PARAM)
(void)ptr;
}
-bool Curl_none_data_pending(const struct connectdata *conn UNUSED_PARAM,
- int connindex UNUSED_PARAM)
+bool Curl_none_data_pending(struct Curl_cfilter *cf UNUSED_PARAM,
+ const struct Curl_easy *data UNUSED_PARAM)
{
- (void)conn;
- (void)connindex;
+ (void)cf;
+ (void)data;
return 0;
}
@@ -1244,28 +1150,30 @@ static int multissl_init(void)
return Curl_ssl->init();
}
-static CURLcode multissl_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode multissl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
if(multissl_setup(NULL))
return CURLE_FAILED_INIT;
- return Curl_ssl->connect_blocking(data, conn, sockindex);
+ return Curl_ssl->connect_blocking(cf, data);
}
-static CURLcode multissl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
if(multissl_setup(NULL))
return CURLE_FAILED_INIT;
- return Curl_ssl->connect_nonblocking(data, conn, sockindex, done);
+ return Curl_ssl->connect_nonblocking(cf, data, done);
}
-static int multissl_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int multissl_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks)
{
if(multissl_setup(NULL))
return 0;
- return Curl_ssl->getsock(conn, socks);
+ return Curl_ssl->get_select_socks(cf, data, socks);
}
static void *multissl_get_internals(struct ssl_connect_data *connssl,
@@ -1276,12 +1184,30 @@ static void *multissl_get_internals(struct ssl_connect_data *connssl,
return Curl_ssl->get_internals(connssl, info);
}
-static void multissl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
if(multissl_setup(NULL))
return;
- Curl_ssl->close_one(data, conn, sockindex);
+ Curl_ssl->close(cf, data);
+}
+
+static ssize_t multissl_recv_plain(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *buf, size_t len, CURLcode *code)
+{
+ if(multissl_setup(NULL))
+ return CURLE_FAILED_INIT;
+ return Curl_ssl->recv_plain(cf, data, buf, len, code);
+}
+
+static ssize_t multissl_send_plain(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const void *mem, size_t len,
+ CURLcode *code)
+{
+ if(multissl_setup(NULL))
+ return CURLE_FAILED_INIT;
+ return Curl_ssl->send_plain(cf, data, mem, len, code);
}
static const struct Curl_ssl Curl_ssl_multi = {
@@ -1299,7 +1225,7 @@ static const struct Curl_ssl Curl_ssl_multi = {
Curl_none_cert_status_request, /* cert_status_request */
multissl_connect, /* connect */
multissl_connect_nonblocking, /* connect_nonblocking */
- multissl_getsock, /* getsock */
+ multissl_get_select_socks, /* getsock */
multissl_get_internals, /* get_internals */
multissl_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1310,7 +1236,10 @@ static const struct Curl_ssl Curl_ssl_multi = {
Curl_none_false_start, /* false_start */
NULL, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ multissl_recv_plain, /* recv decrypted data */
+ multissl_send_plain, /* send data to encrypt */
};
const struct Curl_ssl *Curl_ssl =
@@ -1498,3 +1427,397 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
}
#endif /* !USE_SSL */
+
+#ifdef USE_SSL
+
+static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ /* TODO: close_one closes BOTH conn->ssl AND conn->proxy_ssl for this
+ * sockindex (if in use). Gladly, it is safe to call more than once. */
+ if(connssl) {
+ Curl_ssl->close(cf, data);
+ connssl->state = ssl_connection_none;
+ }
+ cf->connected = FALSE;
+}
+
+static void reinit_hostname(struct Curl_cfilter *cf)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+
+#ifndef CURL_DISABLE_PROXY
+ if(Curl_ssl_cf_is_proxy(cf)) {
+ /* TODO: there is not definition for a proxy setup on a secondary conn */
+ connssl->hostname = cf->conn->http_proxy.host.name;
+ connssl->dispname = cf->conn->http_proxy.host.dispname;
+ connssl->port = cf->conn->http_proxy.port;
+ }
+ else
+#endif
+ {
+ /* TODO: secondaryhostname is set to the IP address we connect to
+ * in the FTP handler, it is assumed that host verification uses the
+ * hostname from FIRSTSOCKET */
+ if(cf->sockindex == SECONDARYSOCKET && 0) {
+ connssl->hostname = cf->conn->secondaryhostname;
+ connssl->dispname = connssl->hostname;
+ connssl->port = cf->conn->secondary_port;
+ }
+ else {
+ connssl->hostname = cf->conn->host.name;
+ connssl->dispname = cf->conn->host.dispname;
+ connssl->port = cf->conn->remote_port;
+ }
+ }
+ DEBUGASSERT(connssl->hostname);
+}
+
+static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ cf_ctx_set_data(cf, data);
+ cf_close(cf, data);
+ cf_ctx_free(cf->ctx);
+ cf->ctx = NULL;
+}
+
+static void ssl_cf_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ cf_ctx_set_data(cf, data);
+ cf_close(cf, data);
+ cf->next->cft->close(cf->next, data);
+ cf_ctx_set_data(cf, NULL);
+}
+
+static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool blocking, bool *done)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result;
+
+ if(cf->connected) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ cf_ctx_set_data(cf, data);
+ (void)connssl;
+ DEBUGASSERT(data->conn);
+ DEBUGASSERT(data->conn == cf->conn);
+ DEBUGASSERT(connssl);
+ DEBUGASSERT(cf->conn->host.name);
+
+ result = cf->next->cft->connect(cf->next, data, blocking, done);
+ if(result || !*done)
+ goto out;
+
+ /* TODO: right now we do not fully control when hostname is set,
+ * assign it on each connect call. */
+ reinit_hostname(cf);
+ *done = FALSE;
+
+ if(blocking) {
+ result = ssl_connect(cf, data);
+ *done = (result == CURLE_OK);
+ }
+ else {
+ result = ssl_connect_nonblocking(cf, data, done);
+ }
+
+ if(!result && *done) {
+ cf->connected = TRUE;
+ if(cf->sockindex == FIRSTSOCKET && !Curl_ssl_cf_is_proxy(cf))
+ Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
+ DEBUGASSERT(connssl->state == ssl_connection_complete);
+ }
+out:
+ cf_ctx_set_data(cf, NULL);
+ return result;
+}
+
+static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
+{
+ bool result;
+
+ cf_ctx_set_data(cf, (struct Curl_easy *)data);
+ if(cf->ctx && Curl_ssl->data_pending(cf, data))
+ result = TRUE;
+ else
+ result = cf->next->cft->has_data_pending(cf->next, data);
+ cf_ctx_set_data(cf, NULL);
+ return result;
+}
+
+static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data, const void *buf, size_t len,
+ CURLcode *err)
+{
+ ssize_t nwritten;
+
+ *err = CURLE_OK;
+ cf_ctx_set_data(cf, data);
+ nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
+ cf_ctx_set_data(cf, NULL);
+ return nwritten;
+}
+
+static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data, char *buf, size_t len,
+ CURLcode *err)
+{
+ ssize_t nread;
+
+ *err = CURLE_OK;
+ cf_ctx_set_data(cf, data);
+ nread = Curl_ssl->recv_plain(cf, data, buf, len, err);
+ cf_ctx_set_data(cf, NULL);
+ return nread;
+}
+
+static int ssl_cf_get_select_socks(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ curl_socket_t *socks)
+{
+ int result;
+
+ cf_ctx_set_data(cf, data);
+ result = Curl_ssl->get_select_socks(cf, data, socks);
+ cf_ctx_set_data(cf, NULL);
+ return result;
+}
+
+static void ssl_cf_attach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ if(Curl_ssl->attach_data) {
+ cf_ctx_set_data(cf, data);
+ Curl_ssl->attach_data(cf, data);
+ cf_ctx_set_data(cf, NULL);
+ }
+}
+
+static void ssl_cf_detach_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ if(Curl_ssl->detach_data) {
+ cf_ctx_set_data(cf, data);
+ Curl_ssl->detach_data(cf, data);
+ cf_ctx_set_data(cf, NULL);
+ }
+}
+
+static const struct Curl_cftype cft_ssl = {
+ "SSL",
+ CF_TYPE_SSL,
+ ssl_cf_destroy,
+ Curl_cf_def_setup,
+ ssl_cf_connect,
+ ssl_cf_close,
+ Curl_cf_def_get_host,
+ ssl_cf_get_select_socks,
+ ssl_cf_data_pending,
+ ssl_cf_send,
+ ssl_cf_recv,
+ ssl_cf_attach_data,
+ ssl_cf_detach_data,
+};
+
+static const struct Curl_cftype cft_ssl_proxy = {
+ "SSL-PROXY",
+ CF_TYPE_SSL,
+ ssl_cf_destroy,
+ Curl_cf_def_setup,
+ ssl_cf_connect,
+ ssl_cf_close,
+ Curl_cf_def_get_host,
+ ssl_cf_get_select_socks,
+ ssl_cf_data_pending,
+ ssl_cf_send,
+ ssl_cf_recv,
+ ssl_cf_attach_data,
+ ssl_cf_detach_data,
+};
+
+CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_cfilter *cf;
+ struct ssl_connect_data *ctx;
+ CURLcode result;
+
+ DEBUGASSERT(data->conn);
+ ctx = cf_ctx_new(data);
+ if(!ctx) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ result = Curl_cf_create(&cf, &cft_ssl, ctx);
+ if(result)
+ goto out;
+
+ Curl_conn_cf_add(data, conn, sockindex, cf);
+
+ result = CURLE_OK;
+
+out:
+ if(result)
+ cf_ctx_free(ctx);
+ return result;
+}
+
+#ifndef CURL_DISABLE_PROXY
+CURLcode Curl_ssl_cfilter_proxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_cfilter *cf;
+ struct ssl_connect_data *ctx;
+ CURLcode result;
+
+ ctx = cf_ctx_new(data);
+ if(!ctx) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ result = Curl_cf_create(&cf, &cft_ssl_proxy, ctx);
+ if(result)
+ goto out;
+
+ Curl_conn_cf_add(data, conn, sockindex, cf);
+
+ result = CURLE_OK;
+
+out:
+ if(result)
+ cf_ctx_free(ctx);
+ return result;
+}
+
+#endif /* !CURL_DISABLE_PROXY */
+
+bool Curl_ssl_supports(struct Curl_easy *data, int option)
+{
+ (void)data;
+ return (Curl_ssl->supports & option)? TRUE : FALSE;
+}
+
+void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
+ CURLINFO info, int n)
+{
+ void *result = NULL;
+ (void)n;
+ if(data->conn) {
+ struct Curl_cfilter *cf;
+ /* get first filter in chain, if any is present */
+ cf = Curl_ssl_cf_get_ssl(data->conn->cfilter[sockindex]);
+ if(cf) {
+ cf_ctx_set_data(cf, data);
+ result = Curl_ssl->get_internals(cf->ctx, info);
+ cf_ctx_set_data(cf, NULL);
+ }
+ }
+ return result;
+}
+
+CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
+ int sockindex)
+{
+ struct Curl_cfilter *cf = data->conn? data->conn->cfilter[sockindex] : NULL;
+ CURLcode result = CURLE_OK;
+
+ (void)data;
+ for(; cf; cf = cf->next) {
+ if(cf->cft == &cft_ssl) {
+ if(Curl_ssl->shut_down(cf, data))
+ result = CURLE_SSL_SHUTDOWN_FAILED;
+ Curl_conn_cf_discard(cf, data);
+ break;
+ }
+ }
+ return result;
+}
+
+static struct Curl_cfilter *get_ssl_cf_engaged(struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_cfilter *cf, *lowest_ssl_cf = NULL;
+
+ for(cf = conn->cfilter[sockindex]; cf; cf = cf->next) {
+ if(cf->cft == &cft_ssl || cf->cft == &cft_ssl_proxy) {
+ lowest_ssl_cf = cf;
+ if(cf->connected || (cf->next && cf->next->connected)) {
+ /* connected or about to start */
+ return cf;
+ }
+ }
+ }
+ return lowest_ssl_cf;
+}
+
+bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
+{
+ return (cf->cft == &cft_ssl_proxy);
+}
+
+struct ssl_config_data *
+Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+#ifdef CURL_DISABLE_PROXY
+ (void)cf;
+ return &data->set.ssl;
+#else
+ return Curl_ssl_cf_is_proxy(cf)? &data->set.proxy_ssl : &data->set.ssl;
+#endif
+}
+
+struct ssl_config_data *
+Curl_ssl_get_config(struct Curl_easy *data, int sockindex)
+{
+ struct Curl_cfilter *cf;
+
+ (void)data;
+ DEBUGASSERT(data->conn);
+ cf = get_ssl_cf_engaged(data->conn, sockindex);
+ return cf? Curl_ssl_cf_get_config(cf, data) : &data->set.ssl;
+}
+
+struct ssl_primary_config *
+Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf)
+{
+#ifdef CURL_DISABLE_PROXY
+ return &cf->conn->ssl_config;
+#else
+ return Curl_ssl_cf_is_proxy(cf)?
+ &cf->conn->proxy_ssl_config : &cf->conn->ssl_config;
+#endif
+}
+
+struct ssl_primary_config *
+Curl_ssl_get_primary_config(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_cfilter *cf;
+
+ (void)data;
+ DEBUGASSERT(conn);
+ cf = get_ssl_cf_engaged(conn, sockindex);
+ return cf? Curl_ssl_cf_get_primary_config(cf) : NULL;
+}
+
+struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf)
+{
+ for(; cf; cf = cf->next) {
+ if(cf->cft == &cft_ssl || cf->cft == &cft_ssl_proxy)
+ return cf;
+ }
+ return NULL;
+}
+
+#endif /* USE_SSL */
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index 50c53b3fbd..5ad64fcf60 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -26,7 +26,10 @@
#include "curl_setup.h"
struct connectdata;
+struct ssl_config_data;
struct ssl_connect_data;
+struct ssl_primary_config;
+struct Curl_ssl_session;
#define SSLSUPP_CA_PATH (1<<0) /* supports CAPATH */
#define SSLSUPP_CERTINFO (1<<1) /* supports CURLOPT_CERTINFO */
@@ -47,98 +50,13 @@ struct ssl_connect_data;
#define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR \
ALPN_ACCEPTED "%.*s"
-struct Curl_ssl {
- /*
- * This *must* be the first entry to allow returning the list of available
- * backends in curl_global_sslset().
- */
- curl_ssl_backend info;
- unsigned int supports; /* bitfield, see above */
- size_t sizeof_ssl_backend_data;
-
- int (*init)(void);
- void (*cleanup)(void);
-
- size_t (*version)(char *buffer, size_t size);
- int (*check_cxn)(struct connectdata *cxn);
- int (*shut_down)(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
- bool (*data_pending)(const struct connectdata *conn,
- int connindex);
-
- /* return 0 if a find random is filled in */
- CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy,
- size_t length);
- bool (*cert_status_request)(void);
-
- CURLcode (*connect_blocking)(struct Curl_easy *data,
- struct connectdata *conn, int sockindex);
- CURLcode (*connect_nonblocking)(struct Curl_easy *data,
- struct connectdata *conn, int sockindex,
- bool *done);
-
- /* If the SSL backend wants to read or write on this connection during a
- handshake, set socks[0] to the connection's FIRSTSOCKET, and return
- a bitmap indicating read or write with GETSOCK_WRITESOCK(0) or
- GETSOCK_READSOCK(0). Otherwise return GETSOCK_BLANK.
- Mandatory. */
- int (*getsock)(struct connectdata *conn, curl_socket_t *socks);
-
- void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
- void (*close_one)(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
- void (*close_all)(struct Curl_easy *data);
- void (*session_free)(void *ptr);
-
- CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
- CURLcode (*set_engine_default)(struct Curl_easy *data);
- struct curl_slist *(*engines_list)(struct Curl_easy *data);
-
- bool (*false_start)(void);
- CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
- unsigned char *sha256sum, size_t sha256sumlen);
-
- bool (*associate_connection)(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex);
- void (*disassociate_connection)(struct Curl_easy *data, int sockindex);
-};
-
-#ifdef USE_SSL
-extern const struct Curl_ssl *Curl_ssl;
-#endif
-
-int Curl_none_init(void);
-void Curl_none_cleanup(void);
-int Curl_none_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
-int Curl_none_check_cxn(struct connectdata *conn);
-CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
- size_t length);
-void Curl_none_close_all(struct Curl_easy *data);
-void Curl_none_session_free(void *ptr);
-bool Curl_none_data_pending(const struct connectdata *conn, int connindex);
-bool Curl_none_cert_status_request(void);
-CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine);
-CURLcode Curl_none_set_engine_default(struct Curl_easy *data);
-struct curl_slist *Curl_none_engines_list(struct Curl_easy *data);
-bool Curl_none_false_start(void);
-bool Curl_ssl_tls13_ciphersuites(void);
+/* Curl_multi SSL backend-specific data; declared differently by each SSL
+ backend */
+struct multi_ssl_backend_data;
CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
const curl_ssl_backend ***avail);
-#include "openssl.h" /* OpenSSL versions */
-#include "gtls.h" /* GnuTLS versions */
-#include "nssg.h" /* NSS versions */
-#include "gskit.h" /* Global Secure ToolKit versions */
-#include "wolfssl.h" /* wolfSSL versions */
-#include "schannel.h" /* Schannel SSPI version */
-#include "sectransp.h" /* SecureTransport (Darwin) version */
-#include "mbedtls.h" /* mbedTLS versions */
-#include "bearssl.h" /* BearSSL versions */
-#include "rustls.h" /* rustls versions */
-
#ifndef MAX_PINNED_PUBKEY_SIZE
#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
#endif
@@ -153,40 +71,6 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
#define ALPN_H2_LENGTH 2
#define ALPN_H2 "h2"
-/* set of helper macros for the backends to access the correct fields. For the
- proxy or for the remote host - to properly support HTTPS proxy */
-#ifndef CURL_DISABLE_PROXY
-#define SSL_IS_PROXY() \
- (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \
- ssl_connection_complete != \
- conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \
- CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state)
-#define SSL_SET_OPTION(var) \
- (SSL_IS_PROXY() ? data->set.proxy_ssl.var : data->set.ssl.var)
-#define SSL_SET_OPTION_LVALUE(var) \
- (*(SSL_IS_PROXY() ? &data->set.proxy_ssl.var : &data->set.ssl.var))
-#define SSL_CONN_CONFIG(var) \
- (SSL_IS_PROXY() ? conn->proxy_ssl_config.var : conn->ssl_config.var)
-#define SSL_HOST_NAME() \
- (SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name)
-#define SSL_HOST_DISPNAME() \
- (SSL_IS_PROXY() ? conn->http_proxy.host.dispname : conn->host.dispname)
-#define SSL_HOST_PORT() \
- (SSL_IS_PROXY() ? conn->port : conn->remote_port)
-#define SSL_PINNED_PUB_KEY() (SSL_IS_PROXY() \
- ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] \
- : data->set.str[STRING_SSL_PINNEDPUBLICKEY])
-#else
-#define SSL_IS_PROXY() FALSE
-#define SSL_SET_OPTION(var) data->set.ssl.var
-#define SSL_SET_OPTION_LVALUE(var) data->set.ssl.var
-#define SSL_CONN_CONFIG(var) conn->ssl_config.var
-#define SSL_HOST_NAME() conn->host.name
-#define SSL_HOST_DISPNAME() conn->host.dispname
-#define SSL_HOST_PORT() conn->remote_port
-#define SSL_PINNED_PUB_KEY() \
- data->set.str[STRING_SSL_PINNEDPUBLICKEY]
-#endif
char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen);
bool Curl_ssl_config_matches(struct ssl_primary_config *data,
@@ -194,31 +78,15 @@ bool Curl_ssl_config_matches(struct ssl_primary_config *data,
bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
struct ssl_primary_config *dest);
void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc);
-/* An implementation of the getsock field of Curl_ssl that relies
- on the ssl_connect_state enum. Asks for read or write depending
- on whether conn->state is ssl_connect_2_reading or
- ssl_connect_2_writing. */
-int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks);
curl_sslbackend Curl_ssl_backend(void);
#ifdef USE_SSL
int Curl_ssl_init(void);
void Curl_ssl_cleanup(void);
-CURLcode Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
-CURLcode Curl_ssl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- bool isproxy,
- int sockindex,
- bool *done);
/* tell the SSL stuff to close down all open information regarding
connections (and thus session ID caching etc) */
void Curl_ssl_close_all(struct Curl_easy *data);
-void Curl_ssl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
-CURLcode Curl_ssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine);
/* Sets engine as default for all SSL operations */
CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data);
@@ -227,9 +95,7 @@ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data);
/* init the SSL session ID cache */
CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t);
void Curl_ssl_version(char *buffer, size_t size);
-bool Curl_ssl_data_pending(const struct connectdata *conn,
- int connindex);
-int Curl_ssl_check_cxn(struct connectdata *conn);
+int Curl_ssl_check_cxn(struct Curl_easy *data, struct connectdata *conn);
/* Certificate information list handling. */
@@ -255,30 +121,6 @@ void Curl_ssl_sessionid_lock(struct Curl_easy *data);
/* Unlock session cache mutex */
void Curl_ssl_sessionid_unlock(struct Curl_easy *data);
-/* extract a session ID
- * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
- * Caller must make sure that the ownership of returned sessionid object
- * is properly taken (e.g. its refcount is incremented
- * under sessionid mutex).
- */
-bool Curl_ssl_getsessionid(struct Curl_easy *data,
- struct connectdata *conn,
- const bool isProxy,
- void **ssl_sessionid,
- size_t *idsize, /* set 0 if unknown */
- int sockindex);
-/* add a new session ID
- * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
- * Caller must ensure that it has properly shared ownership of this sessionid
- * object with cache (e.g. incrementing refcount on success)
- */
-CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
- struct connectdata *conn,
- const bool isProxy,
- void *ssl_sessionid,
- size_t idsize,
- int sockindex,
- bool *added);
/* Kill a single session ID entry in the cache
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
* This will call engine-specific curlssl_session_free function, which must
@@ -304,41 +146,90 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
bool Curl_ssl_cert_status_request(void);
-bool Curl_ssl_false_start(void);
+bool Curl_ssl_false_start(struct Curl_easy *data);
-void Curl_ssl_associate_conn(struct Curl_easy *data,
- struct connectdata *conn);
-void Curl_ssl_detach_conn(struct Curl_easy *data,
- struct connectdata *conn);
+void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend);
#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
+CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+
+CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
+ int sockindex);
+
+#ifndef CURL_DISABLE_PROXY
+CURLcode Curl_ssl_cfilter_proxy_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+#endif /* !CURL_DISABLE_PROXY */
+
+/**
+ * Get the SSL configuration that is used on the connection.
+ * This returns NULL if no SSL is configured.
+ * Otherwise it returns the config of the first (highest) one that is
+ * either connected, in handshake or about to start
+ * (e.g. all filters below it are connected). If SSL filters are present,
+ * but neither can start operating, return the config of the lowest one
+ * that will first come into effect when connecting.
+ */
+struct ssl_config_data *Curl_ssl_get_config(struct Curl_easy *data,
+ int sockindex);
+
+/**
+ * Get the primary SSL configuration from the connection.
+ * This returns NULL if no SSL is configured.
+ * Otherwise it returns the config of the first (highest) one that is
+ * either connected, in handshake or about to start
+ * (e.g. all filters below it are connected). If SSL filters are present,
+ * but neither can start operating, return the config of the lowest one
+ * that will first come into effect when connecting.
+ */
+struct ssl_primary_config *
+Curl_ssl_get_primary_config(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+
+/**
+ * True iff the underlying SSL implementation supports the option.
+ * Option is one of the defined SSLSUPP_* values.
+ * `data` maybe NULL for the features of the default implementation.
+ */
+bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option);
+
+/**
+ * Get the internal ssl instance (like OpenSSL's SSL*) from the filter
+ * chain at `sockindex` of type specified by `info`.
+ * For `n` == 0, the first active (top down) instance is returned.
+ * 1 gives the second active, etc.
+ * NULL is returned when no active SSL filter is present.
+ */
+void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
+ CURLINFO info, int n);
+
#else /* if not USE_SSL */
/* When SSL support is not present, just define away these function calls */
#define Curl_ssl_init() 1
#define Curl_ssl_cleanup() Curl_nop_stmt
-#define Curl_ssl_connect(x,y,z) CURLE_NOT_BUILT_IN
#define Curl_ssl_close_all(x) Curl_nop_stmt
-#define Curl_ssl_close(x,y,z) Curl_nop_stmt
-#define Curl_ssl_shutdown(x,y,z) CURLE_NOT_BUILT_IN
#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN
#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN
#define Curl_ssl_engines_list(x) NULL
-#define Curl_ssl_send(a,b,c,d,e) -1
-#define Curl_ssl_recv(a,b,c,d,e) -1
#define Curl_ssl_initsessions(x,y) CURLE_OK
-#define Curl_ssl_data_pending(x,y) 0
-#define Curl_ssl_check_cxn(x) 0
+#define Curl_ssl_check_cxn(d,x) 0
#define Curl_ssl_free_certinfo(x) Curl_nop_stmt
-#define Curl_ssl_connect_nonblocking(x,y,z,w,a) CURLE_NOT_BUILT_IN
#define Curl_ssl_kill_session(x) Curl_nop_stmt
#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
#define Curl_ssl_cert_status_request() FALSE
-#define Curl_ssl_false_start() FALSE
-#define Curl_ssl_tls13_ciphersuites() FALSE
-#define Curl_ssl_associate_conn(a,b) Curl_nop_stmt
-#define Curl_ssl_detach_conn(a,b) Curl_nop_stmt
+#define Curl_ssl_false_start(a) FALSE
+#define Curl_ssl_get_internals(a,b,c,d) NULL
+#define Curl_ssl_supports(a,b) FALSE
+#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
+#define Curl_ssl_cfilter_proxy_add(a,b,c) CURLE_NOT_BUILT_IN
+#define Curl_ssl_get_config(a,b) NULL
+#define Curl_ssl_cfilter_remove(a,b) CURLE_OK
#endif
#endif /* HEADER_CURL_VTLS_H */
diff --git a/Utilities/cmcurl/lib/vtls/vtls_int.h b/Utilities/cmcurl/lib/vtls/vtls_int.h
new file mode 100644
index 0000000000..6710a2b559
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/vtls_int.h
@@ -0,0 +1,190 @@
+#ifndef HEADER_CURL_VTLS_INT_H
+#define HEADER_CURL_VTLS_INT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * 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
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+#include "cfilters.h"
+#include "urldata.h"
+
+#ifdef USE_SSL
+
+/* Information in each SSL cfilter context: cf->ctx */
+struct ssl_connect_data {
+ ssl_connection_state state;
+ ssl_connect_state connecting_state;
+ const char *hostname; /* hostnaem for verification */
+ const char *dispname; /* display version of hostname */
+ int port; /* remote port at origin */
+ struct ssl_backend_data *backend; /* vtls backend specific props */
+ struct Curl_easy *call_data; /* data handle used in current call,
+ * same as parameter passed, but available
+ * here for backend internal callbacks
+ * that need it. NULLed after at the
+ * end of each vtls filter invcocation. */
+};
+
+
+/* Definitions for SSL Implementations */
+
+struct Curl_ssl {
+ /*
+ * This *must* be the first entry to allow returning the list of available
+ * backends in curl_global_sslset().
+ */
+ curl_ssl_backend info;
+ unsigned int supports; /* bitfield, see above */
+ size_t sizeof_ssl_backend_data;
+
+ int (*init)(void);
+ void (*cleanup)(void);
+
+ size_t (*version)(char *buffer, size_t size);
+ int (*check_cxn)(struct Curl_cfilter *cf, struct Curl_easy *data);
+ int (*shut_down)(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+ bool (*data_pending)(struct Curl_cfilter *cf,
+ const struct Curl_easy *data);
+
+ /* return 0 if a find random is filled in */
+ CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy,
+ size_t length);
+ bool (*cert_status_request)(void);
+
+ CURLcode (*connect_blocking)(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+ CURLcode (*connect_nonblocking)(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done);
+
+ /* If the SSL backend wants to read or write on this connection during a
+ handshake, set socks[0] to the connection's FIRSTSOCKET, and return
+ a bitmap indicating read or write with GETSOCK_WRITESOCK(0) or
+ GETSOCK_READSOCK(0). Otherwise return GETSOCK_BLANK.
+ Mandatory. */
+ int (*get_select_socks)(struct Curl_cfilter *cf, struct Curl_easy *data,
+ curl_socket_t *socks);
+
+ void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
+ void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
+ void (*close_all)(struct Curl_easy *data);
+ void (*session_free)(void *ptr);
+
+ CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
+ CURLcode (*set_engine_default)(struct Curl_easy *data);
+ struct curl_slist *(*engines_list)(struct Curl_easy *data);
+
+ bool (*false_start)(void);
+ CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
+ unsigned char *sha256sum, size_t sha256sumlen);
+
+ bool (*attach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
+ void (*detach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
+
+ void (*free_multi_ssl_backend_data)(struct multi_ssl_backend_data *mbackend);
+
+ ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
+ char *buf, size_t len, CURLcode *code);
+ ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const void *mem, size_t len, CURLcode *code);
+
+};
+
+extern const struct Curl_ssl *Curl_ssl;
+
+
+int Curl_none_init(void);
+void Curl_none_cleanup(void);
+int Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data);
+int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data);
+CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
+ size_t length);
+void Curl_none_close_all(struct Curl_easy *data);
+void Curl_none_session_free(void *ptr);
+bool Curl_none_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data);
+bool Curl_none_cert_status_request(void);
+CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine);
+CURLcode Curl_none_set_engine_default(struct Curl_easy *data);
+struct curl_slist *Curl_none_engines_list(struct Curl_easy *data);
+bool Curl_none_false_start(void);
+int Curl_ssl_get_select_socks(struct Curl_cfilter *cf, struct Curl_easy *data,
+ curl_socket_t *socks);
+
+/**
+ * Get the ssl_config_data in `data` that is relevant for cfilter `cf`.
+ */
+struct ssl_config_data *Curl_ssl_cf_get_config(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
+
+/**
+ * Get the primary config relevant for the filter from its connection.
+ */
+struct ssl_primary_config *
+ Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf);
+
+/**
+ * Get the first SSL filter in the chain starting with `cf`, or NULL.
+ */
+struct Curl_cfilter *Curl_ssl_cf_get_ssl(struct Curl_cfilter *cf);
+
+/**
+ * Get the SSL filter below the given one or NULL if there is none.
+ */
+bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf);
+
+/* extract a session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must make sure that the ownership of returned sessionid object
+ * is properly taken (e.g. its refcount is incremented
+ * under sessionid mutex).
+ */
+bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void **ssl_sessionid,
+ size_t *idsize); /* set 0 if unknown */
+/* add a new session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must ensure that it has properly shared ownership of this sessionid
+ * object with cache (e.g. incrementing refcount on success)
+ */
+CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *ssl_sessionid,
+ size_t idsize,
+ bool *added);
+
+#include "openssl.h" /* OpenSSL versions */
+#include "gtls.h" /* GnuTLS versions */
+#include "nssg.h" /* NSS versions */
+#include "gskit.h" /* Global Secure ToolKit versions */
+#include "wolfssl.h" /* wolfSSL versions */
+#include "schannel.h" /* Schannel SSPI version */
+#include "sectransp.h" /* SecureTransport (Darwin) version */
+#include "mbedtls.h" /* mbedTLS versions */
+#include "bearssl.h" /* BearSSL versions */
+#include "rustls.h" /* rustls versions */
+
+#endif /* USE_SSL */
+
+#endif /* HEADER_CURL_VTLS_INT_H */
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c
index 594c39a324..7cc4774e83 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.c
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.c
@@ -55,6 +55,7 @@
#include "sendf.h"
#include "inet_pton.h"
#include "vtls.h"
+#include "vtls_int.h"
#include "keylog.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
@@ -84,14 +85,17 @@
#endif
#endif
+#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO
+#define USE_BIO_CHAIN
+#else
+#undef USE_BIO_CHAIN
+#endif
+
struct ssl_backend_data {
SSL_CTX* ctx;
SSL* handle;
};
-static Curl_recv wolfssl_recv;
-static Curl_send wolfssl_send;
-
#ifdef OPENSSL_EXTRA
/*
* Availability note:
@@ -241,19 +245,130 @@ static const struct group_name_map gnm[] = {
};
#endif
+#ifdef USE_BIO_CHAIN
+
+static int bio_cf_create(WOLFSSL_BIO *bio)
+{
+ wolfSSL_BIO_set_shutdown(bio, 1);
+ wolfSSL_BIO_set_init(bio, 1);
+ wolfSSL_BIO_set_data(bio, NULL);
+ return 1;
+}
+
+static int bio_cf_destroy(WOLFSSL_BIO *bio)
+{
+ if(!bio)
+ return 0;
+ return 1;
+}
+
+static long bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
+{
+ struct Curl_cfilter *cf = BIO_get_data(bio);
+ long ret = 1;
+
+ (void)cf;
+ (void)ptr;
+ switch(cmd) {
+ case BIO_CTRL_GET_CLOSE:
+ ret = (long)wolfSSL_BIO_get_shutdown(bio);
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ wolfSSL_BIO_set_shutdown(bio, (int)num);
+ break;
+ case BIO_CTRL_FLUSH:
+ /* we do no delayed writes, but if we ever would, this
+ * needs to trigger it. */
+ ret = 1;
+ break;
+ case BIO_CTRL_DUP:
+ ret = 1;
+ break;
+#ifdef BIO_CTRL_EOF
+ case BIO_CTRL_EOF:
+ /* EOF has been reached on input? */
+ return (!cf->next || !cf->next->connected);
+#endif
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen)
+{
+ struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nwritten;
+ CURLcode result = CURLE_OK;
+
+ DEBUGASSERT(data);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ wolfSSL_BIO_clear_retry_flags(bio);
+ if(nwritten < 0 && CURLE_AGAIN == result)
+ BIO_set_retry_read(bio);
+ return (int)nwritten;
+}
+
+static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
+{
+ struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct Curl_easy *data = connssl->call_data;
+ ssize_t nread;
+ CURLcode result = CURLE_OK;
+
+ DEBUGASSERT(data);
+ /* OpenSSL catches this case, so should we. */
+ if(!buf)
+ return 0;
+
+ nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ wolfSSL_BIO_clear_retry_flags(bio);
+ if(nread < 0 && CURLE_AGAIN == result)
+ BIO_set_retry_read(bio);
+ return (int)nread;
+}
+
+static WOLFSSL_BIO_METHOD *bio_cf_method = NULL;
+
+static void bio_cf_init_methods(void)
+{
+ bio_cf_method = wolfSSL_BIO_meth_new(BIO_TYPE_MEM, "wolfSSL CF BIO");
+ wolfSSL_BIO_meth_set_write(bio_cf_method, &bio_cf_out_write);
+ wolfSSL_BIO_meth_set_read(bio_cf_method, &bio_cf_in_read);
+ wolfSSL_BIO_meth_set_ctrl(bio_cf_method, &bio_cf_ctrl);
+ wolfSSL_BIO_meth_set_create(bio_cf_method, &bio_cf_create);
+ wolfSSL_BIO_meth_set_destroy(bio_cf_method, &bio_cf_destroy);
+}
+
+static void bio_cf_free_methods(void)
+{
+ wolfSSL_BIO_meth_free(bio_cf_method);
+}
+
+#else /* USE_BIO_CHAIN */
+
+#define bio_cf_init_methods() Curl_nop_stmt
+#define bio_cf_free_methods() Curl_nop_stmt
+
+#endif /* !USE_BIO_CHAIN */
+
/*
* This function loads all the client/CA certificates and CRLs. Setup the TLS
* layer and do all necessary magic.
*/
static CURLcode
-wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
char *ciphers, *curves;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ 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);
+ const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
SSL_METHOD* req_method = NULL;
- curl_socket_t sockfd = conn->sock[sockindex];
#ifdef HAVE_LIBOQS
word16 oqsAlg = 0;
size_t idx = 0;
@@ -270,13 +385,13 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(connssl->state == ssl_connection_complete)
return CURLE_OK;
- if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
+ if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
return CURLE_SSL_CONNECT_ERROR;
}
/* check to see if we've been told to use an explicit SSL/TLS version */
- switch(SSL_CONN_CONFIG(version)) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
#if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
@@ -339,7 +454,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
}
- switch(SSL_CONN_CONFIG(version)) {
+ switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
#if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
@@ -363,7 +478,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
break;
}
- ciphers = SSL_CONN_CONFIG(cipher_list);
+ ciphers = conn_config->cipher_list;
if(ciphers) {
if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
@@ -372,7 +487,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
infof(data, "Cipher selection: %s", ciphers);
}
- curves = SSL_CONN_CONFIG(curves);
+ curves = conn_config->curves;
if(curves) {
#ifdef HAVE_LIBOQS
@@ -394,18 +509,18 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
#ifndef NO_FILESYSTEM
/* load trusted cacert */
- if(SSL_CONN_CONFIG(CAfile)) {
+ if(conn_config->CAfile) {
if(1 != SSL_CTX_load_verify_locations(backend->ctx,
- SSL_CONN_CONFIG(CAfile),
- SSL_CONN_CONFIG(CApath))) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ conn_config->CAfile,
+ conn_config->CApath)) {
+ if(conn_config->verifypeer) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:"
" CAfile: %s CApath: %s",
- SSL_CONN_CONFIG(CAfile)?
- SSL_CONN_CONFIG(CAfile): "none",
- SSL_CONN_CONFIG(CApath)?
- SSL_CONN_CONFIG(CApath) : "none");
+ conn_config->CAfile?
+ conn_config->CAfile: "none",
+ conn_config->CApath?
+ conn_config->CApath : "none");
return CURLE_SSL_CACERT_BADFILE;
}
else {
@@ -420,25 +535,25 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
infof(data, "successfully set certificate verify locations:");
}
infof(data, " CAfile: %s",
- SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none");
+ conn_config->CAfile ? conn_config->CAfile : "none");
infof(data, " CApath: %s",
- SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none");
+ conn_config->CApath ? conn_config->CApath : "none");
}
/* Load the client certificate, and private key */
- if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) {
- int file_type = do_file_type(SSL_SET_OPTION(cert_type));
+ if(ssl_config->primary.clientcert && ssl_config->key) {
+ int file_type = do_file_type(ssl_config->cert_type);
if(SSL_CTX_use_certificate_file(backend->ctx,
- SSL_SET_OPTION(primary.clientcert),
+ ssl_config->primary.clientcert,
file_type) != 1) {
failf(data, "unable to use client certificate (no key or wrong pass"
" phrase?)");
return CURLE_SSL_CONNECT_ERROR;
}
- file_type = do_file_type(SSL_SET_OPTION(key_type));
- if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key),
+ file_type = do_file_type(ssl_config->key_type);
+ if(SSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key,
file_type) != 1) {
failf(data, "unable to set private key");
return CURLE_SSL_CONNECT_ERROR;
@@ -451,8 +566,8 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
SSL_CTX_set_verify(backend->ctx,
- SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
- SSL_VERIFY_NONE,
+ conn_config->verifypeer?SSL_VERIFY_PEER:
+ SSL_VERIFY_NONE,
NULL);
#ifdef HAVE_SNI
@@ -461,16 +576,16 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#ifdef ENABLE_IPV6
struct in6_addr addr6;
#endif
- const char * const hostname = SSL_HOST_NAME();
- size_t hostname_len = strlen(hostname);
+ size_t hostname_len = strlen(connssl->hostname);
+
if((hostname_len < USHRT_MAX) &&
- !Curl_inet_pton(AF_INET, hostname, &addr4)
+ !Curl_inet_pton(AF_INET, connssl->hostname, &addr4)
#ifdef ENABLE_IPV6
- && !Curl_inet_pton(AF_INET6, hostname, &addr6)
+ && !Curl_inet_pton(AF_INET6, connssl->hostname, &addr6)
#endif
) {
size_t snilen;
- char *snihost = Curl_ssl_snihost(data, hostname, &snilen);
+ char *snihost = Curl_ssl_snihost(data, connssl->hostname, &snilen);
if(!snihost ||
wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, snihost,
(unsigned short)snilen) != 1) {
@@ -491,7 +606,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
}
#ifdef NO_FILESYSTEM
- else if(SSL_CONN_CONFIG(verifypeer)) {
+ else if(conn_config->verifypeer) {
failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
" with \"no filesystem\". Either disable peer verification"
" (insecure) or if you are building an application with libcurl you"
@@ -518,7 +633,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
#ifdef HAVE_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
char protocols[128];
*protocols = '\0';
@@ -563,13 +678,11 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif /* HAVE_SECURE_RENEGOTIATION */
/* Check if there's a cached ID we can/should use here! */
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn,
- SSL_IS_PROXY() ? TRUE : FALSE,
- &ssl_sessionid, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_delsessionid(data, ssl_sessionid);
@@ -581,11 +694,24 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
Curl_ssl_sessionid_unlock(data);
}
+#ifdef USE_BIO_CHAIN
+ {
+ WOLFSSL_BIO *bio;
+
+ bio = BIO_new(bio_cf_method);
+ if(!bio)
+ return CURLE_OUT_OF_MEMORY;
+
+ wolfSSL_BIO_set_data(bio, cf);
+ wolfSSL_set_bio(backend->handle, bio, bio);
+ }
+#else /* USE_BIO_CHAIN */
/* pass the raw socket into the SSL layer */
- if(!SSL_set_fd(backend->handle, (int)sockfd)) {
+ if(!SSL_set_fd(backend->handle, (int)cf->conn->sock[cf->sockindex])) {
failf(data, "SSL: SSL_set_fd failed");
return CURLE_SSL_CONNECT_ERROR;
}
+#endif /* !USE_BIO_CHAIN */
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
@@ -593,25 +719,23 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
static CURLcode
-wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
int ret = -1;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
- const char * const dispname = SSL_HOST_DISPNAME();
- const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
DEBUGASSERT(backend);
ERR_clear_error();
- conn->recv[sockindex] = wolfssl_recv;
- conn->send[sockindex] = wolfssl_send;
-
/* Enable RFC2818 checks */
- if(SSL_CONN_CONFIG(verifyhost)) {
- char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL);
+ if(conn_config->verifyhost) {
+ char *snihost = Curl_ssl_snihost(data, connssl->hostname, NULL);
if(!snihost ||
(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE))
return CURLE_SSL_CONNECT_ERROR;
@@ -661,32 +785,32 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
else if(DOMAIN_NAME_MISMATCH == detail) {
#if 1
failf(data, " subject alt name(s) or common name do not match \"%s\"",
- dispname);
+ connssl->dispname);
return CURLE_PEER_FAILED_VERIFICATION;
#else
/* When the wolfssl_check_domain_name() is used and you desire to
- * continue on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost
+ * continue on a DOMAIN_NAME_MISMATCH, i.e. 'ssl_config.verifyhost
* == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
* error. The only way to do this is currently to switch the
* Wolfssl_check_domain_name() in and out based on the
- * 'conn->ssl_config.verifyhost' value. */
- if(SSL_CONN_CONFIG(verifyhost)) {
+ * 'ssl_config.verifyhost' value. */
+ if(conn_config->verifyhost) {
failf(data,
" subject alt name(s) or common name do not match \"%s\"\n",
- dispname);
+ connssl->dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}
else {
infof(data,
" subject alt name(s) and/or common name do not match \"%s\"",
- dispname);
+ connssl->dispname);
return CURLE_OK;
}
#endif
}
#if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
else if(ASN_NO_SIGNER_E == detail) {
- if(SSL_CONN_CONFIG(verifypeer)) {
+ if(conn_config->verifypeer) {
failf(data, " CA signer not available for verification");
return CURLE_SSL_CACERT_BADFILE;
}
@@ -751,7 +875,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAVE_ALPN
- if(conn->bits.tls_enable_alpn) {
+ if(cf->conn->bits.tls_enable_alpn) {
int rc;
char *protocol = NULL;
unsigned short protocol_len = 0;
@@ -763,17 +887,17 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
!memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
- conn->alpn = CURL_HTTP_VERSION_1_1;
+ cf->conn->alpn = CURL_HTTP_VERSION_1_1;
#ifdef USE_HTTP2
else if(data->state.httpwant >= CURL_HTTP_VERSION_2 &&
protocol_len == ALPN_H2_LENGTH &&
!memcmp(protocol, ALPN_H2, ALPN_H2_LENGTH))
- conn->alpn = CURL_HTTP_VERSION_2;
+ cf->conn->alpn = CURL_HTTP_VERSION_2;
#endif
else
infof(data, "ALPN, unrecognized protocol %.*s", protocol_len,
protocol);
- Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ?
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
else if(rc == SSL_ALPN_NOT_FOUND)
@@ -799,28 +923,26 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
static CURLcode
-wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
+ const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(SSL_SET_OPTION(primary.sessionid)) {
+ if(ssl_config->primary.sessionid) {
bool incache;
bool added = FALSE;
void *old_ssl_sessionid = NULL;
/* SSL_get1_session allocates memory that has to be freed. */
SSL_SESSION *our_ssl_sessionid = SSL_get1_session(backend->handle);
- bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
if(our_ssl_sessionid) {
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
- &old_ssl_sessionid, NULL, sockindex));
+ incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
if(incache) {
if(old_ssl_sessionid != our_ssl_sessionid) {
infof(data, "old SSL session ID is stale, removing");
@@ -830,8 +952,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
if(!incache) {
- result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
- 0, sockindex, NULL);
+ result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL);
if(result) {
Curl_ssl_sessionid_unlock(data);
SSL_SESSION_free(our_ssl_sessionid);
@@ -857,14 +978,13 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
-static ssize_t wolfssl_send(struct Curl_easy *data,
- int sockindex,
+static ssize_t wolfssl_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const void *mem,
size_t len,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
@@ -896,10 +1016,9 @@ static ssize_t wolfssl_send(struct Curl_easy *data,
return rc;
}
-static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
(void) data;
@@ -921,14 +1040,13 @@ static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
}
}
-static ssize_t wolfssl_recv(struct Curl_easy *data,
- int num,
+static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
char *buf,
size_t buffersize,
CURLcode *curlcode)
{
- struct connectdata *conn = data->conn;
- struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
@@ -983,15 +1101,20 @@ static size_t wolfssl_version(char *buffer, size_t size)
static int wolfssl_init(void)
{
+ int ret;
+
#ifdef OPENSSL_EXTRA
Curl_tls_keylog_open();
#endif
- return (wolfSSL_Init() == SSL_SUCCESS);
+ ret = (wolfSSL_Init() == SSL_SUCCESS);
+ bio_cf_init_methods();
+ return ret;
}
static void wolfssl_cleanup(void)
{
+ bio_cf_free_methods();
wolfSSL_Cleanup();
#ifdef OPENSSL_EXTRA
Curl_tls_keylog_close();
@@ -999,14 +1122,15 @@ static void wolfssl_cleanup(void)
}
-static bool wolfssl_data_pending(const struct connectdata *conn,
- int connindex)
+static bool wolfssl_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
- const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- struct ssl_backend_data *backend = connssl->backend;
- DEBUGASSERT(backend);
- if(backend->handle) /* SSL is in use */
- return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE;
+ struct ssl_connect_data *ctx = cf->ctx;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+ if(ctx->backend->handle) /* SSL is in use */
+ return (0 != SSL_pending(ctx->backend->handle)) ? TRUE : FALSE;
else
return FALSE;
}
@@ -1016,36 +1140,33 @@ static bool wolfssl_data_pending(const struct connectdata *conn,
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
+static int wolfssl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *ctx = cf->ctx;
int retval = 0;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
- (void) data;
-
- DEBUGASSERT(backend);
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
- if(backend->handle) {
+ if(ctx->backend->handle) {
ERR_clear_error();
- SSL_free(backend->handle);
- backend->handle = NULL;
+ SSL_free(ctx->backend->handle);
+ ctx->backend->handle = NULL;
}
return retval;
}
static CURLcode
-wolfssl_connect_common(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
- bool nonblocking,
- bool *done)
+wolfssl_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool nonblocking,
+ bool *done)
{
CURLcode result;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = cf->ctx;
+ curl_socket_t sockfd = cf->conn->sock[cf->sockindex];
int what;
/* check if the connection has already been established */
@@ -1064,7 +1185,7 @@ wolfssl_connect_common(struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- result = wolfssl_connect_step1(data, conn, sockindex);
+ result = wolfssl_connect_step1(cf, data);
if(result)
return result;
}
@@ -1119,7 +1240,7 @@ wolfssl_connect_common(struct Curl_easy *data,
* ensuring that a client using select() or epoll() will always
* have a valid fdset to wait on.
*/
- result = wolfssl_connect_step2(data, conn, sockindex);
+ result = wolfssl_connect_step2(cf, data);
if(result || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state ||
@@ -1128,15 +1249,13 @@ wolfssl_connect_common(struct Curl_easy *data,
} /* repeat step2 until all transactions are done. */
if(ssl_connect_3 == connssl->connecting_state) {
- result = wolfssl_connect_step3(data, conn, sockindex);
+ result = wolfssl_connect_step3(cf, data);
if(result)
return result;
}
if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
- conn->recv[sockindex] = wolfssl_recv;
- conn->send[sockindex] = wolfssl_send;
*done = TRUE;
}
else
@@ -1149,21 +1268,21 @@ wolfssl_connect_common(struct Curl_easy *data,
}
-static CURLcode wolfssl_connect_nonblocking(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- return wolfssl_connect_common(data, conn, sockindex, TRUE, done);
+ return wolfssl_connect_common(cf, data, TRUE, done);
}
-static CURLcode wolfssl_connect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+static CURLcode wolfssl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result;
bool done = FALSE;
- result = wolfssl_connect_common(data, conn, sockindex, FALSE, &done);
+ result = wolfssl_connect_common(cf, data, FALSE, &done);
if(result)
return result;
@@ -1216,6 +1335,9 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
#ifdef KEEP_PEER_CERT
SSLSUPP_PINNEDPUBKEY |
#endif
+#ifdef USE_BIO_CHAIN
+ SSLSUPP_HTTPS_PROXY |
+#endif
SSLSUPP_SSL_CTX,
sizeof(struct ssl_backend_data),
@@ -1230,7 +1352,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
Curl_none_cert_status_request, /* cert_status_request */
wolfssl_connect, /* connect */
wolfssl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_getsock, /* getsock */
+ Curl_ssl_get_select_socks, /* getsock */
wolfssl_get_internals, /* get_internals */
wolfssl_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1241,7 +1363,10 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
Curl_none_false_start, /* false_start */
wolfssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
- NULL /* disassociate_connection */
+ NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
+ wolfssl_recv, /* recv decrypted data */
+ wolfssl_send, /* send data to encrypt */
};
#endif
diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.c b/Utilities/cmcurl/lib/vtls/x509asn1.c
index 0cfcbe87da..4c1c9a8b79 100644
--- a/Utilities/cmcurl/lib/vtls/x509asn1.c
+++ b/Utilities/cmcurl/lib/vtls/x509asn1.c
@@ -182,7 +182,7 @@ static const char *getASN1Element(struct Curl_asn1Element *elem,
const char *beg, const char *end)
{
unsigned char b;
- unsigned long len;
+ size_t len;
struct Curl_asn1Element lelem;
/* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
@@ -307,7 +307,7 @@ static const char *bit2str(const char *beg, const char *end)
*/
static const char *int2str(const char *beg, const char *end)
{
- unsigned long val = 0;
+ unsigned int val = 0;
size_t n = end - beg;
if(!n)
@@ -323,7 +323,7 @@ static const char *int2str(const char *beg, const char *end)
do
val = (val << 8) | *(const unsigned char *) beg++;
while(beg < end);
- return curl_maprintf("%s%lx", val >= 10? "0x": "", val);
+ return curl_maprintf("%s%x", val >= 10? "0x": "", val);
}
/*
@@ -953,8 +953,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
* ECC public key is all the data, a value of type BIT STRING mapped to
* OCTET STRING and should not be parsed as an ASN.1 value.
*/
- const unsigned long len =
- (unsigned long)((pubkey->end - pubkey->beg - 2) * 4);
+ const size_t len = ((pubkey->end - pubkey->beg - 2) * 4);
if(!certnum)
infof(data, " ECC Public Key (%lu bits)", len);
if(data->set.ssl.certinfo) {
@@ -972,7 +971,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
if(strcasecompare(algo, "rsaEncryption")) {
const char *q;
- unsigned long len;
+ size_t len;
p = getASN1Element(&elem, pk.beg, pk.end);
if(!p)
@@ -981,7 +980,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
/* Compute key length. */
for(q = elem.beg; !*q && q < elem.end; q++)
;
- len = (unsigned long)((elem.end - q) * 8);
+ len = ((elem.end - q) * 8);
if(len) {
unsigned int i;
for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
@@ -1073,7 +1072,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
size_t cl1;
char *cp2;
CURLcode result = CURLE_OK;
- unsigned long version;
+ unsigned int version;
size_t i;
size_t j;
@@ -1276,9 +1275,12 @@ static const char *checkOID(const char *beg, const char *end,
return matched? ccp: NULL;
}
-CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+CURLcode Curl_verifyhost(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
const char *beg, const char *end)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct Curl_X509certificate cert;
struct Curl_asn1Element dn;
struct Curl_asn1Element elem;
@@ -1290,9 +1292,8 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
int matched = -1;
size_t addrlen = (size_t) -1;
ssize_t len;
- const char * const hostname = SSL_HOST_NAME();
- const char * const dispname = SSL_HOST_DISPNAME();
- size_t hostlen = strlen(hostname);
+ size_t hostlen;
+
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@@ -1302,19 +1303,21 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
/* Verify that connection server matches info in X509 certificate at
`beg'..`end'. */
- if(!SSL_CONN_CONFIG(verifyhost))
+ if(!conn_config->verifyhost)
return CURLE_OK;
if(Curl_parseX509(&cert, beg, end))
return CURLE_PEER_FAILED_VERIFICATION;
+ hostlen = strlen(connssl->hostname);
+
/* Get the server IP address. */
#ifdef ENABLE_IPV6
- if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr))
+ if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, connssl->hostname, &addr))
addrlen = sizeof(struct in6_addr);
else
#endif
- if(Curl_inet_pton(AF_INET, hostname, &addr))
+ if(Curl_inet_pton(AF_INET, connssl->hostname, &addr))
addrlen = sizeof(struct in_addr);
/* Process extensions. */
@@ -1345,19 +1348,20 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
break;
switch(name.tag) {
case 2: /* DNS name. */
+ matched = 0;
len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
name.beg, name.end);
- if(len > 0 && (size_t)len == strlen(dnsname))
- matched = Curl_cert_hostcheck(dnsname,
- (size_t)len, hostname, hostlen);
- else
- matched = 0;
- free(dnsname);
+ if(len > 0) {
+ if(size_t)len == strlen(dnsname)
+ matched = Curl_cert_hostcheck(dnsname, (size_t)len,
+ connssl->hostname, hostlen);
+ free(dnsname);
+ }
break;
case 7: /* IP address. */
- matched = (size_t) (name.end - name.beg) == addrlen &&
- !memcmp(&addr, name.beg, addrlen);
+ matched = (name.end - name.beg) == addrlen &&
+ !memcmp(&addr, name.beg, addrlen);
break;
}
}
@@ -1367,12 +1371,12 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
switch(matched) {
case 1:
/* an alternative name matched the server hostname */
- infof(data, " subjectAltName: %s matched", dispname);
+ infof(data, " subjectAltName: %s matched", connssl->dispname);
return CURLE_OK;
case 0:
/* an alternative name field existed, but didn't match and then
we MUST fail */
- infof(data, " subjectAltName does not match %s", dispname);
+ infof(data, " subjectAltName does not match %s", connssl->dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}
@@ -1402,21 +1406,19 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
failf(data, "SSL: unable to obtain common name from peer certificate");
else {
len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end);
- if(len < 0) {
- free(dnsname);
+ if(len < 0)
return CURLE_OUT_OF_MEMORY;
- }
if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */
failf(data, "SSL: illegal cert name field");
else if(Curl_cert_hostcheck((const char *) dnsname,
- len, hostname, hostlen)) {
+ len, connssl->hostname, hostlen)) {
infof(data, " common name: %s (matched)", dnsname);
free(dnsname);
return CURLE_OK;
}
else
failf(data, "SSL: certificate subject name '%s' does not match "
- "target host name '%s'", dnsname, dispname);
+ "target host name '%s'", dnsname, connssl->dispname);
free(dnsname);
}
diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.h b/Utilities/cmcurl/lib/vtls/x509asn1.h
index a18fa11530..eb8e9597cb 100644
--- a/Utilities/cmcurl/lib/vtls/x509asn1.h
+++ b/Utilities/cmcurl/lib/vtls/x509asn1.h
@@ -30,6 +30,7 @@
#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+#include "cfilters.h"
#include "urldata.h"
/*
@@ -73,7 +74,7 @@ int Curl_parseX509(struct Curl_X509certificate *cert,
const char *beg, const char *end);
CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum,
const char *beg, const char *end);
-CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data,
const char *beg, const char *end);
#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL
* or USE_SECTRANSP */