From 6448f98c1857de521fb2dd3f9d4e5659845b5474 Mon Sep 17 00:00:00 2001 From: Jozef Kralik Date: Tue, 13 Dec 2016 21:10:00 +0100 Subject: 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 --- lib/vtls/axtls.c | 6 +++ lib/vtls/cyassl.c | 5 ++ lib/vtls/darwinssl.c | 145 ++++++++++++++++++++++++++++++++++++++++++--------- lib/vtls/gskit.c | 48 +++++++++++++---- lib/vtls/gtls.c | 135 ++++++++++++++++++++++++++++++++++++++--------- lib/vtls/mbedtls.c | 91 +++++++++++++++++++++++++------- lib/vtls/nss.c | 100 ++++++++++++++++++++++------------- lib/vtls/openssl.c | 120 ++++++++++++++++++++++++------------------ lib/vtls/polarssl.c | 88 ++++++++++++++++++++++++------- lib/vtls/schannel.c | 49 ++++++++++++++--- lib/vtls/vtls.c | 19 ++++++- 11 files changed, 610 insertions(+), 196 deletions(-) (limited to 'lib/vtls') 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 @@ -102,6 +102,41 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr, desc->cBuffers = NumArrElem; } +static CURLcode +set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn) +{ + struct Curl_easy *data = conn->data; + long ssl_version = SSL_CONN_CONFIG(version); + long ssl_version_max = SSL_CONN_CONFIG(version_max); + long i = ssl_version; + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + ssl_version_max = ssl_version << 16; + break; + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + for(; i <= (ssl_version_max >> 16); ++i) { + switch(i) { + case CURL_SSLVERSION_TLSv1_0: + schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_1: + schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_2: + schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "Schannel: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + } + } + return CURLE_OK; +} + static CURLcode schannel_connect_step1(struct connectdata *conn, int sockindex) { @@ -216,17 +251,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) SP_PROT_TLS1_2_CLIENT; break; case CURL_SSLVERSION_TLSv1_0: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT; - break; case CURL_SSLVERSION_TLSv1_1: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT; - break; case CURL_SSLVERSION_TLSv1_2: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; - break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "Schannel: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + { + CURLcode result = set_ssl_version_min_max(&schannel_cred, conn); + if(result != CURLE_OK) + return result; + break; + } case CURL_SSLVERSION_SSLv3: schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; break; 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; } -- cgit v1.2.3