vtls: add options to specify range of enabled TLS versions

This commit introduces the CURL_SSLVERSION_MAX_* constants as well as
the --tls-max option of the curl tool.

Closes https://github.com/curl/curl/pull/1166
This commit is contained in:
Jozef Kralik 2016-12-13 21:10:00 +01:00 committed by Kamil Dudka
parent b666907336
commit 6448f98c18
25 changed files with 781 additions and 227 deletions

View file

@ -695,6 +695,9 @@ CURLcode Curl_open(struct Curl_easy **curl)
return result;
}
#define C_SSLVERSION_VALUE(x) (x & 0xffff)
#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
va_list param)
{
@ -927,7 +930,9 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
* implementations are lame.
*/
#ifdef USE_SSL
data->set.ssl.primary.version = va_arg(param, long);
arg = va_arg(param, long);
data->set.ssl.primary.version = C_SSLVERSION_VALUE(arg);
data->set.ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
#else
result = CURLE_UNKNOWN_OPTION;
#endif
@ -938,7 +943,9 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
* implementations are lame.
*/
#ifdef USE_SSL
data->set.proxy_ssl.primary.version = va_arg(param, long);
arg = va_arg(param, long);
data->set.proxy_ssl.primary.version = C_SSLVERSION_VALUE(arg);
data->set.proxy_ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
#else
result = CURLE_UNKNOWN_OPTION;
#endif

View file

@ -350,6 +350,7 @@ struct ssl_connect_data {
struct ssl_primary_config {
long version; /* what version the client wants to use */
long version_max; /* max supported version the client wants to use*/
bool verifypeer; /* set TRUE if this is desired */
bool verifyhost; /* set TRUE if CN/SAN must match hostname */
bool verifystatus; /* set TRUE if certificate status must be checked */

View file

@ -156,6 +156,12 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
same connection */
return CURLE_OK;
if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
failf(data, "axtls does not support CURL_SSLVERSION_MAX");
return CURLE_SSL_CONNECT_ERROR;
}
/* axTLS only supports TLSv1 */
/* check to see if we've been told to use an explicit SSL/TLS version */
switch(SSL_CONN_CONFIG(version)) {

View file

@ -149,6 +149,11 @@ cyassl_connect_step1(struct connectdata *conn,
if(conssl->state == ssl_connection_complete)
return CURLE_OK;
if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
failf(data, "CyaSSL 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)) {
case CURL_SSLVERSION_DEFAULT:

View file

@ -1044,6 +1044,109 @@ CF_INLINE bool is_file(const char *filename)
return false;
}
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
static CURLcode darwinssl_version_from_curl(long *darwinver, long version)
{
switch(ssl_version) {
case CURL_SSLVERSION_TLSv1_0:
*darwinver = kTLSProtocol1;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1:
*darwinver = kTLSProtocol11;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_2:
*darwinver = kTLSProtocol12;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_3:
break;
}
return CURLE_SSL_CONNECT_ERROR;
}
#endif
static CURLcode
set_ssl_version_min_max(struct connectdata *conn, int sockindex)
{
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
switch(ssl_version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_version = CURL_SSLVERSION_TLSv1_0;
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
ssl_version_max = ssl_version << 16;
break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLSetProtocolVersionMax != NULL) {
SSLProtocol darwin_ver_min = kTLSProtocol1;
SSLProtocol darwin_ver_max = kTLSProtocol1;
CURLcode result = darwinssl_version_from_curl(&darwin_ver_min,
ssl_version);
if(result) {
failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
return result;
}
result = darwinssl_version_from_curl(&darwin_ver_max,
ssl_version_max >> 16);
if(result) {
failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
return result;
}
(void)SSLSetProtocolVersionMin(connssl->ssl_ctx, darwin_ver_min);
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, darwin_ver_max);
return result;
}
else {
#if CURL_SUPPORT_MAC_10_8
long i = ssl_version;
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kSSLProtocolAll,
false);
for(; i <= (ssl_version_max >> 16); i++) {
switch(i) {
case CURL_SSLVERSION_TLSv1_0:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol1,
true);
break;
case CURL_SSLVERSION_TLSv1_1:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol11,
true);
break;
case CURL_SSLVERSION_TLSv1_2:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol12,
true);
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "DarwinSSL: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
}
}
return CURLE_OK;
#endif /* CURL_SUPPORT_MAC_10_8 */
}
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
failf(data, "DarwinSSL: cannot set SSL protocol");
return CURLE_SSL_CONNECT_ERROR;
}
static CURLcode darwinssl_connect_step1(struct connectdata *conn,
int sockindex)
{
@ -1113,20 +1216,15 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
break;
case CURL_SSLVERSION_TLSv1_0:
(void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol1);
break;
case CURL_SSLVERSION_TLSv1_1:
(void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol11);
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol11);
break;
case CURL_SSLVERSION_TLSv1_2:
(void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol12);
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "DarwinSSL: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
{
CURLcode result = set_ssl_version_min_max(conn, sockindex);
if(result != CURLE_OK)
return result;
break;
}
case CURL_SSLVERSION_SSLv3:
err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3);
if(err != noErr) {
@ -1167,23 +1265,15 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
true);
break;
case CURL_SSLVERSION_TLSv1_0:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol1,
true);
break;
case CURL_SSLVERSION_TLSv1_1:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol11,
true);
break;
case CURL_SSLVERSION_TLSv1_2:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol12,
true);
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "DarwinSSL: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
{
CURLcode result = set_ssl_version_min_max(conn, sockindex);
if(result != CURLE_OK)
return result;
break;
}
case CURL_SSLVERSION_SSLv3:
err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kSSLProtocol3,
@ -1209,6 +1299,11 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#endif /* CURL_SUPPORT_MAC_10_8 */
}
#else
if(conn->ssl_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(connssl->ssl_ctx, kSSLProtocolAll, false);
switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:

View file

@ -748,6 +748,40 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
return (ssize_t) nread;
}
static CURLcode
set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
long i = ssl_version;
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
ssl_version_max = ssl_version;
break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_TLSv1_2;
break;
}
for(; i <= (ssl_version_max >> 16); ++i) {
switch(i) {
case CURL_SSLVERSION_TLSv1_0:
*protoflags |= CURL_GSKPROTO_TLSV10_MASK;
break;
case CURL_SSLVERSION_TLSv1_1:
*protoflags |= CURL_GSKPROTO_TLSV11_MASK;
break;
case CURL_SSLVERSION_TLSv1_2:
*protoflags |= CURL_GSKPROTO_TLSV11_MASK;
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "GSKit: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
}
}
return CURLE_OK;
}
static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
{
@ -764,7 +798,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
conn->host.name;
const char *sni;
unsigned int protoflags;
unsigned int protoflags = 0;
long timeout;
Qso_OverlappedIO_t commarea;
int sockpair[2];
@ -849,17 +883,13 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
break;
case CURL_SSLVERSION_TLSv1_0:
protoflags = CURL_GSKPROTO_TLSV10_MASK;
break;
case CURL_SSLVERSION_TLSv1_1:
protoflags = CURL_GSKPROTO_TLSV11_MASK;
break;
case CURL_SSLVERSION_TLSv1_2:
protoflags = CURL_GSKPROTO_TLSV12_MASK;
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "GSKit: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
result = set_ssl_version_min_max(&protoflags, conn);
if(result != CURLE_OK)
return result;
break;
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;

View file

@ -375,6 +375,100 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
return -1;
}
#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
static CURLcode
set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
long i = ssl_version;
long protocol_priority_idx = 0;
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
ssl_version_max = ssl_version << 16;
break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
for(; i <= (ssl_version_max >> 16) &&
protocol_priority_idx < list_size; ++i) {
switch(i) {
case CURL_SSLVERSION_TLSv1_0:
protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0;
break;
case CURL_SSLVERSION_TLSv1_1:
protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1;
break;
case CURL_SSLVERSION_TLSv1_2:
protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2;
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "GnuTLS: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
}
}
return CURLE_OK;
}
#else
#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
/* If GnuTLS was compiled without support for SRP it will error out if SRP is
requested in the priority string, so treat it specially
*/
#define GNUTLS_SRP "+SRP"
static CURLcode
set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
if(ssl_version == CURL_SSLVERSION_TLSv1_3 ||
ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) {
failf(data, "GnuTLS: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
}
if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) {
ssl_version_max = ssl_version << 16;
}
switch(ssl_version | ssl_version_max) {
case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.0:" GNUTLS_SRP;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2:
case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.1:" GNUTLS_SRP;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2:
case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2:
case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.2:" GNUTLS_SRP;
return CURLE_OK;
}
failf(data, "GnuTLS: cannot set ssl protocol");
return CURLE_SSL_CONNECT_ERROR;
}
#endif
static CURLcode
gtls_connect_step1(struct connectdata *conn,
int sockindex)
@ -406,13 +500,8 @@ gtls_connect_step1(struct connectdata *conn,
GNUTLS_CIPHER_3DES_CBC,
};
static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
static int protocol_priority[] = { 0, 0, 0, 0 };
int protocol_priority[] = { 0, 0, 0, 0 };
#else
#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
/* If GnuTLS was compiled without support for SRP it will error out if SRP is
requested in the priority string, so treat it specially
*/
#define GNUTLS_SRP "+SRP"
const char *prioritylist;
const char *err = NULL;
#endif
@ -576,7 +665,7 @@ gtls_connect_step1(struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}
switch(SSL_CONN_CONFIG(version) {
switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_SSLv3:
protocol_priority[0] = GNUTLS_SSL3;
break;
@ -587,17 +676,16 @@ gtls_connect_step1(struct connectdata *conn,
protocol_priority[2] = GNUTLS_TLS1_2;
break;
case CURL_SSLVERSION_TLSv1_0:
protocol_priority[0] = GNUTLS_TLS1_0;
break;
case CURL_SSLVERSION_TLSv1_1:
protocol_priority[0] = GNUTLS_TLS1_1;
break;
case CURL_SSLVERSION_TLSv1_2:
protocol_priority[0] = GNUTLS_TLS1_2;
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "GnuTLS: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
{
CURLcode result = set_ssl_version_min_max(protocol_priority,
sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn);
if(result != CURLE_OK)
return result;
break;
}
case CURL_SSLVERSION_SSLv2:
failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
@ -625,20 +713,15 @@ gtls_connect_step1(struct connectdata *conn,
prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
break;
case CURL_SSLVERSION_TLSv1_0:
prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.0:" GNUTLS_SRP;
break;
case CURL_SSLVERSION_TLSv1_1:
prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.1:" GNUTLS_SRP;
break;
case CURL_SSLVERSION_TLSv1_2:
prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.2:" GNUTLS_SRP;
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "GnuTLS: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
{
CURLcode result = set_ssl_version_min_max(&prioritylist, conn);
if(result != CURLE_OK)
return result;
break;
}
case CURL_SSLVERSION_SSLv2:
failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;

View file

@ -157,6 +157,71 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
static Curl_recv mbed_recv;
static Curl_send mbed_send;
static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
{
switch(ssl_version) {
case CURL_SSLVERSION_TLSv1_0:
*mbedver = MBEDTLS_SSL_MINOR_VERSION_1;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1:
*mbedver = MBEDTLS_SSL_MINOR_VERSION_2;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_2:
*mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_3:
break;
}
return CURLE_SSL_CONNECT_ERROR;
}
static CURLcode
set_ssl_version_min_max(struct connectdata *conn, int sockindex)
{
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
CURLcode result = CURLE_OK;
switch(ssl_version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_version = CURL_SSLVERSION_TLSv1_0;
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
ssl_version_max = ssl_version << 16;
break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version);
if(result) {
failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
return result;
}
result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16);
if(result) {
failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
return result;
}
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
mbedtls_ver_min);
mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
mbedtls_ver_max);
return result;
}
static CURLcode
mbed_connect_step1(struct connectdata *conn,
int sockindex)
@ -333,29 +398,15 @@ mbed_connect_step1(struct connectdata *conn,
infof(data, "mbedTLS: Set SSL version to SSLv3\n");
break;
case CURL_SSLVERSION_TLSv1_0:
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_1);
mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_1);
infof(data, "mbedTLS: Set SSL version to TLS 1.0\n");
break;
case CURL_SSLVERSION_TLSv1_1:
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_2);
mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_2);
infof(data, "mbedTLS: Set SSL version to TLS 1.1\n");
break;
case CURL_SSLVERSION_TLSv1_2:
mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_3);
mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_3);
infof(data, "mbedTLS: Set SSL version to TLS 1.2\n");
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "mbedTLS: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
{
CURLcode result = set_ssl_version_min_max(conn, sockindex);
if(result != CURLE_OK)
return result;
break;
}
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;

View file

@ -1512,78 +1512,108 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
return CURLE_OK;
}
static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
{
switch(version) {
case CURL_SSLVERSION_TLSv1:
/* TODO: set sslver->max to SSL_LIBRARY_VERSION_TLS_1_3 once stable */
#ifdef SSL_LIBRARY_VERSION_TLS_1_2
*nssver = SSL_LIBRARY_VERSION_TLS_1_2;
#elif defined SSL_LIBRARY_VERSION_TLS_1_1
*nssver = SSL_LIBRARY_VERSION_TLS_1_1;
#else
*nssver = SSL_LIBRARY_VERSION_TLS_1_0;
#endif
return CURLE_OK;
case CURL_SSLVERSION_SSLv2:
*nssver = SSL_LIBRARY_VERSION_2;
return CURLE_OK;
case CURL_SSLVERSION_SSLv3:
*nssver = SSL_LIBRARY_VERSION_3_0;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_0:
*nssver = SSL_LIBRARY_VERSION_TLS_1_0;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1:
#ifdef SSL_LIBRARY_VERSION_TLS_1_1
*nssver = SSL_LIBRARY_VERSION_TLS_1_1;
return CURLE_OK;
#else
return CURLE_SSL_CONNECT_ERROR;
#endif
case CURL_SSLVERSION_TLSv1_2:
#ifdef SSL_LIBRARY_VERSION_TLS_1_2
*nssver = SSL_LIBRARY_VERSION_TLS_1_2;
return CURLE_OK;
#else
return CURLE_SSL_CONNECT_ERROR;
#endif
case CURL_SSLVERSION_TLSv1_3:
#ifdef SSL_LIBRARY_VERSION_TLS_1_3
*nssver = SSL_LIBRARY_VERSION_TLS_1_3;
return CURLE_OK;
#else
return CURLE_SSL_CONNECT_ERROR;
#endif
default:
return CURLE_SSL_CONNECT_ERROR;
}
}
static CURLcode nss_init_sslver(SSLVersionRange *sslver,
struct Curl_easy *data,
struct connectdata *conn)
{
switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
CURLcode result;
const long min = SSL_CONN_CONFIG(version);
const long max = SSL_CONN_CONFIG(version_max);
/* map CURL_SSLVERSION_DEFAULT to NSS default */
if(min == CURL_SSLVERSION_DEFAULT || max == CURL_SSLVERSION_MAX_DEFAULT) {
/* map CURL_SSLVERSION_DEFAULT to NSS default */
if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess)
return CURLE_SSL_CONNECT_ERROR;
/* ... but make sure we use at least TLSv1.0 according to libcurl API */
if(sslver->min < SSL_LIBRARY_VERSION_TLS_1_0)
sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1:
sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
/* TODO: set sslver->max to SSL_LIBRARY_VERSION_TLS_1_3 once stable */
#ifdef SSL_LIBRARY_VERSION_TLS_1_2
sslver->max = SSL_LIBRARY_VERSION_TLS_1_2;
#elif defined SSL_LIBRARY_VERSION_TLS_1_1
sslver->max = SSL_LIBRARY_VERSION_TLS_1_1;
#else
sslver->max = SSL_LIBRARY_VERSION_TLS_1_0;
#endif
return CURLE_OK;
case CURL_SSLVERSION_SSLv2:
sslver->min = SSL_LIBRARY_VERSION_2;
sslver->max = SSL_LIBRARY_VERSION_2;
return CURLE_OK;
case CURL_SSLVERSION_SSLv3:
sslver->min = SSL_LIBRARY_VERSION_3_0;
sslver->max = SSL_LIBRARY_VERSION_3_0;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_0:
sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
sslver->max = SSL_LIBRARY_VERSION_TLS_1_0;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1:
#ifdef SSL_LIBRARY_VERSION_TLS_1_1
sslver->min = SSL_LIBRARY_VERSION_TLS_1_1;
sslver->max = SSL_LIBRARY_VERSION_TLS_1_1;
return CURLE_OK;
#endif
break;
case CURL_SSLVERSION_TLSv1_2:
#ifdef SSL_LIBRARY_VERSION_TLS_1_2
sslver->min = SSL_LIBRARY_VERSION_TLS_1_2;
sslver->max = SSL_LIBRARY_VERSION_TLS_1_2;
return CURLE_OK;
#endif
break;
case CURL_SSLVERSION_TLSv1_3:
#ifdef SSL_LIBRARY_VERSION_TLS_1_3
sslver->min = SSL_LIBRARY_VERSION_TLS_1_3;
sslver->max = SSL_LIBRARY_VERSION_TLS_1_3;
return CURLE_OK;
#endif
break;
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
}
failf(data, "TLS minor version cannot be set");
return CURLE_SSL_CONNECT_ERROR;
switch(min) {
case CURL_SSLVERSION_DEFAULT:
break;
case CURL_SSLVERSION_TLSv1:
sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
break;
default:
result = nss_sslver_from_curl(&sslver->min, min);
if(result) {
failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
return result;
}
if(max == CURL_SSLVERSION_MAX_NONE)
sslver->max = sslver->min;
}
switch(max) {
case CURL_SSLVERSION_MAX_NONE:
case CURL_SSLVERSION_MAX_DEFAULT:
break;
default:
result = nss_sslver_from_curl(&sslver->max, max >> 16);
if(result) {
failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
return result;
}
}
return CURLE_OK;
}
static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,

View file

@ -1692,6 +1692,71 @@ get_ssl_version_txt(SSL *ssl)
return "unknown";
}
static CURLcode
set_ssl_version_min_max(long *ctx_options, struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
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
SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION);
*ctx_options |= SSL_OP_NO_TLSv1_2;
#else
failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
return CURLE_NOT_BUILT_IN;
#endif
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
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
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
case CURL_SSLVERSION_MAX_TLSv1_1:
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_2;
#endif
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;
@ -1701,7 +1766,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
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;
#ifdef ENABLE_IPV6
@ -1888,60 +1953,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
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);
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

View file

@ -140,6 +140,68 @@ static void polarssl_debug(void *context, int level, const char *line)
static Curl_recv polarssl_recv;
static Curl_send polarssl_send;
static CURLcode polarssl_version_from_curl(int *polarver, long version)
{
switch(ssl_version) {
case CURL_SSLVERSION_TLSv1_0:
*polarver = SSL_MINOR_VERSION_1;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1:
*polarver = SSL_MINOR_VERSION_2;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_2:
*polarver = SSL_MINOR_VERSION_3;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_3:
break;
}
return CURLE_SSL_CONNECT_ERROR;
}
static CURLcode
set_ssl_version_min_max(struct connectdata *conn, int sockindex);
{
struct Curl_easy *data = conn->data;
struct ssl_connect_data* connssl = &conn->ssl[sockindex];
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
int ssl_min_ver = SSL_MINOR_VERSION_1;
int ssl_max_ver = SSL_MINOR_VERSION_1;
CURLcode result = CURLE_OK;
switch(ssl_version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_version = CURL_SSLVERSION_TLSv1_0;
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
ssl_version_max = ssl_version << 16;
break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
result = polarssl_version_from_curl(&ssl_min_ver, ssl_version);
if(result) {
failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
return result;
}
result = polarssl_version_from_curl(&ssl_max_ver, ssl_version_max >> 16);
if(result) {
failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
return result;
}
ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver);
ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver);
return result;
}
static CURLcode
polarssl_connect_step1(struct connectdata *conn,
@ -287,29 +349,15 @@ polarssl_connect_step1(struct connectdata *conn,
infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n");
break;
case CURL_SSLVERSION_TLSv1_0:
ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
SSL_MINOR_VERSION_1);
ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
SSL_MINOR_VERSION_1);
infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.0\n");
break;
case CURL_SSLVERSION_TLSv1_1:
ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
SSL_MINOR_VERSION_2);
ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
SSL_MINOR_VERSION_2);
infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.1\n");
break;
case CURL_SSLVERSION_TLSv1_2:
ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
SSL_MINOR_VERSION_3);
ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
SSL_MINOR_VERSION_3);
infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.2\n");
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "PolarSSL: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
{
CURLcode result = set_ssl_version_min_max(conn, sockindex);
if(result != CURLE_OK)
return result;
break;
}
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;

View file

@ -102,6 +102,41 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
desc->cBuffers = NumArrElem;
}
static CURLcode
set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
long i = ssl_version;
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
ssl_version_max = ssl_version << 16;
break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
for(; i <= (ssl_version_max >> 16); ++i) {
switch(i) {
case CURL_SSLVERSION_TLSv1_0:
schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_1:
schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_2:
schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "Schannel: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
}
}
return CURLE_OK;
}
static CURLcode
schannel_connect_step1(struct connectdata *conn, int sockindex)
{
@ -216,17 +251,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
SP_PROT_TLS1_2_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_0:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_1:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_2:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_3:
failf(data, "Schannel: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
{
CURLcode result = set_ssl_version_min_max(&schannel_cred, conn);
if(result != CURLE_OK)
return result;
break;
}
case CURL_SSLVERSION_SSLv3:
schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
break;

View file

@ -95,6 +95,7 @@ Curl_ssl_config_matches(struct ssl_primary_config* data,
struct ssl_primary_config* needle)
{
if((data->version == needle->version) &&
(data->version_max == needle->version_max) &&
(data->verifypeer == needle->verifypeer) &&
(data->verifyhost == needle->verifyhost) &&
Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
@ -113,6 +114,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
dest->verifyhost = source->verifyhost;
dest->verifypeer = source->verifypeer;
dest->version = source->version;
dest->version_max = source->version_max;
CLONE_STRING(CAfile);
CLONE_STRING(CApath);
@ -173,11 +175,24 @@ void Curl_ssl_cleanup(void)
static bool ssl_prefs_check(struct Curl_easy *data)
{
/* check for CURLOPT_SSLVERSION invalid parameter value */
if((data->set.ssl.primary.version < 0)
|| (data->set.ssl.primary.version >= CURL_SSLVERSION_LAST)) {
const long sslver = data->set.ssl.primary.version;
if((sslver < 0) || (sslver >= CURL_SSLVERSION_LAST)) {
failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
return FALSE;
}
switch(data->set.ssl.primary.version_max) {
case CURL_SSLVERSION_MAX_NONE:
case CURL_SSLVERSION_MAX_DEFAULT:
break;
default:
if((data->set.ssl.primary.version_max >> 16) < sslver) {
failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION");
return FALSE;
}
}
return TRUE;
}