Skip to content

Commit

Permalink
vtls: add options to specify range of enabled TLS versions
Browse files Browse the repository at this point in the history
This commit introduces the CURL_SSLVERSION_MAX_* constants as well as
the --tls-max option of the curl tool.

Closes curl#1166
  • Loading branch information
Jozef Kralik authored and kdudka committed Mar 8, 2017
1 parent b666907 commit 6448f98
Show file tree
Hide file tree
Showing 25 changed files with 756 additions and 202 deletions.
24 changes: 24 additions & 0 deletions docs/cmdline-opts/tls-max.d
Original file line number Diff line number Diff line change
@@ -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
20 changes: 19 additions & 1 deletion docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ TLSv1.1
TLSv1.2
.IP CURL_SSLVERSION_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
.SH DEFAULT
CURL_SSLVERSION_DEFAULT
Expand All @@ -58,7 +75,8 @@ if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

/* 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 */
curl_easy_perform(curl);
Expand Down
22 changes: 20 additions & 2 deletions docs/libcurl/opts/CURLOPT_SSLVERSION.3
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,23 @@ TLSv1.1 (Added in 7.34.0)
TLSv1.2 (Added in 7.34.0)
.IP CURL_SSLVERSION_TLSv1_3
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
.SH DEFAULT
CURL_SSLVERSION_DEFAULT
Expand All @@ -61,8 +78,9 @@ CURL *curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

/* ask libcurl to use TLS version 1.0 or later */
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
/* ask libcurl to use TLS version 1.1 or later */
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1.1 |
CURL_SSLVERSION_MAX_DEFAULT);

/* Perform the request */
curl_easy_perform(curl);
Expand Down
6 changes: 6 additions & 0 deletions docs/libcurl/symbols-in-versions
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,12 @@ CURL_SSLVERSION_TLSv1_0 7.34.0
CURL_SSLVERSION_TLSv1_1 7.34.0
CURL_SSLVERSION_TLSv1_2 7.34.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_IFUNMODSINCE 7.9.7
CURL_TIMECOND_LASTMOD 7.9.7
Expand Down
12 changes: 12 additions & 0 deletions include/curl/curl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,18 @@ enum {
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 {
CURL_TLSAUTH_NONE,
CURL_TLSAUTH_SRP,
Expand Down
11 changes: 9 additions & 2 deletions lib/url.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/urldata.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
6 changes: 6 additions & 0 deletions lib/vtls/axtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
5 changes: 5 additions & 0 deletions lib/vtls/cyassl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
145 changes: 120 additions & 25 deletions lib/vtls/darwinssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand All @@ -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:
Expand Down
Loading

0 comments on commit 6448f98

Please sign in to comment.