summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJozef Kralik <jozef.kralik@eset.sk>2016-12-13 21:10:00 +0100
committerKamil Dudka <kdudka@redhat.com>2017-03-08 15:54:07 +0100
commit6448f98c1857de521fb2dd3f9d4e5659845b5474 (patch)
tree183b4febdb062f32be9113ae170e3b57f44a4b28
parentb66690733642d764199eeb1b64aaaa2513c13db3 (diff)
downloadgnurl-6448f98c1857de521fb2dd3f9d4e5659845b5474.tar.gz
gnurl-6448f98c1857de521fb2dd3f9d4e5659845b5474.tar.bz2
gnurl-6448f98c1857de521fb2dd3f9d4e5659845b5474.zip
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
-rw-r--r--docs/cmdline-opts/tls-max.d24
-rw-r--r--docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.320
-rw-r--r--docs/libcurl/opts/CURLOPT_SSLVERSION.322
-rw-r--r--docs/libcurl/symbols-in-versions6
-rw-r--r--include/curl/curl.h12
-rw-r--r--lib/url.c11
-rw-r--r--lib/urldata.h1
-rw-r--r--lib/vtls/axtls.c6
-rw-r--r--lib/vtls/cyassl.c5
-rw-r--r--lib/vtls/darwinssl.c145
-rw-r--r--lib/vtls/gskit.c48
-rw-r--r--lib/vtls/gtls.c135
-rw-r--r--lib/vtls/mbedtls.c91
-rw-r--r--lib/vtls/nss.c100
-rw-r--r--lib/vtls/openssl.c120
-rw-r--r--lib/vtls/polarssl.c88
-rw-r--r--lib/vtls/schannel.c49
-rw-r--r--lib/vtls/vtls.c19
-rw-r--r--packages/OS400/curl.inc.in10
-rw-r--r--src/tool_cfgable.h1
-rw-r--r--src/tool_getparam.c6
-rw-r--r--src/tool_help.c1
-rw-r--r--src/tool_operate.c3
-rw-r--r--src/tool_paramhlp.c33
-rw-r--r--src/tool_paramhlp.h2
25 files changed, 756 insertions, 202 deletions
diff --git a/docs/cmdline-opts/tls-max.d b/docs/cmdline-opts/tls-max.d
new file mode 100644
index 000000000..7ae862252
--- /dev/null
+++ b/docs/cmdline-opts/tls-max.d
@@ -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
diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3 b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3
index f96a9e6c5..85ecdc41f 100644
--- a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3
+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.3
@@ -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
@@ -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);
diff --git a/docs/libcurl/opts/CURLOPT_SSLVERSION.3 b/docs/libcurl/opts/CURLOPT_SSLVERSION.3
index 77dfcd49d..d07ae8dde 100644
--- a/docs/libcurl/opts/CURLOPT_SSLVERSION.3
+++ b/docs/libcurl/opts/CURLOPT_SSLVERSION.3
@@ -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
@@ -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);
diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
index 8834ada54..f4cd9805f 100644
--- a/docs/libcurl/symbols-in-versions
+++ b/docs/libcurl/symbols-in-versions
@@ -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
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 467bb0240..8b221ef8f 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -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,
diff --git a/lib/url.c b/lib/url.c
index 300fc4d14..5943896eb 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -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
diff --git a/lib/urldata.h b/lib/urldata.h
index 7f87913a9..ef6a78846 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -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 */
diff --git a/lib/vtls/axtls.c b/lib/vtls/axtls.c
index 1de758b0c..af01fe314 100644
--- a/lib/vtls/axtls.c
+++ b/lib/vtls/axtls.c
@@ -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)) {
diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c
index 1e3b346d6..2dfd79dce 100644
--- a/lib/vtls/cyassl.c
+++ b/lib/vtls/cyassl.c
@@ -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:
diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c
index 25a8ab8b6..26ea04cbb 100644
--- a/lib/vtls/darwinssl.c
+++ b/lib/vtls/darwinssl.c
@@ -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:
diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c
index a0d462b70..d760b6a87 100644
--- a/lib/vtls/gskit.c
+++ b/lib/vtls/gskit.c
@@ -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;
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index faa70aca2..f41036049 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -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;
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
index 07239bf26..dbcb1690c 100644
--- a/lib/vtls/mbedtls.c
+++ b/lib/vtls/mbedtls.c
@@ -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;
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index d5158acef..a09f457f8 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -1512,78 +1512,108 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
return CURLE_OK;
}
-static CURLcode nss_init_sslver(SSLVersionRange *sslver,
- struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
{
- switch(SSL_CONN_CONFIG(version)) {
- case CURL_SSLVERSION_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;
-
+ switch(version) {
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;
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
#elif defined SSL_LIBRARY_VERSION_TLS_1_1
- sslver->max = SSL_LIBRARY_VERSION_TLS_1_1;
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
#else
- sslver->max = SSL_LIBRARY_VERSION_TLS_1_0;
+ *nssver = 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;
+ *nssver = 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;
+ *nssver = 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;
+ *nssver = 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;
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
return CURLE_OK;
+#else
+ return CURLE_SSL_CONNECT_ERROR;
#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;
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
return CURLE_OK;
+#else
+ return CURLE_SSL_CONNECT_ERROR;
#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;
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_3;
return CURLE_OK;
+#else
+ return CURLE_SSL_CONNECT_ERROR;
#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;
+static CURLcode nss_init_sslver(SSLVersionRange *sslver,
+ struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ 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;
+ }
+
+ 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,
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 20626fec9..8881b57ac 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -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
diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c
index e5346ce3d..aa34bbc43 100644
--- a/lib/vtls/polarssl.c
+++ b/lib/vtls/polarssl.c
@@ -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;
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index bd9239956..47356a53d 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -103,6 +103,41 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
}
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)
{
ssize_t written = -1;
@@ -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;
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index f40a97712..693380fb9 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -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;
}
diff --git a/packages/OS400/curl.inc.in b/packages/OS400/curl.inc.in
index c6224a781..b9b0808c7 100644
--- a/packages/OS400/curl.inc.in
+++ b/packages/OS400/curl.inc.in
@@ -262,6 +262,16 @@
d c 6
d CURL_SSLVERSION_TLSv1_3...
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 c 0
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
index 0d2f765d2..b05c440e5 100644
--- a/src/tool_cfgable.h
+++ b/src/tool_cfgable.h
@@ -156,6 +156,7 @@ struct OperationConfig {
struct curl_slist *postquote;
struct curl_slist *prequote;
long ssl_version;
+ long ssl_version_max;
long proxy_ssl_version;
long ip_version;
curl_TimeCond timecond;
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index 686b01d7e..85d75ae6e 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -184,6 +184,7 @@ static const struct LongShort aliases[]= {
{"$S", "tftp-no-options", FALSE},
{"$U", "connect-to", TRUE},
{"$W", "abstract-unix-socket", TRUE},
+ {"$X", "tls-max", TRUE},
{"0", "http1.0", FALSE},
{"01", "http1.1", FALSE},
{"02", "http2", FALSE},
@@ -1060,6 +1061,11 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
config->abstract_unix_socket = TRUE;
GetStr(&config->unix_socket_path, nextarg);
break;
+ case 'X': /* --tls-max */
+ err = str2tls_max(&config->ssl_version_max, nextarg);
+ if(err)
+ return err;
+ break;
}
break;
case '#': /* --progress-bar */
diff --git a/src/tool_help.c b/src/tool_help.c
index 5085e542e..f6fe3527b 100644
--- a/src/tool_help.c
+++ b/src/tool_help.c
@@ -260,6 +260,7 @@ static const char *const helptext[] = {
" --tlsv1.1 Use TLSv1.1 (SSL)",
" --tlsv1.2 Use TLSv1.2 (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-ascii FILE Like --trace, but without hex output",
" --trace-time Add time stamps to trace/verbose output",
diff --git a/src/tool_operate.c b/src/tool_operate.c
index c30b32046..a489b8dbd 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -1087,7 +1087,8 @@ static CURLcode operate_do(struct GlobalConfig *global,
if(config->falsestart)
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,
config->proxy_ssl_version);
}
diff --git a/src/tool_paramhlp.c b/src/tool_paramhlp.c
index 257e5c697..6b534ce5d 100644
--- a/src/tool_paramhlp.c
+++ b/src/tool_paramhlp.c
@@ -550,3 +550,36 @@ CURLcode get_args(struct OperationConfig *config, const size_t i)
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;
+}
diff --git a/src/tool_paramhlp.h b/src/tool_paramhlp.h
index 89a99b2bb..cdfbacf3f 100644
--- a/src/tool_paramhlp.h
+++ b/src/tool_paramhlp.h
@@ -52,4 +52,6 @@ int ftpcccmethod(struct OperationConfig *config, const char *str);
long delegation(struct OperationConfig *config, char *str);
+ParameterError str2tls_max(long *val, const char *str);
+
#endif /* HEADER_CURL_TOOL_PARAMHLP_H */