* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
#ifdef USE_OPENSSL
-#ifdef HAVE_LIMITS_H
#include <limits.h>
-#endif
#include "urldata.h"
#include "sendf.h"
#include "strcase.h"
#include "hostcheck.h"
#include "curl_printf.h"
-
#include <openssl/ssl.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
#include <openssl/rand.h>
#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_DSA
#include <openssl/dsa.h>
+#endif
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/conf.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
-
-#ifdef HAVE_OPENSSL_PKCS12_H
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
#include <openssl/pkcs12.h>
-#endif
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
#include <openssl/ocsp.h>
#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */
#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */
#define CONST_EXTS const
-#define CONST_ASN1_BIT_STRING const
#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1
#else
/* For OpenSSL before 1.1.0 */
#define X509_get0_notBefore(x) X509_get_notBefore(x)
#define X509_get0_notAfter(x) X509_get_notAfter(x)
#define CONST_EXTS /* nope */
-#define CONST_ASN1_BIT_STRING /* nope */
#ifdef LIBRESSL_VERSION_NUMBER
static unsigned long OpenSSL_version_num(void)
{
#define OPENSSL_load_builtin_modules(x)
#endif
+/*
+ * Whether SSL_CTX_set_keylog_callback is available.
+ * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
+ * BoringSSL: supported since d28f59c27bac (committed 2015-11-19)
+ * LibreSSL: unsupported in at least 2.5.1 (explicitly check for it since it
+ * lies and pretends to be OpenSSL 2.0.0).
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+ !defined(LIBRESSL_VERSION_NUMBER)) || \
+ defined(OPENSSL_IS_BORINGSSL)
+#define HAVE_KEYLOG_CALLBACK
+#endif
+
#if defined(LIBRESSL_VERSION_NUMBER)
#define OSSL_PACKAGE "LibreSSL"
#elif defined(OPENSSL_IS_BORINGSSL)
#define OSSL_PACKAGE "OpenSSL"
#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+/* up2date versions of OpenSSL maintain the default reasonably secure without
+ * breaking compatibility, so it is better not to override the default by curl
+ */
+#define DEFAULT_CIPHER_SELECTION NULL
+#else
+/* ... but it is not the case with old versions of OpenSSL */
+#define DEFAULT_CIPHER_SELECTION \
+ "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
+#endif
+
+#define ENABLE_SSLKEYLOGFILE
+
+#ifdef ENABLE_SSLKEYLOGFILE
+typedef struct ssl_tap_state {
+ int master_key_length;
+ unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+} ssl_tap_state_t;
+#endif /* ENABLE_SSLKEYLOGFILE */
+
+struct ssl_backend_data {
+ /* these ones requires specific SSL-types */
+ SSL_CTX* ctx;
+ SSL* handle;
+ X509* server_cert;
+#ifdef ENABLE_SSLKEYLOGFILE
+ /* tap_state holds the last seen master key if we're logging them */
+ ssl_tap_state_t tap_state;
+#endif
+};
+
+#define BACKEND connssl->backend
+
/*
* Number of bytes to read from the random number seed file. This must be
* a finite value (because some entropy "files" like /dev/urandom have
* an infinite length), but must be large enough to provide enough
- * entopy to properly seed OpenSSL's PRNG.
+ * entropy to properly seed OpenSSL's PRNG.
*/
#define RAND_LOAD_LENGTH 1024
+#ifdef ENABLE_SSLKEYLOGFILE
+/* The fp for the open SSLKEYLOGFILE, or NULL if not open */
+static FILE *keylog_file_fp;
+
+#ifdef HAVE_KEYLOG_CALLBACK
+static void ossl_keylog_callback(const SSL *ssl, const char *line)
+{
+ (void)ssl;
+
+ /* Using fputs here instead of fprintf since libcurl's fprintf replacement
+ may not be thread-safe. */
+ if(keylog_file_fp && line && *line) {
+ char stackbuf[256];
+ char *buf;
+ size_t linelen = strlen(line);
+
+ if(linelen <= sizeof(stackbuf) - 2)
+ buf = stackbuf;
+ else {
+ buf = malloc(linelen + 2);
+ if(!buf)
+ return;
+ }
+ strncpy(buf, line, linelen);
+ buf[linelen] = '\n';
+ buf[linelen + 1] = '\0';
+
+ fputs(buf, keylog_file_fp);
+ if(buf != stackbuf)
+ free(buf);
+ }
+}
+#else
+#define KEYLOG_PREFIX "CLIENT_RANDOM "
+#define KEYLOG_PREFIX_LEN (sizeof(KEYLOG_PREFIX) - 1)
+/*
+ * tap_ssl_key is called by libcurl to make the CLIENT_RANDOMs if the OpenSSL
+ * being used doesn't have native support for doing that.
+ */
+static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state)
+{
+ const char *hex = "0123456789ABCDEF";
+ int pos, i;
+ char line[KEYLOG_PREFIX_LEN + 2 * SSL3_RANDOM_SIZE + 1 +
+ 2 * SSL_MAX_MASTER_KEY_LENGTH + 1 + 1];
+ const SSL_SESSION *session = SSL_get_session(ssl);
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+ unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
+ int master_key_length = 0;
+
+ if(!session || !keylog_file_fp)
+ return;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+ /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
+ * we have a valid SSL context if we have a non-NULL session. */
+ SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE);
+ master_key_length = (int)
+ SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH);
+#else
+ if(ssl->s3 && session->master_key_length > 0) {
+ master_key_length = session->master_key_length;
+ memcpy(master_key, session->master_key, session->master_key_length);
+ memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+ }
+#endif
+
+ if(master_key_length <= 0)
+ return;
+
+ /* Skip writing keys if there is no key or it did not change. */
+ if(state->master_key_length == master_key_length &&
+ !memcmp(state->master_key, master_key, master_key_length) &&
+ !memcmp(state->client_random, client_random, SSL3_RANDOM_SIZE)) {
+ return;
+ }
+
+ state->master_key_length = master_key_length;
+ memcpy(state->master_key, master_key, master_key_length);
+ memcpy(state->client_random, client_random, SSL3_RANDOM_SIZE);
+
+ memcpy(line, KEYLOG_PREFIX, KEYLOG_PREFIX_LEN);
+ pos = KEYLOG_PREFIX_LEN;
+
+ /* Client Random for SSLv3/TLS */
+ for(i = 0; i < SSL3_RANDOM_SIZE; i++) {
+ line[pos++] = hex[client_random[i] >> 4];
+ line[pos++] = hex[client_random[i] & 0xF];
+ }
+ line[pos++] = ' ';
+
+ /* Master Secret (size is at most SSL_MAX_MASTER_KEY_LENGTH) */
+ for(i = 0; i < master_key_length; i++) {
+ line[pos++] = hex[master_key[i] >> 4];
+ line[pos++] = hex[master_key[i] & 0xF];
+ }
+ line[pos++] = '\n';
+ line[pos] = '\0';
+
+ /* Using fputs here instead of fprintf since libcurl's fprintf replacement
+ may not be thread-safe. */
+ fputs(line, keylog_file_fp);
+}
+#endif /* !HAVE_KEYLOG_CALLBACK */
+#endif /* ENABLE_SSLKEYLOGFILE */
+
+static const char *SSL_ERROR_to_str(int err)
+{
+ switch(err) {
+ case SSL_ERROR_NONE:
+ return "SSL_ERROR_NONE";
+ case SSL_ERROR_SSL:
+ return "SSL_ERROR_SSL";
+ case SSL_ERROR_WANT_READ:
+ return "SSL_ERROR_WANT_READ";
+ case SSL_ERROR_WANT_WRITE:
+ return "SSL_ERROR_WANT_WRITE";
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ return "SSL_ERROR_WANT_X509_LOOKUP";
+ case SSL_ERROR_SYSCALL:
+ return "SSL_ERROR_SYSCALL";
+ case SSL_ERROR_ZERO_RETURN:
+ return "SSL_ERROR_ZERO_RETURN";
+ case SSL_ERROR_WANT_CONNECT:
+ return "SSL_ERROR_WANT_CONNECT";
+ case SSL_ERROR_WANT_ACCEPT:
+ return "SSL_ERROR_WANT_ACCEPT";
+#if defined(SSL_ERROR_WANT_ASYNC)
+ case SSL_ERROR_WANT_ASYNC:
+ return "SSL_ERROR_WANT_ASYNC";
+#endif
+#if defined(SSL_ERROR_WANT_ASYNC_JOB)
+ case SSL_ERROR_WANT_ASYNC_JOB:
+ return "SSL_ERROR_WANT_ASYNC_JOB";
+#endif
+#if defined(SSL_ERROR_WANT_EARLY)
+ case SSL_ERROR_WANT_EARLY:
+ return "SSL_ERROR_WANT_EARLY";
+#endif
+ default:
+ return "SSL_ERROR unknown";
+ }
+}
+
+/* Return error string for last OpenSSL error
+ */
+static char *ossl_strerror(unsigned long error, char *buf, size_t size)
+{
+ ERR_error_string_n(error, buf, size);
+ return buf;
+}
+
static int passwd_callback(char *buf, int num, int encrypting,
void *global_passwd)
{
if(!encrypting) {
int klen = curlx_uztosi(strlen((char *)global_passwd));
if(num > klen) {
- memcpy(buf, global_passwd, klen+1);
+ memcpy(buf, global_passwd, klen + 1);
return klen;
}
}
/* we have the "SSL is seeded" boolean static to prevent multiple
time-consuming seedings in vain */
static bool ssl_seeded = FALSE;
- char *buf = data->state.buffer; /* point to the big buffer */
- int nread=0;
+ char fname[256];
if(ssl_seeded)
return CURLE_OK;
#endif
{
/* let the option override the define */
- nread += RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]?
- data->set.str[STRING_SSL_RANDOM_FILE]:
- RANDOM_FILE),
- RAND_LOAD_LENGTH);
+ RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]?
+ data->set.str[STRING_SSL_RANDOM_FILE]:
+ RANDOM_FILE),
+ RAND_LOAD_LENGTH);
if(rand_enough())
- return nread;
+ return CURLE_OK;
}
#if defined(HAVE_RAND_EGD)
int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]?
data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET);
if(-1 != ret) {
- nread += ret;
if(rand_enough())
- return nread;
+ return CURLE_OK;
}
}
#endif
- /* If we get here, it means we need to seed the PRNG using a "silly"
- approach! */
+ /* fallback to a custom seeding of the PRNG using a hash based on a current
+ time */
do {
unsigned char randb[64];
- int len = sizeof(randb);
- if(!RAND_bytes(randb, len))
- break;
- RAND_add(randb, len, (len >> 1));
+ size_t len = sizeof(randb);
+ size_t i, i_max;
+ for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
+ struct curltime tv = Curl_now();
+ Curl_wait_ms(1);
+ tv.tv_sec *= i + 1;
+ tv.tv_usec *= (unsigned int)i + 2;
+ tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) *
+ (i + 3)) << 8;
+ tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec +
+ Curl_now().tv_usec) *
+ (i + 4)) << 16;
+ memcpy(&randb[i * sizeof(struct curltime)], &tv,
+ sizeof(struct curltime));
+ }
+ RAND_add(randb, (int)len, (double)len/2);
} while(!rand_enough());
/* generates a default path for the random seed file */
- buf[0]=0; /* blank it first */
- RAND_file_name(buf, BUFSIZE);
- if(buf[0]) {
+ fname[0] = 0; /* blank it first */
+ RAND_file_name(fname, sizeof(fname));
+ if(fname[0]) {
/* we got a file name to try */
- nread += RAND_load_file(buf, RAND_LOAD_LENGTH);
+ RAND_load_file(fname, RAND_LOAD_LENGTH);
if(rand_enough())
- return nread;
+ return CURLE_OK;
}
infof(data, "libcurl is now using a weak random seed!\n");
- return CURLE_SSL_CONNECT_ERROR; /* confusing error code */
+ return (rand_enough() ? CURLE_OK :
+ CURLE_SSL_CONNECT_ERROR /* confusing error code */);
}
#ifndef SSL_FILETYPE_ENGINE
char *key_passwd)
{
struct Curl_easy *data = conn->data;
+ char error_buffer[256];
+ bool check_privkey = TRUE;
int file_type = do_file_type(cert_type);
"could not load PEM client certificate, " OSSL_PACKAGE
" error %s, "
"(no key found, wrong pass phrase, or wrong file format?)",
- ERR_error_string(ERR_get_error(), NULL) );
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
return 0;
}
break;
"could not load ASN1 client certificate, " OSSL_PACKAGE
" error %s, "
"(no key found, wrong pass phrase, or wrong file format?)",
- ERR_error_string(ERR_get_error(), NULL) );
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
return 0;
}
break;
0, ¶ms, NULL, 1)) {
failf(data, "ssl engine cannot load client cert with id"
" '%s' [%s]", cert_file,
- ERR_error_string(ERR_get_error(), NULL));
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
return 0;
}
case SSL_FILETYPE_PKCS12:
{
-#ifdef HAVE_OPENSSL_PKCS12_H
FILE *f;
PKCS12 *p12;
EVP_PKEY *pri;
failf(data,
"could not parse PKCS12 file, check password, " OSSL_PACKAGE
" error %s",
- ERR_error_string(ERR_get_error(), NULL) );
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
PKCS12_free(p12);
return 0;
}
failf(data,
"could not load PKCS12 client certificate, " OSSL_PACKAGE
" error %s",
- ERR_error_string(ERR_get_error(), NULL) );
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
goto fail;
}
if(!cert_done)
return 0; /* failure! */
break;
-#else
- failf(data, "file type P12 for certificate not supported");
- return 0;
-#endif
}
default:
failf(data, "not supported file type '%s' for certificate", cert_type);
break;
if(!key_file)
/* cert & key can only be in PEM case in the same file */
- key_file=cert_file;
+ key_file = cert_file;
+ /* FALLTHROUGH */
case SSL_FILETYPE_ASN1:
if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
failf(data, "unable to set private key file: '%s' type %s",
return 0;
}
- ssl=SSL_new(ctx);
+ ssl = SSL_new(ctx);
if(!ssl) {
failf(data, "unable to create an SSL structure");
return 0;
}
- x509=SSL_get_certificate(ssl);
+ x509 = SSL_get_certificate(ssl);
/* This version was provided by Evan Jordan and is supposed to not
leak memory as the previous version: */
EVP_PKEY_free(pktmp);
}
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL)
+ {
+ /* If RSA is used, don't check the private key if its flags indicate
+ * it doesn't support it. */
+ EVP_PKEY *priv_key = SSL_get_privatekey(ssl);
+ int pktype;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+ pktype = EVP_PKEY_id(priv_key);
+#else
+ pktype = priv_key->type;
+#endif
+ if(pktype == EVP_PKEY_RSA) {
+ RSA *rsa = EVP_PKEY_get1_RSA(priv_key);
+ if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK)
+ check_privkey = FALSE;
+ RSA_free(rsa); /* Decrement reference count */
+ }
+ }
+#endif
+
SSL_free(ssl);
/* If we are using DSA, we can copy the parameters from
* the private key */
-
- /* Now we know that a key and cert have been set against
- * the SSL context */
- if(!SSL_CTX_check_private_key(ctx)) {
- failf(data, "Private key does not match the certificate public key");
- return 0;
+ if(check_privkey == TRUE) {
+ /* Now we know that a key and cert have been set against
+ * the SSL context */
+ if(!SSL_CTX_check_private_key(ctx)) {
+ failf(data, "Private key does not match the certificate public key");
+ return 0;
+ }
}
}
return 1;
size--; /* don't overwrite the buffer end */
memcpy(buf, biomem->data, size);
- buf[size]=0;
+ buf[size] = 0;
BIO_free(bio_out);
#endif
}
-/* Return error string for last OpenSSL error
- */
-static char *ossl_strerror(unsigned long error, char *buf, size_t size)
-{
- /* OpenSSL 0.9.6 and later has a function named
- ERR_error_string_n() that takes the size of the buffer as a
- third argument */
- ERR_error_string_n(error, buf, size);
- return buf;
-}
-
/**
* Global SSL init
*
* @retval 0 error initializing SSL
* @retval 1 SSL initialized successfully
*/
-int Curl_ossl_init(void)
+static int Curl_ossl_init(void)
{
+#ifdef ENABLE_SSLKEYLOGFILE
+ char *keylog_file_name;
+#endif
+
OPENSSL_load_builtin_modules();
#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
OpenSSL_add_all_algorithms();
#endif
+#ifdef ENABLE_SSLKEYLOGFILE
+ if(!keylog_file_fp) {
+ keylog_file_name = curl_getenv("SSLKEYLOGFILE");
+ if(keylog_file_name) {
+ keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT);
+ if(keylog_file_fp) {
+#ifdef WIN32
+ if(setvbuf(keylog_file_fp, NULL, _IONBF, 0))
+#else
+ if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096))
+#endif
+ {
+ fclose(keylog_file_fp);
+ keylog_file_fp = NULL;
+ }
+ }
+ Curl_safefree(keylog_file_name);
+ }
+ }
+#endif
+
return 1;
}
/* Global cleanup */
-void Curl_ossl_cleanup(void)
+static void Curl_ossl_cleanup(void)
{
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
!defined(LIBRESSL_VERSION_NUMBER)
SSL_COMP_free_compression_methods();
#endif
#endif
+
+#ifdef ENABLE_SSLKEYLOGFILE
+ if(keylog_file_fp) {
+ fclose(keylog_file_fp);
+ keylog_file_fp = NULL;
+ }
+#endif
}
/*
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-int Curl_ossl_check_cxn(struct connectdata *conn)
+static int Curl_ossl_check_cxn(struct connectdata *conn)
{
/* SSL_peek takes data out of the raw recv buffer without peeking so we use
recv MSG_PEEK instead. Bug #795 */
(RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK);
if(nread == 0)
return 0; /* connection has been closed */
- else if(nread == 1)
+ if(nread == 1)
return 1; /* connection still in place */
else if(nread == -1) {
int err = SOCKERRNO;
/* Selects an OpenSSL crypto engine
*/
-CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine)
+static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
+ const char *engine)
{
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
ENGINE *e;
/* Sets engine as default for all SSL operations
*/
-CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
+static CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
{
#ifdef HAVE_OPENSSL_ENGINE_H
if(data->state.engine) {
/* Return list of OpenSSL crypto engine names.
*/
-struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
+static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
{
struct curl_slist *list = NULL;
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
static void ossl_close(struct ssl_connect_data *connssl)
{
- if(connssl->handle) {
- (void)SSL_shutdown(connssl->handle);
- SSL_set_connect_state(connssl->handle);
+ if(BACKEND->handle) {
+ (void)SSL_shutdown(BACKEND->handle);
+ SSL_set_connect_state(BACKEND->handle);
- SSL_free(connssl->handle);
- connssl->handle = NULL;
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = NULL;
}
- if(connssl->ctx) {
- SSL_CTX_free(connssl->ctx);
- connssl->ctx = NULL;
+ if(BACKEND->ctx) {
+ SSL_CTX_free(BACKEND->ctx);
+ BACKEND->ctx = NULL;
}
}
/*
* This function is called when an SSL connection is closed.
*/
-void Curl_ossl_close(struct connectdata *conn, int sockindex)
+static void Curl_ossl_close(struct connectdata *conn, int sockindex)
{
ossl_close(&conn->ssl[sockindex]);
ossl_close(&conn->proxy_ssl[sockindex]);
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
+static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
{
int retval = 0;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
we do not send one. Let's hope other servers do the same... */
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- (void)SSL_shutdown(connssl->handle);
+ (void)SSL_shutdown(BACKEND->handle);
- if(connssl->handle) {
+ if(BACKEND->handle) {
buffsize = (int)sizeof(buf);
while(!done) {
int what = SOCKET_READABLE(conn->sock[sockindex],
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
- nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf,
- buffsize);
- err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread);
+ nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize);
+ err = SSL_get_error(BACKEND->handle, (int)nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
default:
/* openssl/ssl.h says "look at error stack/return value/errno" */
sslerror = ERR_get_error();
- failf(conn->data, OSSL_PACKAGE " SSL read: %s, errno %d",
- ossl_strerror(sslerror, buf, sizeof(buf)),
+ failf(conn->data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d",
+ (sslerror ?
+ ossl_strerror(sslerror, buf, sizeof(buf)) :
+ SSL_ERROR_to_str(err)),
SOCKERRNO);
done = 1;
break;
if(data->set.verbose) {
#ifdef HAVE_SSL_GET_SHUTDOWN
- switch(SSL_get_shutdown(connssl->handle)) {
+ switch(SSL_get_shutdown(BACKEND->handle)) {
case SSL_SENT_SHUTDOWN:
infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
break;
#endif
}
- SSL_free(connssl->handle);
- connssl->handle = NULL;
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = NULL;
}
return retval;
}
-void Curl_ossl_session_free(void *ptr)
+static void Curl_ossl_session_free(void *ptr)
{
/* free the ID */
SSL_SESSION_free(ptr);
* This function is called when the 'data' struct is going away. Close
* down everything and free all resources!
*/
-void Curl_ossl_close_all(struct Curl_easy *data)
+static void Curl_ossl_close_all(struct Curl_easy *data)
{
#ifdef HAVE_OPENSSL_ENGINE_H
if(data->state.engine) {
numalts = sk_GENERAL_NAME_num(altnames);
/* loop through all alternatives - until a dnsmatch */
- for(i=0; (i < numalts) && !dnsmatched; i++) {
+ for(i = 0; (i < numalts) && !dnsmatched; i++) {
/* get a handle to alternative name number i */
const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
else {
/* we have to look to the last occurrence of a commonName in the
distinguished one to get the most significant one. */
- int j, i=-1;
+ int j, i = -1;
/* The following is done because of a bug in 0.9.6b */
X509_NAME *name = X509_get_subject_name(server_cert);
if(name)
- while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i))>=0)
- i=j;
+ while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0)
+ i = j;
/* we have the name entry and we will now convert this to a string
that we can use for comparison. Doing this we support BMPstring,
UTF8 etc. */
- if(i>=0) {
+ if(i >= 0) {
ASN1_STRING *tmp =
X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
j = ASN1_STRING_length(tmp);
if(j >= 0) {
- peer_CN = OPENSSL_malloc(j+1);
+ peer_CN = OPENSSL_malloc(j + 1);
if(peer_CN) {
memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j);
peer_CN[j] = '\0';
peer_CN = NULL;
else {
/* convert peer_CN from UTF8 */
- CURLcode rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN));
+ CURLcode rc = Curl_convert_from_utf8(data, (char *)peer_CN,
+ strlen((char *)peer_CN));
/* Curl_convert_from_utf8 calls failf if unsuccessful */
if(rc) {
OPENSSL_free(peer_CN);
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
- long len = SSL_get_tlsext_status_ocsp_resp(connssl->handle, &p);
+ long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &p);
if(!p) {
failf(data, "No OCSP response received");
goto end;
}
- ch = SSL_get_peer_cert_chain(connssl->handle);
- st = SSL_CTX_get_cert_store(connssl->ctx);
+ ch = SSL_get_peer_cert_chain(BACKEND->handle);
+ st = SSL_CTX_get_cert_store(BACKEND->ctx);
#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
- defined(LIBRESSL_VERSION_NUMBER))
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER <= 0x2040200fL))
/* The authorized responder cert in the OCSP response MUST be signed by the
peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert,
no problem, but if it's an intermediate cert OpenSSL has a bug where it
#ifdef HAS_NPN
/*
- * in is a list of lenght prefixed strings. this function has to select
+ * in is a list of length prefixed strings. this function has to select
* the protocol we want to use from the list and write its string into out.
*/
return "unknown";
}
+static CURLcode
+set_ssl_version_min_max(long *ctx_options, struct connectdata *conn,
+ int sockindex)
+{
+#if (OPENSSL_VERSION_NUMBER < 0x1000100FL) || !defined(TLS1_3_VERSION)
+ /* convoluted #if condition just to avoid compiler warnings on unused
+ variable */
+ struct Curl_easy *data = conn->data;
+#endif
+ long ssl_version = SSL_CONN_CONFIG(version);
+ long ssl_version_max = SSL_CONN_CONFIG(version_max);
+
+ if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) {
+ ssl_version_max = ssl_version << 16;
+ }
+
+ switch(ssl_version) {
+ case CURL_SSLVERSION_TLSv1_3:
+#ifdef TLS1_3_VERSION
+ {
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION);
+ *ctx_options |= SSL_OP_NO_TLSv1_2;
+ }
+#else
+ (void)sockindex;
+ failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ /* FALLTHROUGH */
+ case CURL_SSLVERSION_TLSv1_2:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ *ctx_options |= SSL_OP_NO_TLSv1_1;
+#else
+ failf(data, OSSL_PACKAGE " was built without TLS 1.2 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ /* FALLTHROUGH */
+ case CURL_SSLVERSION_TLSv1_1:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ *ctx_options |= SSL_OP_NO_TLSv1;
+#else
+ failf(data, OSSL_PACKAGE " was built without TLS 1.1 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ /* FALLTHROUGH */
+ case CURL_SSLVERSION_TLSv1_0:
+ *ctx_options |= SSL_OP_NO_SSLv2;
+ *ctx_options |= SSL_OP_NO_SSLv3;
+ break;
+ }
+
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_TLSv1_0:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ *ctx_options |= SSL_OP_NO_TLSv1_1;
+#endif
+ /* FALLTHROUGH */
+ case CURL_SSLVERSION_MAX_TLSv1_1:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ *ctx_options |= SSL_OP_NO_TLSv1_2;
+#endif
+ /* FALLTHROUGH */
+ case CURL_SSLVERSION_MAX_TLSv1_2:
+ case CURL_SSLVERSION_MAX_DEFAULT:
+#ifdef TLS1_3_VERSION
+ *ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
+ break;
+ case CURL_SSLVERSION_MAX_TLSv1_3:
+#ifdef TLS1_3_VERSION
+ break;
+#else
+ failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ }
+ return CURLE_OK;
+}
+
static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
{
CURLcode result = CURLE_OK;
X509_LOOKUP *lookup = NULL;
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- long ctx_options;
+ long ctx_options = 0;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
bool sni;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
+ char error_buffer[256];
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
return CURLE_SSL_CONNECT_ERROR;
}
- if(connssl->ctx)
- SSL_CTX_free(connssl->ctx);
- connssl->ctx = SSL_CTX_new(req_method);
+ if(BACKEND->ctx)
+ SSL_CTX_free(BACKEND->ctx);
+ BACKEND->ctx = SSL_CTX_new(req_method);
- if(!connssl->ctx) {
+ if(!BACKEND->ctx) {
failf(data, "SSL: couldn't create a context: %s",
- ERR_error_string(ERR_peek_error(), NULL));
+ ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
return CURLE_OUT_OF_MEMORY;
}
#ifdef SSL_MODE_RELEASE_BUFFERS
- SSL_CTX_set_mode(connssl->ctx, SSL_MODE_RELEASE_BUFFERS);
+ SSL_CTX_set_mode(BACKEND->ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
#ifdef SSL_CTRL_SET_MSG_CALLBACK
if(data->set.fdebug && data->set.verbose) {
/* the SSL trace callback is only used for verbose logging */
- SSL_CTX_set_msg_callback(connssl->ctx, ssl_tls_trace);
- SSL_CTX_set_msg_callback_arg(connssl->ctx, conn);
+ SSL_CTX_set_msg_callback(BACKEND->ctx, ssl_tls_trace);
+ SSL_CTX_set_msg_callback_arg(BACKEND->ctx, conn);
}
#endif
break;
case CURL_SSLVERSION_TLSv1_0:
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_SSLv3;
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- ctx_options |= SSL_OP_NO_TLSv1_1;
- ctx_options |= SSL_OP_NO_TLSv1_2;
-#ifdef TLS1_3_VERSION
- ctx_options |= SSL_OP_NO_TLSv1_3;
-#endif
-#endif
- break;
-
case CURL_SSLVERSION_TLSv1_1:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_SSLv3;
- ctx_options |= SSL_OP_NO_TLSv1;
- ctx_options |= SSL_OP_NO_TLSv1_2;
-#ifdef TLS1_3_VERSION
- ctx_options |= SSL_OP_NO_TLSv1_3;
-#endif
- break;
-#else
- failf(data, OSSL_PACKAGE " was built without TLS 1.1 support");
- return CURLE_NOT_BUILT_IN;
-#endif
-
case CURL_SSLVERSION_TLSv1_2:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_SSLv3;
- ctx_options |= SSL_OP_NO_TLSv1;
- ctx_options |= SSL_OP_NO_TLSv1_1;
-#ifdef TLS1_3_VERSION
- ctx_options |= SSL_OP_NO_TLSv1_3;
-#endif
- break;
-#else
- failf(data, OSSL_PACKAGE " was built without TLS 1.2 support");
- return CURLE_NOT_BUILT_IN;
-#endif
-
case CURL_SSLVERSION_TLSv1_3:
-#ifdef TLS1_3_VERSION
- SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION);
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_SSLv3;
- ctx_options |= SSL_OP_NO_TLSv1;
- ctx_options |= SSL_OP_NO_TLSv1_1;
- ctx_options |= SSL_OP_NO_TLSv1_2;
+ result = set_ssl_version_min_max(&ctx_options, conn, sockindex);
+ if(result != CURLE_OK)
+ return result;
break;
-#else
- failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
- return CURLE_NOT_BUILT_IN;
-#endif
case CURL_SSLVERSION_SSLv2:
#ifndef OPENSSL_NO_SSL2
return CURLE_SSL_CONNECT_ERROR;
}
- SSL_CTX_set_options(connssl->ctx, ctx_options);
+ SSL_CTX_set_options(BACKEND->ctx, ctx_options);
#ifdef HAS_NPN
if(conn->bits.tls_enable_npn)
- SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn);
+ SSL_CTX_set_next_proto_select_cb(BACKEND->ctx, select_next_proto_cb, conn);
#endif
#ifdef HAS_ALPN
unsigned char protocols[128];
#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
+ (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
/* expects length prefixed preference ordered list of protocols in wire
* format
*/
- SSL_CTX_set_alpn_protos(connssl->ctx, protocols, cur);
+ SSL_CTX_set_alpn_protos(BACKEND->ctx, protocols, cur);
}
#endif
if(ssl_cert || ssl_cert_type) {
- if(!cert_stuff(conn, connssl->ctx, ssl_cert, ssl_cert_type,
+ if(!cert_stuff(conn, BACKEND->ctx, ssl_cert, ssl_cert_type,
SSL_SET_OPTION(key), SSL_SET_OPTION(key_type),
SSL_SET_OPTION(key_passwd))) {
/* failf() is already done in cert_stuff() */
ciphers = SSL_CONN_CONFIG(cipher_list);
if(!ciphers)
ciphers = (char *)DEFAULT_CIPHER_SELECTION;
- if(!SSL_CTX_set_cipher_list(connssl->ctx, ciphers)) {
- failf(data, "failed setting cipher list: %s", ciphers);
- return CURLE_SSL_CIPHER;
+ if(ciphers) {
+ if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
+ failf(data, "failed setting cipher list: %s", ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ infof(data, "Cipher selection: %s\n", ciphers);
}
- infof(data, "Cipher selection: %s\n", ciphers);
#ifdef USE_TLS_SRP
if(ssl_authtype == CURL_TLSAUTH_SRP) {
infof(data, "Using TLS-SRP username: %s\n", ssl_username);
- if(!SSL_CTX_set_srp_username(connssl->ctx, ssl_username)) {
+ if(!SSL_CTX_set_srp_username(BACKEND->ctx, ssl_username)) {
failf(data, "Unable to set SRP user name");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!SSL_CTX_set_srp_password(connssl->ctx, SSL_SET_OPTION(password))) {
+ if(!SSL_CTX_set_srp_password(BACKEND->ctx, SSL_SET_OPTION(password))) {
failf(data, "failed setting SRP password");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(!SSL_CONN_CONFIG(cipher_list)) {
infof(data, "Setting cipher list SRP\n");
- if(!SSL_CTX_set_cipher_list(connssl->ctx, "SRP")) {
+ if(!SSL_CTX_set_cipher_list(BACKEND->ctx, "SRP")) {
failf(data, "failed setting SRP cipher list");
return CURLE_SSL_CIPHER;
}
#endif
if(ssl_cafile || ssl_capath) {
- /* tell SSL where to find CA certificates that are used to verify
- the servers certificate. */
- if(!SSL_CTX_load_verify_locations(connssl->ctx, ssl_cafile, ssl_capath)) {
- if(verifypeer) {
+ if(verifypeer) {
+ /* tell SSL where to find CA certificates that are used to verify
+ the servers 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:\n"
" CAfile: %s\n CApath: %s",
return CURLE_SSL_CACERT_BADFILE;
}
else {
- /* Just continue with a warning if no strict certificate verification
- is required. */
- infof(data, "error setting certificate verify locations,"
- " continuing anyway:\n");
+ /* Everything is fine. */
+ infof(data, "successfully set certificate verify locations:\n"
+ " CAfile: %s\n CApath: %s\n",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
}
}
else {
- /* Everything is fine. */
- infof(data, "successfully set certificate verify locations:\n");
+ infof(data, "ignoring certificate verify locations due to "
+ "disabled peer verification\n");
}
- infof(data,
- " CAfile: %s\n"
- " CApath: %s\n",
- ssl_cafile ? ssl_cafile : "none",
- ssl_capath ? ssl_capath : "none");
}
#ifdef CURL_CA_FALLBACK
else if(verifypeer) {
/* verfying the peer without any CA certificates won't
work so use openssl's built in default as fallback */
- SSL_CTX_set_default_verify_paths(connssl->ctx);
+ SSL_CTX_set_default_verify_paths(BACKEND->ctx);
}
#endif
if(ssl_crlfile) {
/* tell SSL where to find CRL file that is used to check certificate
* revocation */
- lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx),
+ 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;
}
- else {
- /* Everything is fine. */
- infof(data, "successfully load CRL file:\n");
- X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
- X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
- }
+ /* Everything is fine. */
+ infof(data, "successfully load CRL file:\n");
+ 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\n", ssl_crlfile);
}
*/
#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS)
if(verifypeer) {
- X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
+ X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx),
X509_V_FLAG_TRUSTED_FIRST);
}
#endif
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
- SSL_CTX_set_verify(connssl->ctx,
+ SSL_CTX_set_verify(BACKEND->ctx,
verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
+ /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */
+#if defined(ENABLE_SSLKEYLOGFILE) && defined(HAVE_KEYLOG_CALLBACK)
+ if(keylog_file_fp) {
+ SSL_CTX_set_keylog_callback(BACKEND->ctx, ossl_keylog_callback);
+ }
+#endif
+
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
- result = (*data->set.ssl.fsslctx)(data, connssl->ctx,
+ result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx,
data->set.ssl.fsslctxp);
if(result) {
failf(data, "error signaled by ssl ctx callback");
}
/* Lets make an SSL structure */
- if(connssl->handle)
- SSL_free(connssl->handle);
- connssl->handle = SSL_new(connssl->ctx);
- if(!connssl->handle) {
+ if(BACKEND->handle)
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = SSL_new(BACKEND->ctx);
+ if(!BACKEND->handle) {
failf(data, "SSL: couldn't create a context (handle)!");
return CURLE_OUT_OF_MEMORY;
}
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
if(SSL_CONN_CONFIG(verifystatus))
- SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp);
+ SSL_set_tlsext_status_type(BACKEND->handle, TLSEXT_STATUSTYPE_ocsp);
#endif
- SSL_set_connect_state(connssl->handle);
+ SSL_set_connect_state(BACKEND->handle);
- connssl->server_cert = 0x0;
+ BACKEND->server_cert = 0x0;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
#ifdef ENABLE_IPV6
(0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
#endif
sni &&
- !SSL_set_tlsext_host_name(connssl->handle, hostname))
+ !SSL_set_tlsext_host_name(BACKEND->handle, hostname))
infof(data, "WARNING: failed to configure server name indication (SNI) "
"TLS extension\n");
#endif
/* Check if there's a cached ID we can/should use here! */
- if(data->set.general_ssl.sessionid) {
+ if(SSL_SET_OPTION(primary.sessionid)) {
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
/* we got a session id, use it! */
- if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
+ if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "SSL: SSL_set_session failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
if(conn->proxy_ssl[sockindex].use) {
BIO *const bio = BIO_new(BIO_f_ssl());
+ SSL *handle = conn->proxy_ssl[sockindex].backend->handle;
DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
- DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL);
+ DEBUGASSERT(handle != NULL);
DEBUGASSERT(bio != NULL);
- BIO_set_ssl(bio, conn->proxy_ssl[sockindex].handle, FALSE);
- SSL_set_bio(connssl->handle, bio, bio);
+ BIO_set_ssl(bio, handle, FALSE);
+ SSL_set_bio(BACKEND->handle, bio, bio);
}
- else if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
+ else if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) {
/* pass the raw socket into the SSL layers */
failf(data, "SSL: SSL_set_fd failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
ERR_clear_error();
- err = SSL_connect(connssl->handle);
+ err = SSL_connect(BACKEND->handle);
+ /* If keylogging is enabled but the keylog callback is not supported then log
+ secrets here, immediately after SSL_connect by using tap_ssl_key. */
+#if defined(ENABLE_SSLKEYLOGFILE) && !defined(HAVE_KEYLOG_CALLBACK)
+ tap_ssl_key(BACKEND->handle, &BACKEND->tap_state);
+#endif
/* 1 is fine
0 is "not successful but was shut down controlled"
<0 is "handshake was not successful, because a fatal error occurred" */
if(1 != err) {
- int detail = SSL_get_error(connssl->handle, err);
+ int detail = SSL_get_error(BACKEND->handle, err);
if(SSL_ERROR_WANT_READ == detail) {
connssl->connecting_state = ssl_connect_2_reading;
return CURLE_OK;
}
- else if(SSL_ERROR_WANT_WRITE == detail) {
+ if(SSL_ERROR_WANT_WRITE == detail) {
connssl->connecting_state = ssl_connect_2_writing;
return CURLE_OK;
}
else {
/* untreated error */
unsigned long errdetail;
- char error_buffer[256]=""; /* OpenSSL documents that this must be at
- least 256 bytes long. */
+ char error_buffer[256]="";
CURLcode result;
long lerr;
int lib;
(reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) {
result = CURLE_SSL_CACERT;
- lerr = SSL_get_verify_result(connssl->handle);
+ lerr = SSL_get_verify_result(BACKEND->handle);
if(lerr != X509_V_OK) {
*certverifyresult = lerr;
snprintf(error_buffer, sizeof(error_buffer),
const char * const hostname = SSL_IS_PROXY() ?
conn->http_proxy.host.name : conn->host.name;
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
- failf(data, "Unknown SSL protocol error in connection to %s:%ld ",
- hostname, port);
+ failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%ld ",
+ SSL_ERROR_to_str(detail), hostname, port);
return result;
}
/* Informational message */
infof(data, "SSL connection using %s / %s\n",
- get_ssl_version_txt(connssl->handle),
- SSL_get_cipher(connssl->handle));
+ get_ssl_version_txt(BACKEND->handle),
+ SSL_get_cipher(BACKEND->handle));
#ifdef HAS_ALPN
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
if(conn->bits.tls_enable_alpn) {
const unsigned char *neg_protocol;
unsigned int len;
- SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len);
+ SSL_get0_alpn_selected(BACKEND->handle, &neg_protocol, &len);
if(len != 0) {
infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol);
do { \
long info_len = BIO_get_mem_data(mem, &ptr); \
Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
- if(1!=BIO_reset(mem)) \
+ if(1 != BIO_reset(mem)) \
break; \
} WHILE_FALSE
/* no extensions, bail out */
return 1;
- for(i=0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
+ for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
ASN1_OBJECT *obj;
X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
BUF_MEM *biomem;
char buf[512];
- char *ptr=buf;
+ char *ptr = buf;
char namebuf[128];
BIO *bio_out = BIO_new(BIO_s_mem());
BIO_get_mem_ptr(bio_out, &biomem);
for(j = 0; j < (size_t)biomem->length; j++) {
- const char *sep="";
+ const char *sep = "";
if(biomem->data[j] == '\n') {
- sep=", ";
+ sep = ", ";
j++; /* skip the newline */
};
while((j<(size_t)biomem->length) && (biomem->data[j] == ' '))
j++;
if(j<(size_t)biomem->length)
- ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
- biomem->data[j]);
+ ptr += snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
+ biomem->data[j]);
}
Curl_ssl_push_certinfo(data, certnum, namebuf, buf);
int numcerts;
BIO *mem;
- sk = SSL_get_peer_cert_chain(connssl->handle);
+ sk = SSL_get_peer_cert_chain(BACKEND->handle);
if(!sk) {
return CURLE_OUT_OF_MEMORY;
}
for(i = 0; i < numcerts; i++) {
ASN1_INTEGER *num;
X509 *x = sk_X509_value(sk, i);
- EVP_PKEY *pubkey=NULL;
+ EVP_PKEY *pubkey = NULL;
int j;
char *ptr;
- CONST_ASN1_BIT_STRING ASN1_BIT_STRING *psig = NULL;
+ const ASN1_BIT_STRING *psig = NULL;
X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
push_certinfo("Subject", i);
{
const BIGNUM *n;
const BIGNUM *e;
- const BIGNUM *d;
- const BIGNUM *p;
- const BIGNUM *q;
- const BIGNUM *dmp1;
- const BIGNUM *dmq1;
- const BIGNUM *iqmp;
- RSA_get0_key(rsa, &n, &e, &d);
- RSA_get0_factors(rsa, &p, &q);
- RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
+ RSA_get0_key(rsa, &n, &e, NULL);
BN_print(mem, n);
push_certinfo("RSA Public Key", i);
print_pubkey_BN(rsa, n, i);
print_pubkey_BN(rsa, e, i);
- print_pubkey_BN(rsa, d, i);
- print_pubkey_BN(rsa, p, i);
- print_pubkey_BN(rsa, q, i);
- print_pubkey_BN(rsa, dmp1, i);
- print_pubkey_BN(rsa, dmq1, i);
- print_pubkey_BN(rsa, iqmp, i);
}
#else
BIO_printf(mem, "%d", BN_num_bits(rsa->n));
push_certinfo("RSA Public Key", i);
print_pubkey_BN(rsa, n, i);
print_pubkey_BN(rsa, e, i);
- print_pubkey_BN(rsa, d, i);
- print_pubkey_BN(rsa, p, i);
- print_pubkey_BN(rsa, q, i);
- print_pubkey_BN(rsa, dmp1, i);
- print_pubkey_BN(rsa, dmq1, i);
- print_pubkey_BN(rsa, iqmp, i);
#endif
break;
}
case EVP_PKEY_DSA:
{
+#ifndef OPENSSL_NO_DSA
DSA *dsa;
#ifdef HAVE_OPAQUE_EVP_PKEY
dsa = EVP_PKEY_get0_DSA(pubkey);
const BIGNUM *p;
const BIGNUM *q;
const BIGNUM *g;
- const BIGNUM *priv_key;
const BIGNUM *pub_key;
DSA_get0_pqg(dsa, &p, &q, &g);
- DSA_get0_key(dsa, &pub_key, &priv_key);
+ DSA_get0_key(dsa, &pub_key, NULL);
print_pubkey_BN(dsa, p, i);
print_pubkey_BN(dsa, q, i);
print_pubkey_BN(dsa, g, i);
- print_pubkey_BN(dsa, priv_key, i);
print_pubkey_BN(dsa, pub_key, i);
}
#else
print_pubkey_BN(dsa, p, i);
print_pubkey_BN(dsa, q, i);
print_pubkey_BN(dsa, g, i);
- print_pubkey_BN(dsa, priv_key, i);
print_pubkey_BN(dsa, pub_key, i);
#endif
+#endif /* !OPENSSL_NO_DSA */
break;
}
case EVP_PKEY_DH:
const BIGNUM *p;
const BIGNUM *q;
const BIGNUM *g;
- const BIGNUM *priv_key;
const BIGNUM *pub_key;
DH_get0_pqg(dh, &p, &q, &g);
- DH_get0_key(dh, &pub_key, &priv_key);
+ DH_get0_key(dh, &pub_key, NULL);
print_pubkey_BN(dh, p, i);
print_pubkey_BN(dh, q, i);
print_pubkey_BN(dh, g, i);
- print_pubkey_BN(dh, priv_key, i);
print_pubkey_BN(dh, pub_key, i);
}
#else
print_pubkey_BN(dh, p, i);
print_pubkey_BN(dh, g, i);
- print_pubkey_BN(dh, priv_key, i);
print_pubkey_BN(dh, pub_key, i);
#endif
break;
struct Curl_easy *data = conn->data;
X509 *issuer;
FILE *fp;
- char *buffer = data->state.buffer;
+ char buffer[2048];
const char *ptr;
long * const certverifyresult = SSL_IS_PROXY() ?
&data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
/* we've been asked to gather certificate info! */
(void)get_cert_chain(conn, connssl);
- connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
- if(!connssl->server_cert) {
+ BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle);
+ if(!BACKEND->server_cert) {
+ BIO_free(mem);
if(!strict)
return CURLE_OK;
infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server");
- rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
- buffer, BUFSIZE);
+ rc = x509_name_oneline(X509_get_subject_name(BACKEND->server_cert),
+ buffer, sizeof(buffer));
infof(data, " subject: %s\n", rc?"[NONE]":buffer);
- ASN1_TIME_print(mem, X509_get0_notBefore(connssl->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notBefore(BACKEND->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " start date: %.*s\n", len, ptr);
- rc = BIO_reset(mem);
+ (void)BIO_reset(mem);
- ASN1_TIME_print(mem, X509_get0_notAfter(connssl->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notAfter(BACKEND->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " expire date: %.*s\n", len, ptr);
- rc = BIO_reset(mem);
+ (void)BIO_reset(mem);
BIO_free(mem);
if(SSL_CONN_CONFIG(verifyhost)) {
- result = verifyhost(conn, connssl->server_cert);
+ result = verifyhost(conn, BACKEND->server_cert);
if(result) {
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
return result;
}
}
- rc = x509_name_oneline(X509_get_issuer_name(connssl->server_cert),
- buffer, BUFSIZE);
+ rc = x509_name_oneline(X509_get_issuer_name(BACKEND->server_cert),
+ buffer, sizeof(buffer));
if(rc) {
if(strict)
failf(data, "SSL: couldn't get X509-issuer name!");
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
SSL_SET_OPTION(issuercert));
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
if(strict)
failf(data, "SSL: Unable to read issuer cert (%s)",
SSL_SET_OPTION(issuercert));
- X509_free(connssl->server_cert);
+ X509_free(BACKEND->server_cert);
X509_free(issuer);
fclose(fp);
return CURLE_SSL_ISSUER_ERROR;
fclose(fp);
- if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) {
+ if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
SSL_SET_OPTION(issuercert));
- X509_free(connssl->server_cert);
+ X509_free(BACKEND->server_cert);
X509_free(issuer);
- connssl->server_cert = NULL;
+ BACKEND->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
X509_free(issuer);
}
- lerr = *certverifyresult = SSL_get_verify_result(connssl->handle);
+ lerr = *certverifyresult = SSL_get_verify_result(BACKEND->handle);
if(*certverifyresult != X509_V_OK) {
if(SSL_CONN_CONFIG(verifypeer)) {
if(SSL_CONN_CONFIG(verifystatus)) {
result = verifystatus(conn, connssl);
if(result) {
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
return result;
}
}
ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
if(!result && ptr) {
- result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr);
+ result = pkp_pin_peer_pubkey(data, BACKEND->server_cert, ptr);
if(result)
failf(data, "SSL: public key does not match pinned public key!");
}
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
connssl->connecting_state = ssl_connect_done;
return result;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
- if(data->set.general_ssl.sessionid) {
+ if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
SSL_SESSION *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
- our_ssl_sessionid = SSL_get1_session(connssl->handle);
+ our_ssl_sessionid = SSL_get1_session(BACKEND->handle);
/* SSL_get1_session() will increment the reference count and the session
will stay in memory until explicitly freed with SSL_SESSION_free(3),
if(connssl->connecting_state == ssl_connect_2_reading ||
connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = ssl_connect_2_writing==
+ curl_socket_t writefd = ssl_connect_2_writing ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
+ curl_socket_t readfd = ssl_connect_2_reading ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
return CURLE_SSL_CONNECT_ERROR;
}
- else if(0 == what) {
+ if(0 == what) {
if(nonblocking) {
*done = FALSE;
return CURLE_OK;
}
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
}
/* socket is readable or writable */
}
return CURLE_OK;
}
-CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
+static CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
{
return ossl_connect_common(conn, sockindex, TRUE, done);
}
-CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
+static CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
bool done = FALSE;
return CURLE_OK;
}
-bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex)
+static bool Curl_ossl_data_pending(const struct connectdata *conn,
+ int connindex)
{
- if(conn->ssl[connindex].handle)
- /* SSL is in use */
- return (0 != SSL_pending(conn->ssl[connindex].handle) ||
- (conn->proxy_ssl[connindex].handle &&
- 0 != SSL_pending(conn->proxy_ssl[connindex].handle))) ?
- TRUE : FALSE;
- else
- return FALSE;
+ const struct ssl_connect_data *connssl = &conn->ssl[connindex];
+ const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex];
+
+ if(connssl->backend->handle && SSL_pending(connssl->backend->handle))
+ return TRUE;
+
+ if(proxyssl->backend->handle && SSL_pending(proxyssl->backend->handle))
+ return TRUE;
+
+ return FALSE;
}
+static size_t Curl_ossl_version(char *buffer, size_t size);
+
static ssize_t ossl_send(struct connectdata *conn,
int sockindex,
const void *mem,
/* SSL_write() is said to return 'int' while write() and send() returns
'size_t' */
int err;
- char error_buffer[256]; /* OpenSSL documents that this must be at least 256
- bytes long. */
+ char error_buffer[256];
unsigned long sslerror;
int memlen;
int rc;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
ERR_clear_error();
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
+ rc = SSL_write(BACKEND->handle, mem, memlen);
if(rc <= 0) {
- err = SSL_get_error(conn->ssl[sockindex].handle, rc);
+ err = SSL_get_error(BACKEND->handle, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
return -1;
}
/* a true error */
- failf(conn->data, "SSL_write() return error %d", err);
+ failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d",
+ SSL_ERROR_to_str(err), SOCKERRNO);
*curlcode = CURLE_SEND_ERROR;
return -1;
}
size_t buffersize, /* max amount to read */
CURLcode *curlcode)
{
- char error_buffer[256]; /* OpenSSL documents that this must be at
- least 256 bytes long. */
+ char error_buffer[256];
unsigned long sslerror;
ssize_t nread;
int buffsize;
+ struct ssl_connect_data *connssl = &conn->ssl[num];
ERR_clear_error();
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize);
+ nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize);
if(nread <= 0) {
/* failed SSL_read */
- int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
+ int err = SSL_get_error(BACKEND->handle, (int)nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
if((nread < 0) || sslerror) {
/* If the return code was negative or there actually is an error in the
queue */
- failf(conn->data, "SSL read: %s, errno %d",
- ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)),
+ failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d",
+ (sslerror ?
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)) :
+ SSL_ERROR_to_str(err)),
SOCKERRNO);
*curlcode = CURLE_RECV_ERROR;
return -1;
return nread;
}
-size_t Curl_ossl_version(char *buffer, size_t size)
+static size_t Curl_ossl_version(char *buffer, size_t size)
{
#ifdef OPENSSL_IS_BORINGSSL
return snprintf(buffer, size, OSSL_PACKAGE);
unsigned long ssleay_value;
sub[2]='\0';
sub[1]='\0';
- ssleay_value=OpenSSL_version_num();
+ ssleay_value = OpenSSL_version_num();
if(ssleay_value < 0x906000) {
- ssleay_value=SSLEAY_VERSION_NUMBER;
+ ssleay_value = SSLEAY_VERSION_NUMBER;
sub[0]='\0';
}
else {
}
/* can be called with data == NULL */
-CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy,
- size_t length)
+static CURLcode Curl_ossl_random(struct Curl_easy *data,
+ unsigned char *entropy, size_t length)
{
int rc;
if(data) {
return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
}
-void Curl_ossl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum /* output */,
- size_t unused)
+static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum /* output */,
+ size_t unused)
{
- MD5_CTX MD5pw;
- (void)unused;
- MD5_Init(&MD5pw);
- MD5_Update(&MD5pw, tmp, tmplen);
- MD5_Final(md5sum, &MD5pw);
+ EVP_MD_CTX *mdctx;
+ unsigned int len = 0;
+ (void) unused;
+
+ mdctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
+ EVP_DigestUpdate(mdctx, tmp, tmplen);
+ EVP_DigestFinal_ex(mdctx, md5sum, &len);
+ EVP_MD_CTX_destroy(mdctx);
+ return CURLE_OK;
}
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum /* output */,
- size_t unused)
+static void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum /* output */,
+ size_t unused)
{
- SHA256_CTX SHA256pw;
- (void)unused;
- SHA256_Init(&SHA256pw);
- SHA256_Update(&SHA256pw, tmp, tmplen);
- SHA256_Final(sha256sum, &SHA256pw);
+ EVP_MD_CTX *mdctx;
+ unsigned int len = 0;
+ (void) unused;
+
+ mdctx = EVP_MD_CTX_create();
+ EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL);
+ EVP_DigestUpdate(mdctx, tmp, tmplen);
+ EVP_DigestFinal_ex(mdctx, sha256sum, &len);
+ EVP_MD_CTX_destroy(mdctx);
}
#endif
-bool Curl_ossl_cert_status_request(void)
+static bool Curl_ossl_cert_status_request(void)
{
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
return FALSE;
#endif
}
+
+static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info)
+{
+ /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
+ return info == CURLINFO_TLS_SESSION ?
+ (void *)BACKEND->ctx : (void *)BACKEND->handle;
+}
+
+const struct Curl_ssl Curl_ssl_openssl = {
+ { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
+
+ 1, /* have_ca_path */
+ 1, /* have_certinfo */
+ 1, /* have_pinnedpubkey */
+ 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 */
+ Curl_ossl_check_cxn, /* check_cxn */
+ Curl_ossl_shutdown, /* shutdown */
+ Curl_ossl_data_pending, /* data_pending */
+ Curl_ossl_random, /* random */
+ Curl_ossl_cert_status_request, /* cert_status_request */
+ Curl_ossl_connect, /* connect */
+ Curl_ossl_connect_nonblocking, /* connect_nonblocking */
+ Curl_ossl_get_internals, /* get_internals */
+ Curl_ossl_close, /* close_one */
+ Curl_ossl_close_all, /* close_all */
+ Curl_ossl_session_free, /* session_free */
+ Curl_ossl_set_engine, /* set_engine */
+ Curl_ossl_set_engine_default, /* set_engine_default */
+ Curl_ossl_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_ossl_md5sum, /* md5sum */
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+ Curl_ossl_sha256sum /* sha256sum */
+#else
+ NULL /* sha256sum */
+#endif
+};
+
#endif /* USE_OPENSSL */