return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
}
+bool Curl_conn_get_ssl_info(struct Curl_easy *data,
+ struct connectdata *conn, int sockindex,
+ struct curl_tlssessioninfo *info)
+{
+ if(Curl_conn_is_ssl(conn, sockindex)) {
+ struct Curl_cfilter *cf = conn->cfilter[sockindex];
+ CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO,
+ NULL, (void *)info) : CURLE_UNKNOWN_OPTION;
+ return !result;
+ }
+ return FALSE;
+}
+
bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
{
struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
struct Curl_dns_entry;
struct connectdata;
struct ip_quadruple;
+struct curl_tlssessioninfo;
/* Callback to destroy resources held by this filter instance.
* Implementations MUST NOT chain calls to cf->next.
* - CF_QUERY_IP_INFO: res1 says if connection used IPv6, res2 is the
* ip quadruple
* - CF_QUERY_HOST_PORT: the remote hostname and port a filter talks to
+ * - CF_QUERY_SSL_INFO: fill out the passed curl_tlssessioninfo with the
+ * internal from the SSL secured connection when
+ * available.
+ * - CF_QUERY_SSL_CTX_INFO: same as CF_QUERY_SSL_INFO, but give the SSL_CTX
+ * when available, or the same internal pointer
+ * when the TLS stack does not differentiate.
*/
/* query res1 res2 */
#define CF_QUERY_MAX_CONCURRENT 1 /* number - */
* to NULL when not connected. */
#define CF_QUERY_REMOTE_ADDR 10 /* - `Curl_sockaddr_ex *` */
#define CF_QUERY_HOST_PORT 11 /* port const char * */
+#define CF_QUERY_SSL_INFO 12 /* - struct curl_tlssessioninfo * */
+#define CF_QUERY_SSL_CTX_INFO 13 /* - struct curl_tlssessioninfo * */
/**
* Query the cfilter for properties. Filters ignorant of a query will
*/
bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex);
+/*
+ * Fill `info` with information about the TLS instance securing
+ * the connection when available, otherwise e.g. when
+ * Curl_conn_is_ssl() is FALSE, return FALSE.
+ */
+bool Curl_conn_get_ssl_info(struct Curl_easy *data,
+ struct connectdata *conn, int sockindex,
+ struct curl_tlssessioninfo *info);
+
/**
* Connection provides multiplexing of easy handles at `socketindex`.
*/
#include "urldata.h"
#include "getinfo.h"
+#include "cfilters.h"
#include "vtls/vtls.h"
#include "connect.h" /* Curl_getconnectinfo() */
#include "progress.h"
struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
param_slistp;
struct curl_tlssessioninfo *tsi = &data->tsi;
-#ifdef USE_SSL
- struct connectdata *conn = data->conn;
-#endif
+ /* we are exposing a pointer to internal memory with unknown
+ * lifetime here. */
*tsip = tsi;
- tsi->backend = Curl_ssl_backend();
- tsi->internals = NULL;
-
-#ifdef USE_SSL
- if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
- tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0);
+ if(!Curl_conn_get_ssl_info(data, data->conn, FIRSTSOCKET, tsi)) {
+ tsi->backend = Curl_ssl_backend();
+ tsi->internals = NULL;
}
-#endif
}
break;
default:
case CF_QUERY_HTTP_VERSION:
*pres1 = 30;
return CURLE_OK;
+ case CF_QUERY_SSL_INFO:
+ case CF_QUERY_SSL_CTX_INFO: {
+ struct curl_tlssessioninfo *info = pres2;
+ if(Curl_vquic_tls_get_ssl_info(&ctx->tls,
+ (query == CF_QUERY_SSL_INFO), info))
+ return CURLE_OK;
+ break;
+ }
default:
break;
}
case CF_QUERY_HTTP_VERSION:
*pres1 = 30;
return CURLE_OK;
+ case CF_QUERY_SSL_INFO:
+ case CF_QUERY_SSL_CTX_INFO: {
+ struct curl_tlssessioninfo *info = pres2;
+ if(Curl_vquic_tls_get_ssl_info(&ctx->tls,
+ (query == CF_QUERY_SSL_INFO), info))
+ return CURLE_OK;
+ break;
+ }
default:
break;
}
case CF_QUERY_HTTP_VERSION:
*pres1 = 30;
return CURLE_OK;
+ case CF_QUERY_SSL_INFO:
+ case CF_QUERY_SSL_CTX_INFO: {
+ struct curl_tlssessioninfo *info = pres2;
+ if(Curl_vquic_tls_get_ssl_info(&ctx->tls,
+ (query == CF_QUERY_SSL_INFO), info))
+ return CURLE_OK;
+ break;
+ }
default:
break;
}
return result;
}
-bool Curl_conn_is_quiche(const struct Curl_easy *data,
- const struct connectdata *conn,
- int sockindex)
-{
- struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
-
- (void)data;
- for(; cf; cf = cf->next) {
- if(cf->cft == &Curl_cft_http3)
- return TRUE;
- if(cf->cft->flags & CF_TYPE_IP_CONNECT)
- return FALSE;
- }
- return FALSE;
-}
-
#endif
struct connectdata *conn,
const struct Curl_addrinfo *ai);
-bool Curl_conn_is_quiche(const struct Curl_easy *data,
- const struct connectdata *conn,
- int sockindex);
-
#endif
#endif /* HEADER_CURL_VQUIC_CURL_QUICHE_H */
}
+bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx,
+ bool give_ssl_ctx,
+ struct curl_tlssessioninfo *info)
+{
+#ifdef USE_OPENSSL
+ info->backend = CURLSSLBACKEND_OPENSSL;
+ info->internals = give_ssl_ctx ?
+ (void *)ctx->ossl.ssl_ctx : (void *)ctx->ossl.ssl;
+ return TRUE;
+#elif defined(USE_GNUTLS)
+ (void)give_ssl_ctx; /* gnutls always returns its session */
+ info->backend = CURLSSLBACKEND_OPENSSL;
+ info->internals = ctx->gtls.session;
+ return TRUE;
+#elif defined(USE_WOLFSSL)
+ info->backend = CURLSSLBACKEND_WOLFSSL;
+ info->internals = give_ssl_ctx ?
+ (void *)ctx->wssl.ssl_ctx : (void *)ctx->wssl.ssl;
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
#endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
struct ssl_peer;
struct Curl_ssl_session;
+struct curl_tlssessioninfo;
struct curl_tls_ctx {
#ifdef USE_OPENSSL
struct Curl_easy *data,
struct ssl_peer *peer);
+bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx,
+ bool give_ssl_ctx,
+ struct curl_tlssessioninfo *info);
+
#endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
#endif /* HEADER_CURL_VQUIC_TLS_H */
*when = connssl->handshake_done;
return CURLE_OK;
}
+ case CF_QUERY_SSL_INFO:
+ case CF_QUERY_SSL_CTX_INFO: {
+ struct curl_tlssessioninfo *info = pres2;
+ struct cf_call_data save;
+ CF_DATA_SAVE(save, cf, data);
+ info->backend = Curl_ssl_backend();
+ info->internals = connssl->ssl_impl->get_internals(
+ cf->ctx, (query == CF_QUERY_SSL_INFO) ?
+ CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION);
+ CF_DATA_RESTORE(cf, save);
+ return CURLE_OK;
+ }
default:
break;
}
return (Curl_ssl->supports & ssl_option);
}
-static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
-{
- for(; cf; cf = cf->next) {
- if(cf->cft == &Curl_cft_ssl)
- return cf;
-#ifndef CURL_DISABLE_PROXY
- if(cf->cft == &Curl_cft_ssl_proxy)
- return cf;
-#endif
- }
- return NULL;
-}
-
-
-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 SSL filter in chain, if any is present */
- cf = get_ssl_filter(data->conn->cfilter[sockindex]);
- if(cf) {
- struct ssl_connect_data *connssl = cf->ctx;
- struct cf_call_data save;
- CF_DATA_SAVE(save, cf, data);
- result = connssl->ssl_impl->get_internals(cf->ctx, info);
- CF_DATA_RESTORE(cf, save);
- }
- }
- return result;
-}
-
static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool send_shutdown, bool *done)
*/
bool Curl_ssl_supports(struct Curl_easy *data, unsigned 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);
-
/**
* Get the ssl_config_data in `data` that is relevant for cfilter `cf`.
*/
#define Curl_ssl_free_certinfo(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_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_remove(a,b,c) CURLE_OK
(void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT,
global->parallel_connect ? 0L : 1L);
(void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per);
+ /* curl does not use signals, switching this on saves some system calls */
+ (void)curl_easy_setopt(per->curl, CURLOPT_NOSIGNAL, 1L);
(void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb);
(void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per);
(void)curl_easy_setopt(per->curl, CURLOPT_NOPROGRESS, 0L);
***************************************************************************/
#include "first.h"
+static int tse_found_tls_session = FALSE;
+
static size_t write_tse_cb(char *ptr, size_t size, size_t nmemb, void *opaque)
{
+ CURL *easy = opaque;
(void)ptr;
- (void)opaque;
+ if(!tse_found_tls_session) {
+ struct curl_tlssessioninfo *tlssession;
+ CURLcode rc;
+
+ rc = curl_easy_getinfo(easy, CURLINFO_TLS_SSL_PTR, &tlssession);
+ if(rc) {
+ curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) "
+ "failed: %s\n", curl_easy_strerror(rc));
+ return rc;
+ }
+ if(tlssession->backend == CURLSSLBACKEND_NONE) {
+ curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) "
+ "gave no backend\n");
+ return CURLE_FAILED_INIT;
+ }
+ if(!tlssession->internals) {
+ curl_mfprintf(stderr, "curl_easy_getinfo(CURLINFO_TLS_SSL_PTR) "
+ "missing\n");
+ return CURLE_FAILED_INIT;
+ }
+ tse_found_tls_session = TRUE;
+ }
return size * nmemb;
}
-static int add_transfer(CURLM *multi, CURLSH *share,
- struct curl_slist *resolve,
- const char *url, long http_version)
+static CURL *tse_add_transfer(CURLM *multi, CURLSH *share,
+ struct curl_slist *resolve,
+ const char *url, long http_version)
{
CURL *easy;
CURLMcode mc;
easy = curl_easy_init();
if(!easy) {
curl_mfprintf(stderr, "curl_easy_init failed\n");
- return 1;
+ return NULL;
}
curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(easy, CURLOPT_DEBUGFUNCTION, debug_cb);
curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(easy, CURLOPT_HTTP_VERSION, http_version);
curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_tse_cb);
- curl_easy_setopt(easy, CURLOPT_WRITEDATA, NULL);
+ curl_easy_setopt(easy, CURLOPT_WRITEDATA, easy);
curl_easy_setopt(easy, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L);
if(resolve)
curl_mfprintf(stderr, "curl_multi_add_handle: %s\n",
curl_multi_strerror(mc));
curl_easy_cleanup(easy);
- return 1;
+ return NULL;
}
- return 0;
+ return easy;
}
static int test_tls_session_reuse(int argc, char *argv[])
curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
- if(add_transfer(multi, share, resolve, url, http_version))
+ if(!tse_add_transfer(multi, share, resolve, url, http_version))
goto cleanup;
++ongoing;
add_more = 6;
}
else {
while(add_more) {
- if(add_transfer(multi, share, resolve, url, http_version))
+ if(!tse_add_transfer(multi, share, resolve, url, http_version))
goto cleanup;
++ongoing;
--add_more;
} while(ongoing || add_more);
+ if(!tse_found_tls_session) {
+ curl_mfprintf(stderr, "CURLINFO_TLS_SSL_PTR not found during run\n");
+ exitcode = CURLE_FAILED_INIT;
+ goto cleanup;
+ }
+
curl_mfprintf(stderr, "exiting\n");
exitcode = 0;