diff --git a/lib/url.c b/lib/url.c index 6d6a56e1f..296951059 100644 --- a/lib/url.c +++ b/lib/url.c @@ -4176,7 +4176,12 @@ static void llist_dtor(void *user, void *element) */ static struct connectdata *allocate_conn(struct Curl_easy *data) { - struct connectdata *conn = calloc(1, sizeof(struct connectdata)); +#ifdef USE_SSL +#define SSL_EXTRA + 4 * Curl_ssl->sizeof_ssl_backend_data - sizeof(long long) +#else +#define SSL_EXTRA 0 +#endif + struct connectdata *conn = calloc(1, sizeof(struct connectdata) + SSL_EXTRA); if(!conn) return NULL; @@ -4259,6 +4264,23 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->ip_version = data->set.ipver; +#ifdef USE_SSL + /* + * To save on malloc()s, the SSL backend-specific data has been allocated + * at the end of the connectdata struct. + */ + { + char *p = (char *)&conn->align_data__do_not_use; + conn->ssl[0].backend = (struct ssl_backend_data *)p; + conn->ssl[1].backend = + (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data); + conn->proxy_ssl[0].backend = + (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data * 2); + conn->proxy_ssl[1].backend = + (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data * 3); + } +#endif + #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ defined(NTLM_WB_ENABLED) conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; diff --git a/lib/urldata.h b/lib/urldata.h index 0d0010fa7..ae73ba66a 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -82,71 +82,6 @@ #include "cookie.h" #include "formdata.h" -#ifdef USE_OPENSSL -#include -#ifdef HAVE_OPENSSL_ENGINE_H -#include -#endif -#endif /* USE_OPENSSL */ - -#ifdef USE_GNUTLS -#include -#endif - -#ifdef USE_MBEDTLS - -#include -#include -#include -#include - -#elif defined USE_POLARSSL - -#include -#include -#include -#include - -#endif /* USE_POLARSSL */ - -#ifdef USE_CYASSL -#undef OCSP_REQUEST /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */ -#undef OCSP_RESPONSE /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */ -#include -#endif - -#ifdef USE_NSS -#include -#include -#endif - -#ifdef USE_GSKIT -#include -#endif - -#ifdef USE_AXTLS -#include -#include -#undef malloc -#undef calloc -#undef realloc -#endif /* USE_AXTLS */ - -#if defined(USE_SCHANNEL) || defined(USE_WINDOWS_SSPI) -#include "curl_sspi.h" -#endif -#ifdef USE_SCHANNEL -#include -#include -#endif - -#ifdef USE_DARWINSSL -#include -/* For some reason, when building for iOS, the omnibus header above does - * not include SecureTransport.h as of iOS SDK 5.1. */ -#include -#endif - #ifdef HAVE_NETINET_IN_H #include #endif @@ -236,20 +171,6 @@ enum protection_level { }; #endif -#ifdef USE_SCHANNEL -/* Structs to store Schannel handles */ -struct curl_schannel_cred { - CredHandle cred_handle; - TimeStamp time_stamp; - int refcount; -}; - -struct curl_schannel_ctxt { - CtxtHandle ctxt_handle; - TimeStamp time_stamp; -}; -#endif - /* enum for the nonblocking SSL connection state machine */ typedef enum { ssl_connect_1, @@ -266,6 +187,9 @@ typedef enum { ssl_connection_complete } ssl_connection_state; +/* SSL backend-specific data; declared differently by each SSL backend */ +struct ssl_backend_data; + /* struct for data related to each SSL connection */ struct ssl_connect_data { /* Use ssl encrypted communications TRUE/FALSE, not necessarily using it atm @@ -274,78 +198,8 @@ struct ssl_connect_data { bool use; ssl_connection_state state; ssl_connect_state connecting_state; -#if defined(USE_OPENSSL) - /* these ones requires specific SSL-types */ - SSL_CTX* ctx; - SSL* handle; - X509* server_cert; -#elif defined(USE_GNUTLS) - gnutls_session_t session; - gnutls_certificate_credentials_t cred; -#ifdef USE_TLS_SRP - gnutls_srp_client_credentials_t srp_client_cred; -#endif -#elif defined(USE_MBEDTLS) - mbedtls_ctr_drbg_context ctr_drbg; - mbedtls_entropy_context entropy; - mbedtls_ssl_context ssl; - int server_fd; - mbedtls_x509_crt cacert; - mbedtls_x509_crt clicert; - mbedtls_x509_crl crl; - mbedtls_pk_context pk; - mbedtls_ssl_config config; - const char *protocols[3]; -#elif defined(USE_POLARSSL) - ctr_drbg_context ctr_drbg; - entropy_context entropy; - ssl_context ssl; - int server_fd; - x509_crt cacert; - x509_crt clicert; - x509_crl crl; - rsa_context rsa; -#elif defined(USE_CYASSL) - SSL_CTX* ctx; - SSL* handle; -#elif defined(USE_NSS) - PRFileDesc *handle; - char *client_nickname; - struct Curl_easy *data; - struct curl_llist obj_list; - PK11GenericObject *obj_clicert; -#elif defined(USE_GSKIT) - gsk_handle handle; - int iocport; - int localfd; - int remotefd; -#elif defined(USE_AXTLS) - SSL_CTX* ssl_ctx; - SSL* ssl; -#elif defined(USE_SCHANNEL) - struct curl_schannel_cred *cred; - struct curl_schannel_ctxt *ctxt; - SecPkgContext_StreamSizes stream_sizes; - size_t encdata_length, decdata_length; - size_t encdata_offset, decdata_offset; - unsigned char *encdata_buffer, *decdata_buffer; - /* encdata_is_incomplete: if encdata contains only a partial record that - can't be decrypted without another Curl_read_plain (that is, status is - SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes - more bytes into encdata then set this back to false. */ - bool encdata_is_incomplete; - unsigned long req_flags, ret_flags; - CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ - bool recv_sspi_close_notify; /* true if connection closed by close_notify */ - bool recv_connection_closed; /* true if connection closed, regardless how */ - bool use_alpn; /* true if ALPN is used for this connection */ -#elif defined(USE_DARWINSSL) - SSLContextRef ssl_ctx; - curl_socket_t ssl_sockfd; - bool ssl_direction; /* true if writing, false if reading */ - size_t ssl_write_buffered_length; -#elif defined(USE_SSL) -#error "SSL backend specific information missing from ssl_connect_data" +#if defined(USE_SSL) + struct ssl_backend_data *backend; #endif }; @@ -1175,6 +1029,16 @@ struct connectdata { char *unix_domain_socket; bool abstract_unix_socket; #endif + +#ifdef USE_SSL + /* + * To avoid multiple malloc() calls, the ssl_connect_data structures + * associated with a connectdata struct are allocated in the same block + * as the latter. This field forces alignment to an 8-byte boundary so + * that this all works. + */ + long long *align_data__do_not_use; +#endif }; /* The end of connectdata. */ @@ -1429,7 +1293,8 @@ struct UrlState { ares_channel f.e. */ #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) - ENGINE *engine; + /* void instead of ENGINE to avoid bleeding OpenSSL into this header */ + void *engine; #endif /* USE_OPENSSL */ struct curltime expiretime; /* set this with Curl_expire() only */ struct Curl_tree timenode; /* for the splay stuff */ diff --git a/lib/vtls/axtls.c b/lib/vtls/axtls.c index a91da3a8e..9b08d4981 100644 --- a/lib/vtls/axtls.c +++ b/lib/vtls/axtls.c @@ -47,7 +47,12 @@ #include "curl_memory.h" #include "memdebug.h" -#define BACKEND connssl +struct ssl_backend_data { + SSL_CTX* ssl_ctx; + SSL* ssl; +}; + +#define BACKEND connssl->backend static CURLcode map_error_to_curl(int axtls_err) { @@ -652,7 +657,7 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ static int Curl_axtls_check_cxn(struct connectdata *conn) { /* openssl.c line: - rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1); + rc = SSL_peek(conn->ssl[FIRSTSOCKET].backend->ssl, (void*)&buf, 1); axTLS compat layer always returns the last argument, so connection is always alive? */ @@ -705,6 +710,8 @@ const struct Curl_ssl Curl_ssl_axtls = { 0, /* have_ssl_ctx */ 0, /* support_https_proxy */ + sizeof(struct ssl_backend_data), + /* * axTLS has no global init. Everything is done through SSL and SSL_CTX * structs stored in connectdata structure. diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c index 00cf79a7c..6385f8960 100644 --- a/lib/vtls/cyassl.c +++ b/lib/vtls/cyassl.c @@ -91,6 +91,7 @@ and that's a problem since options.h hasn't been included yet. */ #include "x509asn1.h" #include "curl_printf.h" +#include #include #ifdef HAVE_CYASSL_ERROR_SSL_H #include @@ -122,7 +123,12 @@ and that's a problem since options.h hasn't been included yet. */ #endif #endif -#define BACKEND connssl +struct ssl_backend_data { + SSL_CTX* ctx; + SSL* handle; +}; + +#define BACKEND connssl->backend static Curl_recv cyassl_recv; static Curl_send cyassl_send; @@ -984,6 +990,8 @@ const struct Curl_ssl Curl_ssl_cyassl = { 1, /* have_ssl_ctx */ 0, /* support_https_proxy */ + sizeof(struct ssl_backend_data), + Curl_cyassl_init, /* init */ Curl_none_cleanup, /* cleanup */ Curl_cyassl_version, /* version */ diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c index 28f9dde85..c0e71ccbe 100644 --- a/lib/vtls/darwinssl.c +++ b/lib/vtls/darwinssl.c @@ -44,6 +44,8 @@ #endif #include +/* For some reason, when building for iOS, the omnibus header above does + * not include SecureTransport.h as of iOS SDK 5.1. */ #include #include #include @@ -118,7 +120,14 @@ #define ioErr -36 #define paramErr -50 -#define BACKEND connssl +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; +}; + +#define BACKEND connssl->backend /* pinned public key support tests */ @@ -2893,6 +2902,8 @@ const struct Curl_ssl Curl_ssl_darwinssl = { 0, /* have_ssl_ctx */ 0, /* support_https_proxy */ + sizeof(struct ssl_backend_data), + Curl_none_init, /* init */ Curl_none_cleanup, /* cleanup */ Curl_darwinssl_version, /* version */ diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c index 19808c621..5d6bb0c8f 100644 --- a/lib/vtls/gskit.c +++ b/lib/vtls/gskit.c @@ -98,7 +98,14 @@ #define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12) #define CURL_GSKPROTO_LAST 5 -#define BACKEND connssl +struct ssl_backend_data { + gsk_handle handle; + int iocport; + int localfd; + int remotefd; +}; + +#define BACKEND connssl->backend /* Supported ciphers. */ typedef struct { @@ -638,7 +645,7 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, if(FD_ISSET(BACKEND->remotefd, &fds_write)) { /* Try getting data from HTTPS proxy and pipe it upstream. */ n = 0; - i = gsk_secure_soc_read(connproxyssl->handle, + i = gsk_secure_soc_read(connproxyssl->backend->handle, buf, sizeof buf, &n); switch(i) { case GSK_OK: @@ -664,7 +671,7 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex, if(n < 0) return -1; if(n) { - i = gsk_secure_soc_write(connproxyssl->handle, buf, n, &m); + i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m); if(i != GSK_OK || n != m) return -1; ret = 1; @@ -1355,6 +1362,7 @@ const struct Curl_ssl Curl_ssl_gskit = { /* TODO: convert to 1 and fix test #1014 (if need) */ 0, /* support_https_proxy */ + sizeof(struct ssl_backend_data), Curl_gskit_init, /* init */ Curl_gskit_cleanup, /* cleanup */ diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 48de842a8..6364a61cf 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -107,7 +107,15 @@ static bool gtls_inited = FALSE; # include #endif -#define BACKEND connssl +struct ssl_backend_data { + gnutls_session_t session; + gnutls_certificate_credentials_t cred; +#ifdef USE_TLS_SRP + gnutls_srp_client_credentials_t srp_client_cred; +#endif +}; + +#define BACKEND connssl->backend /* * Custom push and pull callback functions used by GNU TLS to read and write @@ -843,7 +851,7 @@ gtls_connect_step1(struct connectdata *conn, } if(conn->proxy_ssl[sockindex].use) { - transport_ptr = conn->proxy_ssl[sockindex].session; + transport_ptr = conn->proxy_ssl[sockindex].backend->session; gnutls_transport_push = Curl_gtls_push_ssl; gnutls_transport_pull = Curl_gtls_pull_ssl; } @@ -1806,6 +1814,8 @@ const struct Curl_ssl Curl_ssl_gnutls = { 0, /* have_ssl_ctx */ 1, /* support_https_proxy */ + sizeof(struct ssl_backend_data), + Curl_gtls_init, /* init */ Curl_gtls_cleanup, /* cleanup */ Curl_gtls_version, /* version */ diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 162374e57..a46fb5fdc 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -61,7 +61,20 @@ #include "curl_memory.h" #include "memdebug.h" -#define BACKEND connssl +struct ssl_backend_data { + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + mbedtls_ssl_context ssl; + int server_fd; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + mbedtls_x509_crl crl; + mbedtls_pk_context pk; + mbedtls_ssl_config config; + const char *protocols[3]; +}; + +#define BACKEND connssl->backend /* apply threading? */ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) @@ -1034,6 +1047,8 @@ const struct Curl_ssl Curl_ssl_mbedtls = { 1, /* have_ssl_ctx */ 0, /* support_https_proxy */ + sizeof(struct ssl_backend_data), + Curl_mbedtls_init, /* init */ Curl_mbedtls_cleanup, /* cleanup */ Curl_mbedtls_version, /* version */ diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index 95dbb9a2f..2d132f5b1 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -78,7 +78,15 @@ /* enough to fit the string "PEM Token #[0|1]" */ #define SLOTSIZE 13 -#define BACKEND connssl +struct ssl_backend_data { + PRFileDesc *handle; + char *client_nickname; + struct Curl_easy *data; + struct curl_llist obj_list; + PK11GenericObject *obj_clicert; +}; + +#define BACKEND connssl->backend static PRLock *nss_initlock = NULL; static PRLock *nss_crllock = NULL; @@ -1480,7 +1488,7 @@ static void Curl_nss_close(struct connectdata *conn, int sockindex) struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex]; - if(BACKEND->handle || connssl_proxy->handle) { + if(BACKEND->handle || connssl_proxy->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]); @@ -1489,9 +1497,9 @@ static void Curl_nss_close(struct connectdata *conn, int sockindex) if(BACKEND->handle) /* nss_close(connssl) will transitively close also - connssl_proxy->handle if both are used. Clear it to avoid + connssl_proxy->backend->handle if both are used. Clear it to avoid a double close leading to crash. */ - connssl_proxy->handle = NULL; + connssl_proxy->backend->handle = NULL; nss_close(connssl); nss_close(connssl_proxy); @@ -1911,8 +1919,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) if(conn->proxy_ssl[sockindex].use) { DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); - DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL); - nspr_io = conn->proxy_ssl[sockindex].handle; + DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL); + nspr_io = conn->proxy_ssl[sockindex].backend->handle; second_layer = TRUE; } else { @@ -2343,6 +2351,8 @@ const struct Curl_ssl Curl_ssl_nss = { 0, /* have_ssl_ctx */ 1, /* support_https_proxy */ + sizeof(struct ssl_backend_data), + Curl_nss_init, /* init */ Curl_nss_cleanup, /* cleanup */ Curl_nss_version, /* version */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index ebaefd2ee..bc5475e53 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -51,8 +51,10 @@ #include "strcase.h" #include "hostcheck.h" #include "curl_printf.h" - #include +#ifdef HAVE_OPENSSL_ENGINE_H +#include +#endif #include #include #ifndef OPENSSL_NO_DSA @@ -155,7 +157,14 @@ static unsigned long OpenSSL_version_num(void) #define DEFAULT_CIPHER_SELECTION \ "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" -#define BACKEND connssl +struct ssl_backend_data { + /* these ones requires specific SSL-types */ + SSL_CTX* ctx; + SSL* handle; + X509* server_cert; +}; + +#define BACKEND connssl->backend /* * Number of bytes to read from the random number seed file. This must be @@ -2273,7 +2282,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) if(conn->proxy_ssl[sockindex].use) { BIO *const bio = BIO_new(BIO_f_ssl()); - SSL *handle = conn->proxy_ssl[sockindex].handle; + SSL *handle = conn->proxy_ssl[sockindex].backend->handle; DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); DEBUGASSERT(BACKEND->handle != NULL); DEBUGASSERT(bio != NULL); @@ -3415,6 +3424,8 @@ const struct Curl_ssl Curl_ssl_openssl = { 1, /* have_ssl_ctx */ 1, /* support_https_proxy */ + sizeof(struct ssl_backend_data), + Curl_ossl_init, /* init */ Curl_ossl_cleanup, /* cleanup */ Curl_ossl_version, /* version */ diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c index a23266d64..7d1b3b1fd 100644 --- a/lib/vtls/polarssl.c +++ b/lib/vtls/polarssl.c @@ -31,6 +31,8 @@ #ifdef USE_POLARSSL +#elif defined USE_POLARSSL + #include #include #include @@ -70,7 +72,18 @@ #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) -#define BACKEND connssl +struct ssl_backend_data { + ctr_drbg_context ctr_drbg; + entropy_context entropy; + ssl_context ssl; + int server_fd; + x509_crt cacert; + x509_crt clicert; + x509_crl crl; + rsa_context rsa; +}; + +#define BACKEND connssl->backend /* apply threading? */ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) @@ -896,6 +909,8 @@ const struct Curl_ssl Curl_ssl_polarssl = { 0, /* have_ssl_ctx */ 0, /* support_https_proxy */ + sizeof(struct ssl_backend_data), + Curl_polarssl_init, /* init */ Curl_polarssl_cleanup, /* cleanup */ Curl_polarssl_version, /* version */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 4fb24504d..d3f44018b 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -46,6 +46,8 @@ # error "Can't compile SCHANNEL support without SSPI." #endif +#include +#include #include "curl_sspi.h" #include "schannel.h" #include "vtls.h" @@ -127,7 +129,38 @@ * #define failf(x, y, ...) printf(y, __VA_ARGS__) */ -#define BACKEND connssl +/* Structs to store Schannel handles */ +struct curl_schannel_cred { + CredHandle cred_handle; + TimeStamp time_stamp; + int refcount; +}; + +struct curl_schannel_ctxt { + CtxtHandle ctxt_handle; + TimeStamp time_stamp; +}; + +struct ssl_backend_data { + struct curl_schannel_cred *cred; + struct curl_schannel_ctxt *ctxt; + SecPkgContext_StreamSizes stream_sizes; + size_t encdata_length, decdata_length; + size_t encdata_offset, decdata_offset; + unsigned char *encdata_buffer, *decdata_buffer; + /* encdata_is_incomplete: if encdata contains only a partial record that + can't be decrypted without another Curl_read_plain (that is, status is + SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes + more bytes into encdata then set this back to false. */ + bool encdata_is_incomplete; + unsigned long req_flags, ret_flags; + CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ + bool recv_sspi_close_notify; /* true if connection closed by close_notify */ + bool recv_connection_closed; /* true if connection closed, regardless how */ + bool use_alpn; /* true if ALPN is used for this connection */ +}; + +#define BACKEND connssl->backend static Curl_recv schannel_recv; static Curl_send schannel_send; @@ -1791,6 +1824,8 @@ const struct Curl_ssl Curl_ssl_schannel = { 0, /* have_ssl_ctx */ 0, /* support_https_proxy */ + sizeof(struct ssl_backend_data), + Curl_schannel_init, /* init */ Curl_schannel_cleanup, /* cleanup */ Curl_schannel_version, /* version */ diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h index a814b72fb..e993fb77c 100644 --- a/lib/vtls/vtls.h +++ b/lib/vtls/vtls.h @@ -36,6 +36,8 @@ struct Curl_ssl { unsigned support_https_proxy:1; /* supports access via HTTPS proxies */ + size_t sizeof_ssl_backend_data; + int (*init)(void); void (*cleanup)(void);