1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

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

@ -0,0 +1,24 @@
Long: tls-max
Arg: <VERSION>
Tags: Versions
Protocols: SSL
Added: 7.54.0
Requires: TLS
See-also: tlsv1.0 tlsv1.1 tlsv1.2
Help: Use TLSv1.0 or greater
---
VERSION defines maximum supported TLS version. A minimum is defined
by arguments tlsv1.0 or tlsv1.1 or tlsv1.2.
.RS
.IP "default"
Use up to recommended TLS version.
.IP "1.0"
Use up to TLSv1.0.
.IP "1.1"
Use up to TLSv1.1.
.IP "1.2"
Use up to TLSv1.2.
.IP "1.3"
Use up to TLSv1.3.
.RE

View File

@ -46,6 +46,23 @@ TLSv1.1
TLSv1.2 TLSv1.2
.IP CURL_SSLVERSION_TLSv1_3 .IP CURL_SSLVERSION_TLSv1_3
TLSv1.3 TLSv1.3
.IP CURL_SSLVERSION_MAX_DEFAULT
The flag defines maximum supported TLS version as TLSv1.2 or default
value from SSL library. Only library NSS currently allows to get
maximum supported TLS version.
(Added in 7.54.0)
.IP CURL_SSLVERSION_MAX_TLSv1_0
The flag defines maximum supported TLS version as TLSv1.0.
(Added in 7.54.0)
.IP CURL_SSLVERSION_MAX_TLSv1_1
The flag defines maximum supported TLS version as TLSv1.1.
(Added in 7.54.0)
.IP CURL_SSLVERSION_MAX_TLSv1_2
The flag defines maximum supported TLS version as TLSv1.2.
(Added in 7.54.0)
.IP CURL_SSLVERSION_MAX_TLSv1_3
The flag defines maximum supported TLS version as TLSv1.3.
(Added in 7.54.0)
.RE .RE
.SH DEFAULT .SH DEFAULT
CURL_SSLVERSION_DEFAULT CURL_SSLVERSION_DEFAULT
@ -58,7 +75,8 @@ if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
/* ask libcurl to use TLS version 1.0 or later */ /* ask libcurl to use TLS version 1.0 or later */
curl_easy_setopt(curl, CURLOPT_PROXY_SSLVERSION, CURL_SSLVERSION_TLSv1); curl_easy_setopt(curl, CURLOPT_PROXY_SSLVERSION, CURL_SSLVERSION_TLSv1_1 |
CURL_SSLVERSION_MAX_DEFAULT);
/* Perform the request */ /* Perform the request */
curl_easy_perform(curl); curl_easy_perform(curl);

View File

@ -50,6 +50,23 @@ TLSv1.1 (Added in 7.34.0)
TLSv1.2 (Added in 7.34.0) TLSv1.2 (Added in 7.34.0)
.IP CURL_SSLVERSION_TLSv1_3 .IP CURL_SSLVERSION_TLSv1_3
TLSv1.3 (Added in 7.52.0) TLSv1.3 (Added in 7.52.0)
.IP CURL_SSLVERSION_MAX_DEFAULT
The flag defines maximum supported TLS version as TLSv1.2 or default
value from SSL library. Only library NSS currently allows to get
maximum supported TLS version.
(Added in 7.54.0)
.IP CURL_SSLVERSION_MAX_TLSv1_0
The flag defines maximum supported TLS version as TLSv1.0.
(Added in 7.54.0)
.IP CURL_SSLVERSION_MAX_TLSv1_1
The flag defines maximum supported TLS version as TLSv1.1.
(Added in 7.54.0)
.IP CURL_SSLVERSION_MAX_TLSv1_2
The flag defines maximum supported TLS version as TLSv1.2.
(Added in 7.54.0)
.IP CURL_SSLVERSION_MAX_TLSv1_3
The flag defines maximum supported TLS version as TLSv1.3.
(Added in 7.54.0)
.RE .RE
.SH DEFAULT .SH DEFAULT
CURL_SSLVERSION_DEFAULT CURL_SSLVERSION_DEFAULT
@ -61,8 +78,9 @@ CURL *curl = curl_easy_init();
if(curl) { if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
/* ask libcurl to use TLS version 1.0 or later */ /* ask libcurl to use TLS version 1.1 or later */
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1.1 |
CURL_SSLVERSION_MAX_DEFAULT);
/* Perform the request */ /* Perform the request */
curl_easy_perform(curl); curl_easy_perform(curl);

View File

@ -798,6 +798,12 @@ CURL_SSLVERSION_TLSv1_0 7.34.0
CURL_SSLVERSION_TLSv1_1 7.34.0 CURL_SSLVERSION_TLSv1_1 7.34.0
CURL_SSLVERSION_TLSv1_2 7.34.0 CURL_SSLVERSION_TLSv1_2 7.34.0
CURL_SSLVERSION_TLSv1_3 7.52.0 CURL_SSLVERSION_TLSv1_3 7.52.0
CURL_SSLVERSION_MAX_NONE 7.54.0
CURL_SSLVERSION_MAX_DEFAULT 7.54.0
CURL_SSLVERSION_MAX_TLSv1_0 7.54.0
CURL_SSLVERSION_MAX_TLSv1_1 7.54.0
CURL_SSLVERSION_MAX_TLSv1_2 7.54.0
CURL_SSLVERSION_MAX_TLSv1_3 7.54.0
CURL_TIMECOND_IFMODSINCE 7.9.7 CURL_TIMECOND_IFMODSINCE 7.9.7
CURL_TIMECOND_IFUNMODSINCE 7.9.7 CURL_TIMECOND_IFUNMODSINCE 7.9.7
CURL_TIMECOND_LASTMOD 7.9.7 CURL_TIMECOND_LASTMOD 7.9.7

View File

@ -1884,6 +1884,18 @@ enum {
CURL_SSLVERSION_LAST /* never use, keep last */ CURL_SSLVERSION_LAST /* never use, keep last */
}; };
enum {
CURL_SSLVERSION_MAX_NONE = 0,
CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16),
CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16),
CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16),
CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16),
CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16),
/* never use, keep last */
CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16)
};
enum CURL_TLSAUTH { enum CURL_TLSAUTH {
CURL_TLSAUTH_NONE, CURL_TLSAUTH_NONE,
CURL_TLSAUTH_SRP, CURL_TLSAUTH_SRP,

View File

@ -695,6 +695,9 @@ CURLcode Curl_open(struct Curl_easy **curl)
return result; 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, CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
va_list param) va_list param)
{ {
@ -927,7 +930,9 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
* implementations are lame. * implementations are lame.
*/ */
#ifdef USE_SSL #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 #else
result = CURLE_UNKNOWN_OPTION; result = CURLE_UNKNOWN_OPTION;
#endif #endif
@ -938,7 +943,9 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
* implementations are lame. * implementations are lame.
*/ */
#ifdef USE_SSL #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 #else
result = CURLE_UNKNOWN_OPTION; result = CURLE_UNKNOWN_OPTION;
#endif #endif

View File

@ -350,6 +350,7 @@ struct ssl_connect_data {
struct ssl_primary_config { struct ssl_primary_config {
long version; /* what version the client wants to use */ 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 verifypeer; /* set TRUE if this is desired */
bool verifyhost; /* set TRUE if CN/SAN must match hostname */ bool verifyhost; /* set TRUE if CN/SAN must match hostname */
bool verifystatus; /* set TRUE if certificate status must be checked */ 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 */ same connection */
return CURLE_OK; 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 */ /* axTLS only supports TLSv1 */
/* check to see if we've been told to use an explicit SSL/TLS version */ /* check to see if we've been told to use an explicit SSL/TLS version */
switch(SSL_CONN_CONFIG(version)) { switch(SSL_CONN_CONFIG(version)) {

View File

@ -149,6 +149,11 @@ cyassl_connect_step1(struct connectdata *conn,
if(conssl->state == ssl_connection_complete) if(conssl->state == ssl_connection_complete)
return CURLE_OK; 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 */ /* check to see if we've been told to use an explicit SSL/TLS version */
switch(SSL_CONN_CONFIG(version)) { switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_DEFAULT:

View File

@ -1044,6 +1044,109 @@ CF_INLINE bool is_file(const char *filename)
return false; 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, static CURLcode darwinssl_connect_step1(struct connectdata *conn,
int sockindex) int sockindex)
{ {
@ -1113,20 +1216,15 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
break; break;
case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_0:
(void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol1);
break;
case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_1:
(void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol11);
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol11);
break;
case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_2:
(void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol12);
(void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
break;
case CURL_SSLVERSION_TLSv1_3: 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: case CURL_SSLVERSION_SSLv3:
err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3); err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3);
if(err != noErr) { if(err != noErr) {
@ -1167,23 +1265,15 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
true); true);
break; break;
case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_0:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol1,
true);
break;
case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_1:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol11,
true);
break;
case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_2:
(void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kTLSProtocol12,
true);
break;
case CURL_SSLVERSION_TLSv1_3: 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: case CURL_SSLVERSION_SSLv3:
err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
kSSLProtocol3, kSSLProtocol3,
@ -1209,6 +1299,11 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#endif /* CURL_SUPPORT_MAC_10_8 */ #endif /* CURL_SUPPORT_MAC_10_8 */
} }
#else #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); (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false);
switch(conn->ssl_config.version) { switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT: 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; 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) 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: const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
conn->host.name; conn->host.name;
const char *sni; const char *sni;
unsigned int protoflags; unsigned int protoflags = 0;
long timeout; long timeout;
Qso_OverlappedIO_t commarea; Qso_OverlappedIO_t commarea;
int sockpair[2]; 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; CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
break; break;
case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_0:
protoflags = CURL_GSKPROTO_TLSV10_MASK;
break;
case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_1:
protoflags = CURL_GSKPROTO_TLSV11_MASK;
break;
case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_2:
protoflags = CURL_GSKPROTO_TLSV12_MASK;
break;
case CURL_SSLVERSION_TLSv1_3: case CURL_SSLVERSION_TLSv1_3:
failf(data, "GSKit: TLS 1.3 is not yet supported"); result = set_ssl_version_min_max(&protoflags, conn);
return CURLE_SSL_CONNECT_ERROR; if(result != CURLE_OK)
return result;
break;
default: default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR; 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; 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 static CURLcode
gtls_connect_step1(struct connectdata *conn, gtls_connect_step1(struct connectdata *conn,
int sockindex) int sockindex)
@ -406,13 +500,8 @@ gtls_connect_step1(struct connectdata *conn,
GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_3DES_CBC,
}; };
static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; 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 #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 *prioritylist;
const char *err = NULL; const char *err = NULL;
#endif #endif
@ -576,7 +665,7 @@ gtls_connect_step1(struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
} }
switch(SSL_CONN_CONFIG(version) { switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_SSLv3: case CURL_SSLVERSION_SSLv3:
protocol_priority[0] = GNUTLS_SSL3; protocol_priority[0] = GNUTLS_SSL3;
break; break;
@ -587,17 +676,16 @@ gtls_connect_step1(struct connectdata *conn,
protocol_priority[2] = GNUTLS_TLS1_2; protocol_priority[2] = GNUTLS_TLS1_2;
break; break;
case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_0:
protocol_priority[0] = GNUTLS_TLS1_0;
break;
case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_1:
protocol_priority[0] = GNUTLS_TLS1_1;
break;
case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_2:
protocol_priority[0] = GNUTLS_TLS1_2;
break;
case CURL_SSLVERSION_TLSv1_3: 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: case CURL_SSLVERSION_SSLv2:
failf(data, "GnuTLS does not support SSLv2"); failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
@ -625,20 +713,15 @@ gtls_connect_step1(struct connectdata *conn,
prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP; prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
break; break;
case CURL_SSLVERSION_TLSv1_0: 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: 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: 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: 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: case CURL_SSLVERSION_SSLv2:
failf(data, "GnuTLS does not support SSLv2"); failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR; 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_recv mbed_recv;
static Curl_send mbed_send; 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 static CURLcode
mbed_connect_step1(struct connectdata *conn, mbed_connect_step1(struct connectdata *conn,
int sockindex) int sockindex)
@ -333,29 +398,15 @@ mbed_connect_step1(struct connectdata *conn,
infof(data, "mbedTLS: Set SSL version to SSLv3\n"); infof(data, "mbedTLS: Set SSL version to SSLv3\n");
break; break;
case CURL_SSLVERSION_TLSv1_0: 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: 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: 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: 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: default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;

View File

@ -1512,78 +1512,108 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
return CURLE_OK; 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, static CURLcode nss_init_sslver(SSLVersionRange *sslver,
struct Curl_easy *data, struct Curl_easy *data,
struct connectdata *conn) struct connectdata *conn)
{ {
switch(SSL_CONN_CONFIG(version)) { CURLcode result;
case CURL_SSLVERSION_DEFAULT: 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 */ /* map CURL_SSLVERSION_DEFAULT to NSS default */
if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess) if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess)
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
/* ... but make sure we use at least TLSv1.0 according to libcurl API */ /* ... but make sure we use at least TLSv1.0 according to libcurl API */
if(sslver->min < SSL_LIBRARY_VERSION_TLS_1_0) if(sslver->min < SSL_LIBRARY_VERSION_TLS_1_0)
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"); switch(min) {
return CURLE_SSL_CONNECT_ERROR; 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, static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,

View File

@ -1692,6 +1692,71 @@ get_ssl_version_txt(SSL *ssl)
return "unknown"; 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) static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
@ -1701,7 +1766,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
X509_LOOKUP *lookup = NULL; X509_LOOKUP *lookup = NULL;
curl_socket_t sockfd = conn->sock[sockindex]; curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex];
long ctx_options; long ctx_options = 0;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
bool sni; bool sni;
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
@ -1888,60 +1953,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
break; break;
case CURL_SSLVERSION_TLSv1_0: 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: 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: 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: case CURL_SSLVERSION_TLSv1_3:
#ifdef TLS1_3_VERSION result = set_ssl_version_min_max(&ctx_options, conn);
SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION); if(result != CURLE_OK)
ctx_options |= SSL_OP_NO_SSLv2; return result;
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;
break; break;
#else
failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
return CURLE_NOT_BUILT_IN;
#endif
case CURL_SSLVERSION_SSLv2: case CURL_SSLVERSION_SSLv2:
#ifndef OPENSSL_NO_SSL2 #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_recv polarssl_recv;
static Curl_send polarssl_send; 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 static CURLcode
polarssl_connect_step1(struct connectdata *conn, 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"); infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n");
break; break;
case CURL_SSLVERSION_TLSv1_0: 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: 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: 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: 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: default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;

View File

@ -102,6 +102,41 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
desc->cBuffers = NumArrElem; 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 static CURLcode
schannel_connect_step1(struct connectdata *conn, int sockindex) 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; SP_PROT_TLS1_2_CLIENT;
break; break;
case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_0:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_1:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_2:
schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
break;
case CURL_SSLVERSION_TLSv1_3: 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: case CURL_SSLVERSION_SSLv3:
schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
break; break;

View File

@ -95,6 +95,7 @@ Curl_ssl_config_matches(struct ssl_primary_config* data,
struct ssl_primary_config* needle) struct ssl_primary_config* needle)
{ {
if((data->version == needle->version) && if((data->version == needle->version) &&
(data->version_max == needle->version_max) &&
(data->verifypeer == needle->verifypeer) && (data->verifypeer == needle->verifypeer) &&
(data->verifyhost == needle->verifyhost) && (data->verifyhost == needle->verifyhost) &&
Curl_safe_strcasecompare(data->CApath, needle->CApath) && 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->verifyhost = source->verifyhost;
dest->verifypeer = source->verifypeer; dest->verifypeer = source->verifypeer;
dest->version = source->version; dest->version = source->version;
dest->version_max = source->version_max;
CLONE_STRING(CAfile); CLONE_STRING(CAfile);
CLONE_STRING(CApath); CLONE_STRING(CApath);
@ -173,11 +175,24 @@ void Curl_ssl_cleanup(void)
static bool ssl_prefs_check(struct Curl_easy *data) static bool ssl_prefs_check(struct Curl_easy *data)
{ {
/* check for CURLOPT_SSLVERSION invalid parameter value */ /* check for CURLOPT_SSLVERSION invalid parameter value */
if((data->set.ssl.primary.version < 0) const long sslver = data->set.ssl.primary.version;
|| (data->set.ssl.primary.version >= CURL_SSLVERSION_LAST)) { if((sslver < 0) || (sslver >= CURL_SSLVERSION_LAST)) {
failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
return FALSE; 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; return TRUE;
} }

View File

@ -262,6 +262,16 @@
d c 6 d c 6
d CURL_SSLVERSION_TLSv1_3... d CURL_SSLVERSION_TLSv1_3...
d c 7 d c 7
d CURL_SSLVERSION_MAX_DEFAULT...
d c X'00010000'
d CURL_SSLVERSION_MAX_TLSv1_0...
d c X'00040000'
d CURL_SSLVERSION_MAX_TLSv1_1...
d c X'00050000'
d CURL_SSLVERSION_MAX_TLSv1_2...
d c X'00060000'
d CURL_SSLVERSION_MAX_TLSv1_3...
d c X'00070000'
* *
d CURL_TLSAUTH_NONE... d CURL_TLSAUTH_NONE...
d c 0 d c 0

View File

@ -156,6 +156,7 @@ struct OperationConfig {
struct curl_slist *postquote; struct curl_slist *postquote;
struct curl_slist *prequote; struct curl_slist *prequote;
long ssl_version; long ssl_version;
long ssl_version_max;
long proxy_ssl_version; long proxy_ssl_version;
long ip_version; long ip_version;
curl_TimeCond timecond; curl_TimeCond timecond;

View File

@ -184,6 +184,7 @@ static const struct LongShort aliases[]= {
{"$S", "tftp-no-options", FALSE}, {"$S", "tftp-no-options", FALSE},
{"$U", "connect-to", TRUE}, {"$U", "connect-to", TRUE},
{"$W", "abstract-unix-socket", TRUE}, {"$W", "abstract-unix-socket", TRUE},
{"$X", "tls-max", TRUE},
{"0", "http1.0", FALSE}, {"0", "http1.0", FALSE},
{"01", "http1.1", FALSE}, {"01", "http1.1", FALSE},
{"02", "http2", FALSE}, {"02", "http2", FALSE},
@ -1060,6 +1061,11 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
config->abstract_unix_socket = TRUE; config->abstract_unix_socket = TRUE;
GetStr(&config->unix_socket_path, nextarg); GetStr(&config->unix_socket_path, nextarg);
break; break;
case 'X': /* --tls-max */
err = str2tls_max(&config->ssl_version_max, nextarg);
if(err)
return err;
break;
} }
break; break;
case '#': /* --progress-bar */ case '#': /* --progress-bar */

View File

@ -260,6 +260,7 @@ static const char *const helptext[] = {
" --tlsv1.1 Use TLSv1.1 (SSL)", " --tlsv1.1 Use TLSv1.1 (SSL)",
" --tlsv1.2 Use TLSv1.2 (SSL)", " --tlsv1.2 Use TLSv1.2 (SSL)",
" --tlsv1.3 Use TLSv1.3 (SSL)", " --tlsv1.3 Use TLSv1.3 (SSL)",
" --tls-max VERSION Use TLS up to VERSION (SSL)",
" --trace FILE Write a debug trace to FILE", " --trace FILE Write a debug trace to FILE",
" --trace-ascii FILE Like --trace, but without hex output", " --trace-ascii FILE Like --trace, but without hex output",
" --trace-time Add time stamps to trace/verbose output", " --trace-time Add time stamps to trace/verbose output",

View File

@ -1087,7 +1087,8 @@ static CURLcode operate_do(struct GlobalConfig *global,
if(config->falsestart) if(config->falsestart)
my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L); my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version); my_setopt_enum(curl, CURLOPT_SSLVERSION,
config->ssl_version | config->ssl_version_max);
my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION, my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION,
config->proxy_ssl_version); config->proxy_ssl_version);
} }

View File

@ -550,3 +550,36 @@ CURLcode get_args(struct OperationConfig *config, const size_t i)
return result; return result;
} }
/*
* Parse the string and modify ssl_version in the val argument. Return PARAM_OK
* on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
*
* Since this function gets called with the 'nextarg' pointer from within the
* getparameter a lot, we must check it for NULL before accessing the str
* data.
*/
ParameterError str2tls_max(long *val, const char *str)
{
static struct s_tls_max {
const char *tls_max_str;
long tls_max;
} const tls_max_array[] = {
{ "default", CURL_SSLVERSION_MAX_DEFAULT },
{ "1.0", CURL_SSLVERSION_MAX_TLSv1_0 },
{ "1.1", CURL_SSLVERSION_MAX_TLSv1_1 },
{ "1.2", CURL_SSLVERSION_MAX_TLSv1_2 },
{ "1.3", CURL_SSLVERSION_MAX_TLSv1_3 }
};
size_t i = 0;
if(!str)
return PARAM_REQUIRES_PARAMETER;
for(i = 0; i < sizeof(tls_max_array)/sizeof(tls_max_array[0]); i++) {
if(!strcmp(str, tls_max_array[i].tls_max_str)) {
*val = tls_max_array[i].tls_max;
return PARAM_OK;
}
}
return PARAM_BAD_USE;
}

View File

@ -52,4 +52,6 @@ int ftpcccmethod(struct OperationConfig *config, const char *str);
long delegation(struct OperationConfig *config, char *str); long delegation(struct OperationConfig *config, char *str);
ParameterError str2tls_max(long *val, const char *str);
#endif /* HEADER_CURL_TOOL_PARAMHLP_H */ #endif /* HEADER_CURL_TOOL_PARAMHLP_H */