Last active
July 22, 2021 09:45
-
-
Save hakasenyang/8dea6875b09757b411c2053a1cd34460 to your computer and use it in GitHub Desktop.
ssl.hakase.io source
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Tor Check : https://gist.github.com/TheRealBastiaan/889b4ec5fafd928e0de2 | |
function IsTorExitPoint($ip=null){ | |
$ip = ($ip) ? $ip : $_SERVER['REMOTE_ADDR']; | |
if (gethostbyname(ReverseIPOctets($ip).".".$_SERVER['SERVER_PORT'].".".ReverseIPOctets($_SERVER['SERVER_ADDR']).".ip-port.exitlist.torproject.org")=="127.0.0.2") { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
function ReverseIPOctets($inputip){ | |
$ipoc = explode(".",$inputip); | |
return $ipoc[3].".".$ipoc[2].".".$ipoc[1].".".$ipoc[0]; | |
} | |
?> | |
<!doctype html> | |
<html lang="en"> | |
<head> | |
<title>SSL Test</title> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<meta property="og:locale" content="en_US"> | |
<meta property="og:site_name" content="Hakase's SSL Test Page"> | |
<meta property="og:title" content="Hakase's SSL Test Page"> | |
<meta property="og:url" content="//hakase.io/"> | |
<meta property="og:type" content="website"> | |
<meta property="og:image" content="//ssl.hakase.io/favicon.ico"> | |
<meta property="og:description" content="SSL Test Page (TLS1.3, etc.)"> | |
<style> | |
body img { | |
width: auto; | |
height: auto; | |
max-width: 100%; | |
} | |
.visible_hidden { | |
visibility: hidden; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>SSL Page!</h1> | |
<p> | |
<?php | |
if ($_SERVER['SSL_PROTOCOL'] === 'TLSv1.3') { | |
$early_data = (!empty($_SERVER['SSL_EARLY_DATA'])) ? 'Enabled' : 'Not used'; | |
echo ' <strong>' . $early_data . ' TLS 1.3 0-RTT (Experimental)</strong><br>' . PHP_EOL; | |
} | |
?> | |
<?php $curves = $_SERVER['SSL_CURVES']; | |
$curves = preg_replace('/0x[0-9a-fA-F]{4}(\:*)/', '', $curves); $curves = explode(':', $curves)[0]; $curves = ($curves) ? '('.$curves.')' : NULL; ?> | |
Connection method : <?php echo $_SERVER['SERVER_PROTOCOL']; ?> / <?php echo $_SERVER['SSL_PROTOCOL']; ?><?php if(!empty($_SERVER['SSL_TLS13'])) echo ' (draft '.$_SERVER['SSL_TLS13'].')'; echo ' / '.$_SERVER['SSL_CIPHER'];?> <?php echo $curves; ?><br> | |
Your browser support ciphers : <?php | |
$a = str_replace(':', ' / ', preg_replace('/0x[0-9a-fA-F]{4}(\:*)/', '', $_SERVER['SSL_CIPHERS'])); | |
echo (substr($a, -3) === ' / ') ? substr($a, 0, -3) : $a; | |
?><br> | |
Your browser support curves : <?php | |
$a = str_replace(':', ' / ', preg_replace('/0x[0-9a-fA-F]{4}(\:*)/', '', $_SERVER['SSL_CURVES'])); | |
echo (substr($a, -3) === ' / ') ? substr($a, 0, -3) : $a; | |
?> <br><a href="//dev.ssllabs.com/ssltest/viewMyClient.html" target="_blank">(ciphers detail view)</a> | |
<br><a href="//dev.ssllabs.com/ssltest/analyze.html?d=hakase.io" target="_blank">SSLLabs A+</a> | |
<br><a href="ssltest/hakase.io.html" target="_blank">testssl.sh</a> | |
</p> | |
<p> | |
OpenSSL Version : OpenSSL 1.1.2-dev | |
<br>- Patch : <a href="//hks.pw/ossl" target="_blank">My Git</a> / <a href="//github.com/hakasenyang/openssl-patch" target="_blank">Github</a> (Equal preference + Support draft 23, 26, 28 patch) | |
<br>PHP Version : <?php echo phpversion().PHP_EOL; ?> | |
<br>IP Address : <?php echo $_SERVER['REMOTE_ADDR']; if (isset($_SERVER['HTTP_X_REAL_IP'])) echo ' ('.$_SERVER['HTTP_X_REAL_IP'].')'.PHP_EOL; ?> | |
<br>Tor Check : <strong><?php echo (IsTorExitPoint()) ? 'Using Tor' : 'Not using Tor'; ?></strong> | |
<br>User-Agent : <?php echo $_SERVER['HTTP_USER_AGENT'].PHP_EOL; ?> | |
<br>GeoIP : <?php echo $_SERVER['GEOIP_CITY']; if ($_SERVER['GEOIP_CITY'] !== $_SERVER['GEOIP_SUBDIVISIONS']) echo ' / ' . $_SERVER['GEOIP_SUBDIVISIONS']; echo ' / ' . $_SERVER['GEOIP_COUNTRY_NAME']; echo PHP_EOL; ?> | |
<br>Server Info : <a href="//info.hakase.io/" target="_blank">phpSysInfo</a> | |
</p> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c | |
index 4f9da0b..809fad7 100644 | |
--- a/src/event/ngx_event_openssl.c | |
+++ b/src/event/ngx_event_openssl.c | |
@@ -3919,6 +3919,14 @@ ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) | |
} | |
+ngx_int_t | |
+ngx_ssl_get_tls13(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) | |
+{ | |
+ s->data = (u_char *) SSL_get_version_tls13(c->ssl->connection); | |
+ return NGX_OK; | |
+} | |
+ | |
+ | |
ngx_int_t | |
ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) | |
{ | |
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h | |
index f3526a0..3c504dd 100644 | |
--- a/src/event/ngx_event_openssl.h | |
+++ b/src/event/ngx_event_openssl.h | |
@@ -227,6 +227,8 @@ ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name); | |
ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, | |
ngx_str_t *s); | |
+ngx_int_t ngx_ssl_get_tls13(ngx_connection_t *c, ngx_pool_t *pool, | |
+ ngx_str_t *s); | |
ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, | |
ngx_str_t *s); | |
ngx_int_t ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, | |
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c | |
index d7b0fe7..6c8e239 100644 | |
--- a/src/http/modules/ngx_http_ssl_module.c | |
+++ b/src/http/modules/ngx_http_ssl_module.c | |
@@ -321,6 +321,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { | |
{ ngx_string("ssl_protocol"), NULL, ngx_http_ssl_static_variable, | |
(uintptr_t) ngx_ssl_get_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 }, | |
+ { ngx_string("ssl_tls13"), NULL, ngx_http_ssl_static_variable, | |
+ (uintptr_t) ngx_ssl_get_tls13, NGX_HTTP_VAR_CHANGEABLE, 0 }, | |
+ | |
{ ngx_string("ssl_cipher"), NULL, ngx_http_ssl_static_variable, | |
(uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | |
fastcgi_param QUERY_STRING $query_string; | |
fastcgi_param REQUEST_METHOD $request_method; | |
fastcgi_param CONTENT_TYPE $content_type; | |
fastcgi_param CONTENT_LENGTH $content_length; | |
fastcgi_param SCRIPT_NAME $fastcgi_script_name; | |
fastcgi_param REQUEST_URI $request_uri; | |
fastcgi_param DOCUMENT_URI $document_uri; | |
fastcgi_param DOCUMENT_ROOT $document_root; | |
fastcgi_param SERVER_PROTOCOL $server_protocol; | |
fastcgi_param REQUEST_SCHEME $scheme; | |
fastcgi_param HTTP2 $http2; | |
fastcgi_param SSL_CIPHERS $ssl_ciphers; | |
fastcgi_param SSL_CURVES $ssl_curves; | |
fastcgi_param SSL_CIPHER $ssl_cipher; | |
fastcgi_param SSL_PROTOCOL $ssl_protocol; | |
fastcgi_param SSL_TLS13 $ssl_tls13 if_not_empty; | |
fastcgi_param SSL_EARLY_DATA $ssl_early_data if_not_empty; | |
fastcgi_param HTTPS $https if_not_empty; | |
fastcgi_param GATEWAY_INTERFACE CGI/1.1; | |
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; | |
# GeoIP | |
#fastcgi_param GEOIP_COUNTRY_CODE $geoip_country_code; | |
#fastcgi_param GEOIP_COUNTRY_NAME $geoip_country_name; | |
#fastcgi_param GEOIP_REGION_NAME $geoip_city_country_code; | |
#fastcgi_param GEOIP_REGION $geoip_city_continent_code; | |
#fastcgi_param GEOIP_CITY $geoip_city; | |
fastcgi_param REMOTE_ADDR $remote_addr; | |
fastcgi_param REMOTE_PORT $remote_port; | |
fastcgi_param SERVER_ADDR $server_addr; | |
fastcgi_param SERVER_PORT $server_port; | |
fastcgi_param SERVER_NAME $server_name; | |
# PHP only, required if PHP was built with --enable-force-cgi-redirect | |
fastcgi_param REDIRECT_STATUS 200; | |
fastcgi_param HTTP_STATUS $status; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/doc/man1/ciphers.pod b/doc/man1/ciphers.pod | |
index 3aea982384..3c93eba0bf 100644 | |
--- a/doc/man1/ciphers.pod | |
+++ b/doc/man1/ciphers.pod | |
@@ -400,6 +400,21 @@ permissible. | |
=back | |
+=head1 EQUAL PREFERENCE GROUPS | |
+ | |
+If configuring a server, one may also configure equal-preference groups to | |
+partially respect the client's preferences when | |
+B<SSL_OP_CIPHER_SERVER_PREFERENCE> is enabled. Ciphers in an equal-preference | |
+group have equal priority and use the client order. This may be used to | |
+enforce that AEADs are preferred but select AES-GCM vs. ChaCha20-Poly1305 | |
+based on client preferences. An equal-preference is specified with square | |
+brackets, combining multiple selectors separated by |. For example: | |
+ | |
+ [ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256] | |
+ | |
+ Once an equal-preference group is used, future directives must be | |
+ opcode-less. | |
+ | |
=head1 CIPHER SUITE NAMES | |
The following lists give the SSL or TLS cipher suites names from the | |
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h | |
index 0a18a43544..195e543cac 100644 | |
--- a/include/openssl/ssl.h | |
+++ b/include/openssl/ssl.h | |
@@ -1829,6 +1829,7 @@ __owur int SSL_get_early_data_status(const SSL *s); | |
__owur int SSL_get_error(const SSL *s, int ret_code); | |
__owur const char *SSL_get_version(const SSL *s); | |
+__owur const char *SSL_get_version_tls13(const SSL *s); | |
/* This sets the 'default' SSL version that SSL_new() will create */ | |
__owur int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); | |
diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h | |
index 87b295c9f9..d118d8e864 100644 | |
--- a/include/openssl/sslerr.h | |
+++ b/include/openssl/sslerr.h | |
@@ -596,6 +596,8 @@ int ERR_load_SSL_strings(void); | |
# define SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION 209 | |
# define SSL_R_MISSING_TMP_DH_KEY 171 | |
# define SSL_R_MISSING_TMP_ECDH_KEY 311 | |
+# define SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS 101 | |
+# define SSL_R_NESTED_GROUP 108 | |
# define SSL_R_NOT_ON_RECORD_BOUNDARY 182 | |
# define SSL_R_NOT_REPLACING_CERTIFICATE 289 | |
# define SSL_R_NOT_SERVER 284 | |
@@ -726,9 +728,11 @@ int ERR_load_SSL_strings(void); | |
# define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239 | |
# define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242 | |
# define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243 | |
+# define SSL_R_UNEXPECTED_GROUP_CLOSE 109 | |
# define SSL_R_UNEXPECTED_CCS_MESSAGE 262 | |
# define SSL_R_UNEXPECTED_END_OF_EARLY_DATA 178 | |
# define SSL_R_UNEXPECTED_MESSAGE 244 | |
+# define SSL_R_UNEXPECTED_OPERATOR_IN_GROUP 110 | |
# define SSL_R_UNEXPECTED_RECORD 245 | |
# define SSL_R_UNINITIALIZED 276 | |
# define SSL_R_UNKNOWN_ALERT_TYPE 246 | |
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h | |
index 2e46cf80d3..0accc837a3 100644 | |
--- a/include/openssl/tls1.h | |
+++ b/include/openssl/tls1.h | |
@@ -30,6 +30,16 @@ extern "C" { | |
# define TLS1_3_VERSION 0x0304 | |
# define TLS_MAX_VERSION TLS1_3_VERSION | |
+/* TODO(TLS1.3) REMOVE ME: Version indicators for draft version */ | |
+# define TLS1_3_VERSION_DRAFT_23 0x7f17 | |
+# define TLS1_3_VERSION_DRAFT_26 0x7f1a | |
+# define TLS1_3_VERSION_DRAFT_27 0x7f1b | |
+# define TLS1_3_VERSION_DRAFT 0x7f1c | |
+# define TLS1_3_VERSION_DRAFT_TXT_23 "TLS 1.3 (draft 23)" | |
+# define TLS1_3_VERSION_DRAFT_TXT_26 "TLS 1.3 (draft 26)" | |
+# define TLS1_3_VERSION_DRAFT_TXT_27 "TLS 1.3 (draft 27)" | |
+# define TLS1_3_VERSION_DRAFT_TXT "TLS 1.3 (draft 28)" | |
+ | |
/* Special value for method supporting multiple versions */ | |
# define TLS_ANY_VERSION 0x10000 | |
diff --git a/ssl/record/ssl3_record_tls13.c b/ssl/record/ssl3_record_tls13.c | |
index a11ed483e6..4fd583dd03 100644 | |
--- a/ssl/record/ssl3_record_tls13.c | |
+++ b/ssl/record/ssl3_record_tls13.c | |
@@ -173,8 +173,9 @@ int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending) | |
if (((alg_enc & SSL_AESCCM) != 0 | |
&& EVP_CipherUpdate(ctx, NULL, &lenu, NULL, | |
(unsigned int)rec->length) <= 0) | |
- || EVP_CipherUpdate(ctx, NULL, &lenu, recheader, | |
- sizeof(recheader)) <= 0 | |
+ || (s->version_draft != TLS1_3_VERSION_DRAFT_23 | |
+ && EVP_CipherUpdate(ctx, NULL, &lenu, recheader, | |
+ sizeof(recheader)) <= 0) | |
|| EVP_CipherUpdate(ctx, rec->data, &lenu, rec->input, | |
(unsigned int)rec->length) <= 0 | |
|| EVP_CipherFinal_ex(ctx, rec->data + lenu, &lenf) <= 0 | |
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c | |
index 7713f767b2..a0af8ac001 100644 | |
--- a/ssl/s3_lib.c | |
+++ b/ssl/s3_lib.c | |
@@ -31,7 +31,25 @@ const unsigned char tls12downgrade[] = { | |
}; | |
/* The list of available TLSv1.3 ciphers */ | |
+/* Since nginx can not set the TLS 1.3 cipher, remove it temporarily. */ | |
static SSL_CIPHER tls13_ciphers[] = { | |
+ { | |
+ 0, | |
+ } | |
+}; | |
+ | |
+/* | |
+ * The list of available ciphers, mostly organized into the following | |
+ * groups: | |
+ * Always there | |
+ * EC | |
+ * PSK | |
+ * SRP (within that: RSA EC PSK) | |
+ * Cipher families: Chacha/poly, Camellia, Gost, IDEA, SEED | |
+ * Weak ciphers | |
+ */ | |
+static SSL_CIPHER ssl3_ciphers[] = { | |
+ /* TLSv1.3 ciphers */ | |
{ | |
1, | |
TLS1_3_RFC_AES_128_GCM_SHA256, | |
@@ -111,20 +129,8 @@ static SSL_CIPHER tls13_ciphers[] = { | |
SSL_HANDSHAKE_MAC_SHA256, | |
128, | |
128, | |
- } | |
-}; | |
- | |
-/* | |
- * The list of available ciphers, mostly organized into the following | |
- * groups: | |
- * Always there | |
- * EC | |
- * PSK | |
- * SRP (within that: RSA EC PSK) | |
- * Cipher families: Chacha/poly, Camellia, Gost, IDEA, SEED | |
- * Weak ciphers | |
- */ | |
-static SSL_CIPHER ssl3_ciphers[] = { | |
+ }, | |
+ /* List of cipher below TLSv1.3 */ | |
{ | |
1, | |
SSL3_TXT_RSA_NULL_MD5, | |
@@ -167,7 +173,7 @@ static SSL_CIPHER ssl3_ciphers[] = { | |
SSL_aRSA, | |
SSL_3DES, | |
SSL_SHA1, | |
- SSL3_VERSION, TLS1_2_VERSION, | |
+ SSL3_VERSION, TLS1_VERSION, | |
DTLS1_BAD_VER, DTLS1_2_VERSION, | |
SSL_NOT_DEFAULT | SSL_MEDIUM | SSL_FIPS, | |
SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, | |
@@ -232,7 +238,7 @@ static SSL_CIPHER ssl3_ciphers[] = { | |
SSL_aRSA, | |
SSL_AES128, | |
SSL_SHA1, | |
- SSL3_VERSION, TLS1_2_VERSION, | |
+ SSL3_VERSION, TLS1_VERSION, | |
DTLS1_BAD_VER, DTLS1_2_VERSION, | |
SSL_HIGH | SSL_FIPS, | |
SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, | |
@@ -296,7 +302,7 @@ static SSL_CIPHER ssl3_ciphers[] = { | |
SSL_aRSA, | |
SSL_AES256, | |
SSL_SHA1, | |
- SSL3_VERSION, TLS1_2_VERSION, | |
+ SSL3_VERSION, TLS1_VERSION, | |
DTLS1_BAD_VER, DTLS1_2_VERSION, | |
SSL_HIGH | SSL_FIPS, | |
SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, | |
@@ -4104,6 +4110,17 @@ int ssl3_put_cipher_by_char(const SSL_CIPHER *c, WPACKET *pkt, size_t *len) | |
return 1; | |
} | |
+struct ssl_cipher_preference_list_st* ssl_get_cipher_preferences(SSL *s) | |
+{ | |
+ if (s->cipher_list != NULL) | |
+ return (s->cipher_list); | |
+ | |
+ if ((s->ctx != NULL) && (s->ctx->cipher_list != NULL)) | |
+ return (s->ctx->cipher_list); | |
+ | |
+ return NULL; | |
+} | |
+ | |
/* | |
* ssl3_choose_cipher - choose a cipher from those offered by the client | |
* @s: SSL connection | |
@@ -4113,16 +4130,24 @@ int ssl3_put_cipher_by_char(const SSL_CIPHER *c, WPACKET *pkt, size_t *len) | |
* Returns the selected cipher or NULL when no common ciphers. | |
*/ | |
const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, | |
- STACK_OF(SSL_CIPHER) *srvr) | |
+ struct ssl_cipher_preference_list_st | |
+ *server_pref) | |
{ | |
const SSL_CIPHER *c, *ret = NULL; | |
- STACK_OF(SSL_CIPHER) *prio, *allow; | |
- int i, ii, ok, prefer_sha256 = 0; | |
+ STACK_OF(SSL_CIPHER) *srvr = server_pref->ciphers, *prio, *allow; | |
+ int i, ii, ok, prefer_sha256 = 0, safari_ec = 0; | |
unsigned long alg_k = 0, alg_a = 0, mask_k = 0, mask_a = 0; | |
const EVP_MD *mdsha256 = EVP_sha256(); | |
-#ifndef OPENSSL_NO_CHACHA | |
- STACK_OF(SSL_CIPHER) *prio_chacha = NULL; | |
-#endif | |
+ | |
+ /* in_group_flags will either be NULL, or will point to an array of | |
+ * bytes which indicate equal-preference groups in the |prio| stack. | |
+ * See the comment about |in_group_flags| in the | |
+ * |ssl_cipher_preference_list_st| struct. */ | |
+ const uint8_t *in_group_flags; | |
+ | |
+ /* group_min contains the minimal index so far found in a group, or -1 | |
+ * if no such value exists yet. */ | |
+ int group_min = -1; | |
/* Let's see which ciphers we can support */ | |
@@ -4149,54 +4174,13 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, | |
#endif | |
/* SUITE-B takes precedence over server preference and ChaCha priortiy */ | |
- if (tls1_suiteb(s)) { | |
+ if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || tls1_suiteb(s)) { | |
prio = srvr; | |
+ in_group_flags = server_pref->in_group_flags; | |
allow = clnt; | |
- } else if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { | |
- prio = srvr; | |
- allow = clnt; | |
-#ifndef OPENSSL_NO_CHACHA | |
- /* If ChaCha20 is at the top of the client preference list, | |
- and there are ChaCha20 ciphers in the server list, then | |
- temporarily prioritize all ChaCha20 ciphers in the servers list. */ | |
- if (s->options & SSL_OP_PRIORITIZE_CHACHA && sk_SSL_CIPHER_num(clnt) > 0) { | |
- c = sk_SSL_CIPHER_value(clnt, 0); | |
- if (c->algorithm_enc == SSL_CHACHA20POLY1305) { | |
- /* ChaCha20 is client preferred, check server... */ | |
- int num = sk_SSL_CIPHER_num(srvr); | |
- int found = 0; | |
- for (i = 0; i < num; i++) { | |
- c = sk_SSL_CIPHER_value(srvr, i); | |
- if (c->algorithm_enc == SSL_CHACHA20POLY1305) { | |
- found = 1; | |
- break; | |
- } | |
- } | |
- if (found) { | |
- prio_chacha = sk_SSL_CIPHER_new_reserve(NULL, num); | |
- /* if reserve fails, then there's likely a memory issue */ | |
- if (prio_chacha != NULL) { | |
- /* Put all ChaCha20 at the top, starting with the one we just found */ | |
- sk_SSL_CIPHER_push(prio_chacha, c); | |
- for (i++; i < num; i++) { | |
- c = sk_SSL_CIPHER_value(srvr, i); | |
- if (c->algorithm_enc == SSL_CHACHA20POLY1305) | |
- sk_SSL_CIPHER_push(prio_chacha, c); | |
- } | |
- /* Pull in the rest */ | |
- for (i = 0; i < num; i++) { | |
- c = sk_SSL_CIPHER_value(srvr, i); | |
- if (c->algorithm_enc != SSL_CHACHA20POLY1305) | |
- sk_SSL_CIPHER_push(prio_chacha, c); | |
- } | |
- prio = prio_chacha; | |
- } | |
- } | |
- } | |
- } | |
-# endif | |
} else { | |
prio = clnt; | |
+ in_group_flags = NULL; | |
allow = srvr; | |
} | |
@@ -4227,14 +4211,16 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, | |
for (i = 0; i < sk_SSL_CIPHER_num(prio); i++) { | |
c = sk_SSL_CIPHER_value(prio, i); | |
+ ok = 1; | |
+ | |
/* Skip ciphers not supported by the protocol version */ | |
if (!SSL_IS_DTLS(s) && | |
((s->version < c->min_tls) || (s->version > c->max_tls))) | |
- continue; | |
+ ok = 0; | |
if (SSL_IS_DTLS(s) && | |
(DTLS_VERSION_LT(s->version, c->min_dtls) || | |
DTLS_VERSION_GT(s->version, c->max_dtls))) | |
- continue; | |
+ ok = 0; | |
/* | |
* Since TLS 1.3 ciphersuites can be used with any auth or | |
@@ -4256,10 +4242,10 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, | |
#ifndef OPENSSL_NO_PSK | |
/* with PSK there must be server callback set */ | |
if ((alg_k & SSL_PSK) && s->psk_server_callback == NULL) | |
- continue; | |
+ ok = 0; | |
#endif /* OPENSSL_NO_PSK */ | |
- ok = (alg_k & mask_k) && (alg_a & mask_a); | |
+ ok = ok && (alg_k & mask_k) && (alg_a & mask_a); | |
#ifdef CIPHER_DEBUG | |
fprintf(stderr, "%d:[%08lX:%08lX:%08lX:%08lX]%p:%s\n", ok, alg_k, | |
alg_a, mask_k, mask_a, (void *)c, c->name); | |
@@ -4276,6 +4262,14 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, | |
if (!ok) | |
continue; | |
+ | |
+ safari_ec = 0; | |
+#if !defined(OPENSSL_NO_EC) | |
+ if ((alg_k & SSL_kECDHE) && (alg_a & SSL_aECDSA)) { | |
+ if (s->s3->is_probably_safari) | |
+ safari_ec = 1; | |
+ } | |
+#endif | |
} | |
ii = sk_SSL_CIPHER_find(allow, c); | |
if (ii >= 0) { | |
@@ -4283,14 +4277,7 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, | |
if (!ssl_security(s, SSL_SECOP_CIPHER_SHARED, | |
c->strength_bits, 0, (void *)c)) | |
continue; | |
-#if !defined(OPENSSL_NO_EC) | |
- if ((alg_k & SSL_kECDHE) && (alg_a & SSL_aECDSA) | |
- && s->s3->is_probably_safari) { | |
- if (!ret) | |
- ret = sk_SSL_CIPHER_value(allow, ii); | |
- continue; | |
- } | |
-#endif | |
+ | |
if (prefer_sha256) { | |
const SSL_CIPHER *tmp = sk_SSL_CIPHER_value(allow, ii); | |
@@ -4302,13 +4289,38 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, | |
ret = tmp; | |
continue; | |
} | |
- ret = sk_SSL_CIPHER_value(allow, ii); | |
+ | |
+ if (in_group_flags != NULL && in_group_flags[i] == 1) { | |
+ /* This element of |prio| is in a group. Update | |
+ * the minimum index found so far and continue | |
+ * looking. */ | |
+ if (group_min == -1 || group_min > ii) | |
+ group_min = ii; | |
+ } else { | |
+ if (group_min != -1 && group_min < ii) | |
+ ii = group_min; | |
+ if (safari_ec) { | |
+ if (!ret) | |
+ ret = sk_SSL_CIPHER_value(allow, ii); | |
+ continue; | |
+ } | |
+ ret = sk_SSL_CIPHER_value(allow, ii); | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if (in_group_flags != NULL && !in_group_flags[i] && group_min != -1) { | |
+ /* We are about to leave a group, but we found a match | |
+ * in it, so that's our answer. */ | |
+ if (safari_ec) { | |
+ if (!ret) | |
+ ret = sk_SSL_CIPHER_value(allow, group_min); | |
+ continue; | |
+ } | |
+ ret = sk_SSL_CIPHER_value(allow, group_min); | |
break; | |
} | |
} | |
-#ifndef OPENSSL_NO_CHACHA | |
- sk_SSL_CIPHER_free(prio_chacha); | |
-#endif | |
return ret; | |
} | |
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c | |
index 14066d0ea4..dc190fa334 100644 | |
--- a/ssl/ssl_ciph.c | |
+++ b/ssl/ssl_ciph.c | |
@@ -190,6 +190,7 @@ typedef struct cipher_order_st { | |
const SSL_CIPHER *cipher; | |
int active; | |
int dead; | |
+ int in_group; | |
struct cipher_order_st *next, *prev; | |
} CIPHER_ORDER; | |
@@ -294,6 +295,7 @@ static const SSL_CIPHER cipher_aliases[] = { | |
{0, SSL_TXT_TLSV1, NULL, 0, 0, 0, 0, 0, TLS1_VERSION}, | |
{0, "TLSv1.0", NULL, 0, 0, 0, 0, 0, TLS1_VERSION}, | |
{0, SSL_TXT_TLSV1_2, NULL, 0, 0, 0, 0, 0, TLS1_2_VERSION}, | |
+ {0, "TLS13", NULL, 0, 0, 0, 0, 0, TLS1_3_VERSION}, | |
/* strength classes */ | |
{0, SSL_TXT_LOW, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, SSL_LOW}, | |
@@ -679,6 +681,7 @@ static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method, | |
co_list[co_list_num].next = NULL; | |
co_list[co_list_num].prev = NULL; | |
co_list[co_list_num].active = 0; | |
+ co_list[co_list_num].in_group = 0; | |
co_list_num++; | |
} | |
@@ -772,8 +775,8 @@ static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey, | |
uint32_t alg_auth, uint32_t alg_enc, | |
uint32_t alg_mac, int min_tls, | |
uint32_t algo_strength, int rule, | |
- int32_t strength_bits, CIPHER_ORDER **head_p, | |
- CIPHER_ORDER **tail_p) | |
+ int32_t strength_bits, int in_group, | |
+ CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p) | |
{ | |
CIPHER_ORDER *head, *tail, *curr, *next, *last; | |
const SSL_CIPHER *cp; | |
@@ -781,9 +784,9 @@ static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey, | |
#ifdef CIPHER_DEBUG | |
fprintf(stderr, | |
- "Applying rule %d with %08x/%08x/%08x/%08x/%08x %08x (%d)\n", | |
+ "Applying rule %d with %08x/%08x/%08x/%08x/%08x %08x (%d) g:%d\n", | |
rule, alg_mkey, alg_auth, alg_enc, alg_mac, min_tls, | |
- algo_strength, strength_bits); | |
+ algo_strength, strength_bits, in_group); | |
#endif | |
if (rule == CIPHER_DEL || rule == CIPHER_BUMP) | |
@@ -860,6 +863,7 @@ static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey, | |
if (!curr->active) { | |
ll_append_tail(&head, curr, &tail); | |
curr->active = 1; | |
+ curr->in_group = in_group; | |
} | |
} | |
/* Move the added cipher to this location */ | |
@@ -867,6 +871,7 @@ static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey, | |
/* reverse == 0 */ | |
if (curr->active) { | |
ll_append_tail(&head, curr, &tail); | |
+ curr->in_group = 0; | |
} | |
} else if (rule == CIPHER_DEL) { | |
/* reverse == 1 */ | |
@@ -878,6 +883,7 @@ static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey, | |
*/ | |
ll_append_head(&head, curr, &tail); | |
curr->active = 0; | |
+ curr->in_group = 0; | |
} | |
} else if (rule == CIPHER_BUMP) { | |
if (curr->active) | |
@@ -945,8 +951,8 @@ static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p, | |
*/ | |
for (i = max_strength_bits; i >= 0; i--) | |
if (number_uses[i] > 0) | |
- ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ORD, i, head_p, | |
- tail_p); | |
+ ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ORD, i, 0, | |
+ head_p, tail_p); | |
OPENSSL_free(number_uses); | |
return 1; | |
@@ -960,7 +966,7 @@ static int ssl_cipher_process_rulestr(const char *rule_str, | |
uint32_t alg_mkey, alg_auth, alg_enc, alg_mac, algo_strength; | |
int min_tls; | |
const char *l, *buf; | |
- int j, multi, found, rule, retval, ok, buflen; | |
+ int j, multi, found, rule, retval, ok, buflen, in_group = 0, has_group = 0; | |
uint32_t cipher_id = 0; | |
char ch; | |
@@ -971,18 +977,66 @@ static int ssl_cipher_process_rulestr(const char *rule_str, | |
if (ch == '\0') | |
break; /* done */ | |
- if (ch == '-') { | |
+ if (in_group) { | |
+ if (ch == ']') { | |
+ if (!in_group) { | |
+ SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, | |
+ SSL_R_UNEXPECTED_GROUP_CLOSE); | |
+ retval = found = in_group = 0; | |
+ break; | |
+ } | |
+ if (*tail_p) | |
+ (*tail_p)->in_group = 0; | |
+ in_group = 0; | |
+ l++; | |
+ continue; | |
+ } | |
+ if (ch == '|') { | |
+ rule = CIPHER_ADD; | |
+ l++; | |
+ continue; | |
+ } else if (!(ch >= 'a' && ch <= 'z') | |
+ && !(ch >= 'A' && ch <= 'Z') | |
+ && !(ch >= '0' && ch <= '9')) { | |
+ SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, | |
+ SSL_R_UNEXPECTED_OPERATOR_IN_GROUP); | |
+ retval = found = in_group = 0; | |
+ break; | |
+ } else { | |
+ rule = CIPHER_ADD; | |
+ } | |
+ } else if (ch == '-') { | |
rule = CIPHER_DEL; | |
l++; | |
} else if (ch == '+') { | |
rule = CIPHER_ORD; | |
l++; | |
+ } else if (ch == '!' && has_group) { | |
+ SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, | |
+ SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); | |
+ retval = found = in_group = 0; | |
+ break; | |
} else if (ch == '!') { | |
rule = CIPHER_KILL; | |
l++; | |
+ } else if (ch == '@' && has_group) { | |
+ SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, | |
+ SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); | |
+ retval = found = in_group = 0; | |
+ break; | |
} else if (ch == '@') { | |
rule = CIPHER_SPECIAL; | |
l++; | |
+ } else if (ch == '[') { | |
+ if (in_group) { | |
+ SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, SSL_R_NESTED_GROUP); | |
+ retval = found = in_group = 0; | |
+ break; | |
+ } | |
+ in_group = 1; | |
+ has_group = 1; | |
+ l++; | |
+ continue; | |
} else { | |
rule = CIPHER_ADD; | |
} | |
@@ -1007,7 +1061,7 @@ static int ssl_cipher_process_rulestr(const char *rule_str, | |
while (((ch >= 'A') && (ch <= 'Z')) || | |
((ch >= '0') && (ch <= '9')) || | |
((ch >= 'a') && (ch <= 'z')) || | |
- (ch == '-') || (ch == '.') || (ch == '=')) | |
+ (ch == '-') || (ch == '.') || (ch == '=') || (ch == '_')) | |
#else | |
while (isalnum((unsigned char)ch) || (ch == '-') || (ch == '.') | |
|| (ch == '=')) | |
@@ -1024,7 +1078,7 @@ static int ssl_cipher_process_rulestr(const char *rule_str, | |
* alphanumeric, so we call this an error. | |
*/ | |
SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, SSL_R_INVALID_COMMAND); | |
- retval = found = 0; | |
+ retval = found = in_group = 0; | |
l++; | |
break; | |
} | |
@@ -1203,8 +1257,8 @@ static int ssl_cipher_process_rulestr(const char *rule_str, | |
} else if (found) { | |
ssl_cipher_apply_rule(cipher_id, | |
alg_mkey, alg_auth, alg_enc, alg_mac, | |
- min_tls, algo_strength, rule, -1, head_p, | |
- tail_p); | |
+ min_tls, algo_strength, rule, -1, in_group, | |
+ head_p, tail_p); | |
} else { | |
while ((*l != '\0') && !ITEM_SEP(*l)) | |
l++; | |
@@ -1213,6 +1267,11 @@ static int ssl_cipher_process_rulestr(const char *rule_str, | |
break; /* done */ | |
} | |
+ if (in_group) { | |
+ SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, SSL_R_INVALID_COMMAND); | |
+ retval = 0; | |
+ } | |
+ | |
return retval; | |
} | |
@@ -1377,7 +1436,7 @@ int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str) | |
if (ret && ctx->cipher_list != NULL) { | |
/* We already have a cipher_list, so we need to update it */ | |
- return update_cipher_list(&ctx->cipher_list, &ctx->cipher_list_by_id, | |
+ return update_cipher_list(&ctx->cipher_list->ciphers, &ctx->cipher_list_by_id, | |
ctx->tls13_ciphersuites); | |
} | |
@@ -1390,7 +1449,7 @@ int SSL_set_ciphersuites(SSL *s, const char *str) | |
if (ret && s->cipher_list != NULL) { | |
/* We already have a cipher_list, so we need to update it */ | |
- return update_cipher_list(&s->cipher_list, &s->cipher_list_by_id, | |
+ return update_cipher_list(&s->cipher_list->ciphers, &s->cipher_list_by_id, | |
s->tls13_ciphersuites); | |
} | |
@@ -1399,17 +1458,20 @@ int SSL_set_ciphersuites(SSL *s, const char *str) | |
STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
STACK_OF(SSL_CIPHER) *tls13_ciphersuites, | |
- STACK_OF(SSL_CIPHER) **cipher_list, | |
+ struct ssl_cipher_preference_list_st **cipher_list, | |
STACK_OF(SSL_CIPHER) **cipher_list_by_id, | |
const char *rule_str, | |
CERT *c) | |
{ | |
- int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases, i; | |
+ int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases; | |
uint32_t disabled_mkey, disabled_auth, disabled_enc, disabled_mac; | |
- STACK_OF(SSL_CIPHER) *cipherstack; | |
+ STACK_OF(SSL_CIPHER) *cipherstack = NULL; | |
const char *rule_p; | |
CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr; | |
const SSL_CIPHER **ca_list = NULL; | |
+ uint8_t *in_group_flags = NULL; | |
+ unsigned int num_in_group_flags = 0; | |
+ struct ssl_cipher_preference_list_st *pref_list = NULL; | |
/* | |
* Return with error if nothing to do. | |
@@ -1458,16 +1520,16 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
* preference). | |
*/ | |
ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, 0, 0, 0, 0, CIPHER_ADD, | |
- -1, &head, &tail); | |
- ssl_cipher_apply_rule(0, SSL_kECDHE, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, | |
- &tail); | |
- ssl_cipher_apply_rule(0, SSL_kECDHE, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, | |
- &tail); | |
+ -1, 0, &head, &tail); | |
+ ssl_cipher_apply_rule(0, SSL_kECDHE, 0, 0, 0, 0, 0, CIPHER_ADD, -1, 0, | |
+ &head, &tail); | |
+ ssl_cipher_apply_rule(0, SSL_kECDHE, 0, 0, 0, 0, 0, CIPHER_DEL, -1, 0, | |
+ &head, &tail); | |
/* Within each strength group, we prefer GCM over CHACHA... */ | |
- ssl_cipher_apply_rule(0, 0, 0, SSL_AESGCM, 0, 0, 0, CIPHER_ADD, -1, | |
+ ssl_cipher_apply_rule(0, 0, 0, SSL_AESGCM, 0, 0, 0, CIPHER_ADD, -1, 0, | |
&head, &tail); | |
- ssl_cipher_apply_rule(0, 0, 0, SSL_CHACHA20, 0, 0, 0, CIPHER_ADD, -1, | |
+ ssl_cipher_apply_rule(0, 0, 0, SSL_CHACHA20, 0, 0, 0, CIPHER_ADD, -1, 0, | |
&head, &tail); | |
/* | |
@@ -1476,13 +1538,13 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
* strength. | |
*/ | |
ssl_cipher_apply_rule(0, 0, 0, SSL_AES ^ SSL_AESGCM, 0, 0, 0, CIPHER_ADD, | |
- -1, &head, &tail); | |
+ -1, 0, &head, &tail); | |
/* Temporarily enable everything else for sorting */ | |
- ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail); | |
+ ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, 0, &head, &tail); | |
/* Low priority for MD5 */ | |
- ssl_cipher_apply_rule(0, 0, 0, 0, SSL_MD5, 0, 0, CIPHER_ORD, -1, &head, | |
+ ssl_cipher_apply_rule(0, 0, 0, 0, SSL_MD5, 0, 0, CIPHER_ORD, -1, 0, &head, | |
&tail); | |
/* | |
@@ -1490,16 +1552,16 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
* disabled. (For applications that allow them, they aren't too bad, but | |
* we prefer authenticated ciphers.) | |
*/ | |
- ssl_cipher_apply_rule(0, 0, SSL_aNULL, 0, 0, 0, 0, CIPHER_ORD, -1, &head, | |
+ ssl_cipher_apply_rule(0, 0, SSL_aNULL, 0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, | |
&tail); | |
- ssl_cipher_apply_rule(0, SSL_kRSA, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, | |
+ ssl_cipher_apply_rule(0, SSL_kRSA, 0, 0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, | |
&tail); | |
- ssl_cipher_apply_rule(0, SSL_kPSK, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, | |
+ ssl_cipher_apply_rule(0, SSL_kPSK, 0, 0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, | |
&tail); | |
/* RC4 is sort-of broken -- move to the end */ | |
- ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, 0, 0, 0, CIPHER_ORD, -1, &head, | |
+ ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, 0, 0, 0, CIPHER_ORD, -1, 0, &head, | |
&tail); | |
/* | |
@@ -1515,7 +1577,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
* Partially overrule strength sort to prefer TLS 1.2 ciphers/PRFs. | |
* TODO(openssl-team): is there an easier way to accomplish all this? | |
*/ | |
- ssl_cipher_apply_rule(0, 0, 0, 0, 0, TLS1_2_VERSION, 0, CIPHER_BUMP, -1, | |
+ ssl_cipher_apply_rule(0, 0, 0, 0, 0, TLS1_2_VERSION, 0, CIPHER_BUMP, -1, 0, | |
&head, &tail); | |
/* | |
@@ -1531,15 +1593,18 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
* Because we now bump ciphers to the top of the list, we proceed in | |
* reverse order of preference. | |
*/ | |
- ssl_cipher_apply_rule(0, 0, 0, 0, SSL_AEAD, 0, 0, CIPHER_BUMP, -1, | |
+ ssl_cipher_apply_rule(0, 0, 0, 0, SSL_AEAD, 0, 0, CIPHER_BUMP, -1, 0, | |
&head, &tail); | |
ssl_cipher_apply_rule(0, SSL_kDHE | SSL_kECDHE, 0, 0, 0, 0, 0, | |
- CIPHER_BUMP, -1, &head, &tail); | |
+ CIPHER_BUMP, -1, 0, &head, &tail); | |
ssl_cipher_apply_rule(0, SSL_kDHE | SSL_kECDHE, 0, 0, SSL_AEAD, 0, 0, | |
- CIPHER_BUMP, -1, &head, &tail); | |
+ CIPHER_BUMP, -1, 0, &head, &tail); | |
+ | |
+ ssl_cipher_apply_rule(0, 0, 0, 0, 0, TLS1_3_VERSION, 0, CIPHER_BUMP, -1, 0, | |
+ &head, &tail); | |
/* Now disable everything (maintaining the ordering!) */ | |
- ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, &tail); | |
+ ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_DEL, -1, 0, &head, &tail); | |
/* | |
* We also need cipher aliases for selecting based on the rule_str. | |
@@ -1553,9 +1618,8 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
num_of_alias_max = num_of_ciphers + num_of_group_aliases + 1; | |
ca_list = OPENSSL_malloc(sizeof(*ca_list) * num_of_alias_max); | |
if (ca_list == NULL) { | |
- OPENSSL_free(co_list); | |
SSLerr(SSL_F_SSL_CREATE_CIPHER_LIST, ERR_R_MALLOC_FAILURE); | |
- return NULL; /* Failure */ | |
+ goto err; /* Failure */ | |
} | |
ssl_cipher_collect_aliases(ca_list, num_of_group_aliases, | |
disabled_mkey, disabled_auth, disabled_enc, | |
@@ -1580,28 +1644,19 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
OPENSSL_free(ca_list); /* Not needed anymore */ | |
- if (!ok) { /* Rule processing failure */ | |
- OPENSSL_free(co_list); | |
- return NULL; | |
- } | |
+ if (!ok) | |
+ goto err; /* Rule processing failure */ | |
/* | |
* Allocate new "cipherstack" for the result, return with error | |
* if we cannot get one. | |
*/ | |
- if ((cipherstack = sk_SSL_CIPHER_new_null()) == NULL) { | |
- OPENSSL_free(co_list); | |
- return NULL; | |
- } | |
+ if ((cipherstack = sk_SSL_CIPHER_new_null()) == NULL) | |
+ goto err; | |
- /* Add TLSv1.3 ciphers first - we always prefer those if possible */ | |
- for (i = 0; i < sk_SSL_CIPHER_num(tls13_ciphersuites); i++) { | |
- if (!sk_SSL_CIPHER_push(cipherstack, | |
- sk_SSL_CIPHER_value(tls13_ciphersuites, i))) { | |
- sk_SSL_CIPHER_free(cipherstack); | |
- return NULL; | |
- } | |
- } | |
+ in_group_flags = OPENSSL_malloc(num_of_ciphers); | |
+ if (!in_group_flags) | |
+ goto err; | |
/* | |
* The cipher selection for the list is done. The ciphers are added | |
@@ -1609,26 +1664,50 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
*/ | |
for (curr = head; curr != NULL; curr = curr->next) { | |
if (curr->active) { | |
- if (!sk_SSL_CIPHER_push(cipherstack, curr->cipher)) { | |
- OPENSSL_free(co_list); | |
- sk_SSL_CIPHER_free(cipherstack); | |
- return NULL; | |
- } | |
+ if (!sk_SSL_CIPHER_push(cipherstack, curr->cipher)) | |
+ goto err; | |
+ in_group_flags[num_in_group_flags++] = curr->in_group; | |
#ifdef CIPHER_DEBUG | |
fprintf(stderr, "<%s>\n", curr->cipher->name); | |
#endif | |
} | |
} | |
- OPENSSL_free(co_list); /* Not needed any longer */ | |
- if (!update_cipher_list_by_id(cipher_list_by_id, cipherstack)) { | |
- sk_SSL_CIPHER_free(cipherstack); | |
- return NULL; | |
- } | |
- sk_SSL_CIPHER_free(*cipher_list); | |
- *cipher_list = cipherstack; | |
+ OPENSSL_free(co_list); /* Not needed any longer */ | |
+ co_list = NULL; | |
+ | |
+ if (!update_cipher_list_by_id(cipher_list_by_id, cipherstack)) | |
+ goto err; | |
+ | |
+ pref_list = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st)); | |
+ if (!pref_list) | |
+ goto err; | |
+ pref_list->ciphers = cipherstack; | |
+ pref_list->in_group_flags = OPENSSL_malloc(num_in_group_flags); | |
+ if (!pref_list->in_group_flags) | |
+ goto err; | |
+ memcpy(pref_list->in_group_flags, in_group_flags, num_in_group_flags); | |
+ OPENSSL_free(in_group_flags); | |
+ in_group_flags = NULL; | |
+ if (*cipher_list != NULL) | |
+ ssl_cipher_preference_list_free(*cipher_list); | |
+ *cipher_list = pref_list; | |
+ pref_list = NULL; | |
return cipherstack; | |
+ | |
+err: | |
+ if (co_list) | |
+ OPENSSL_free(co_list); | |
+ if (in_group_flags) | |
+ OPENSSL_free(in_group_flags); | |
+ if (cipherstack) | |
+ sk_SSL_CIPHER_free(cipherstack); | |
+ if (pref_list && pref_list->in_group_flags) | |
+ OPENSSL_free(pref_list->in_group_flags); | |
+ if (pref_list) | |
+ OPENSSL_free(pref_list); | |
+ return NULL; | |
} | |
char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len) | |
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c | |
index 11331ce41f..cfc770b8d6 100644 | |
--- a/ssl/ssl_err.c | |
+++ b/ssl/ssl_err.c | |
@@ -965,6 +965,9 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_DH_KEY), "missing tmp dh key"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_ECDH_KEY), | |
"missing tmp ecdh key"}, | |
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS), | |
+ "mixed special operator with groups"}, | |
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NESTED_GROUP), "nested group"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_ON_RECORD_BOUNDARY), | |
"not on record boundary"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_REPLACING_CERTIFICATE), | |
@@ -1199,11 +1202,14 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { | |
"unable to load ssl3 md5 routines"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES), | |
"unable to load ssl3 sha1 routines"}, | |
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_GROUP_CLOSE), "unexpected group close"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_CCS_MESSAGE), | |
"unexpected ccs message"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_END_OF_EARLY_DATA), | |
"unexpected end of early data"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_MESSAGE), "unexpected message"}, | |
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP), | |
+ "unexpected operator in group"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_RECORD), "unexpected record"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNINITIALIZED), "uninitialized"}, | |
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_ALERT_TYPE), "unknown alert type"}, | |
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c | |
index ec5b1554f7..f81ae38839 100644 | |
--- a/ssl/ssl_lib.c | |
+++ b/ssl/ssl_lib.c | |
@@ -1117,6 +1117,71 @@ int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm) | |
return X509_VERIFY_PARAM_set1(ssl->param, vpm); | |
} | |
+void ssl_cipher_preference_list_free(struct ssl_cipher_preference_list_st | |
+ *cipher_list) | |
+{ | |
+ sk_SSL_CIPHER_free(cipher_list->ciphers); | |
+ OPENSSL_free(cipher_list->in_group_flags); | |
+ OPENSSL_free(cipher_list); | |
+} | |
+ | |
+struct ssl_cipher_preference_list_st* | |
+ssl_cipher_preference_list_dup(struct ssl_cipher_preference_list_st | |
+ *cipher_list) | |
+{ | |
+ struct ssl_cipher_preference_list_st* ret = NULL; | |
+ size_t n = sk_SSL_CIPHER_num(cipher_list->ciphers); | |
+ | |
+ ret = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st)); | |
+ if (!ret) | |
+ goto err; | |
+ ret->ciphers = NULL; | |
+ ret->in_group_flags = NULL; | |
+ ret->ciphers = sk_SSL_CIPHER_dup(cipher_list->ciphers); | |
+ if (!ret->ciphers) | |
+ goto err; | |
+ ret->in_group_flags = OPENSSL_malloc(n); | |
+ if (!ret->in_group_flags) | |
+ goto err; | |
+ memcpy(ret->in_group_flags, cipher_list->in_group_flags, n); | |
+ return ret; | |
+ | |
+err: | |
+ if (ret->ciphers) | |
+ sk_SSL_CIPHER_free(ret->ciphers); | |
+ if (ret) | |
+ OPENSSL_free(ret); | |
+ return NULL; | |
+} | |
+ | |
+struct ssl_cipher_preference_list_st* | |
+ssl_cipher_preference_list_from_ciphers(STACK_OF(SSL_CIPHER) *ciphers) | |
+{ | |
+ struct ssl_cipher_preference_list_st* ret = NULL; | |
+ size_t n = sk_SSL_CIPHER_num(ciphers); | |
+ | |
+ ret = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st)); | |
+ if (!ret) | |
+ goto err; | |
+ ret->ciphers = NULL; | |
+ ret->in_group_flags = NULL; | |
+ ret->ciphers = sk_SSL_CIPHER_dup(ciphers); | |
+ if (!ret->ciphers) | |
+ goto err; | |
+ ret->in_group_flags = OPENSSL_malloc(n); | |
+ if (!ret->in_group_flags) | |
+ goto err; | |
+ memset(ret->in_group_flags, 0, n); | |
+ return ret; | |
+ | |
+err: | |
+ if (ret->ciphers) | |
+ sk_SSL_CIPHER_free(ret->ciphers); | |
+ if (ret) | |
+ OPENSSL_free(ret); | |
+ return NULL; | |
+} | |
+ | |
X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) | |
{ | |
return ctx->param; | |
@@ -1157,7 +1222,8 @@ void SSL_free(SSL *s) | |
BUF_MEM_free(s->init_buf); | |
/* add extra stuff */ | |
- sk_SSL_CIPHER_free(s->cipher_list); | |
+ if (s->cipher_list != NULL) | |
+ ssl_cipher_preference_list_free(s->cipher_list); | |
sk_SSL_CIPHER_free(s->cipher_list_by_id); | |
sk_SSL_CIPHER_free(s->tls13_ciphersuites); | |
@@ -2426,9 +2492,9 @@ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s) | |
{ | |
if (s != NULL) { | |
if (s->cipher_list != NULL) { | |
- return s->cipher_list; | |
+ return (s->cipher_list->ciphers); | |
} else if ((s->ctx != NULL) && (s->ctx->cipher_list != NULL)) { | |
- return s->ctx->cipher_list; | |
+ return (s->ctx->cipher_list->ciphers); | |
} | |
} | |
return NULL; | |
@@ -2502,8 +2568,8 @@ const char *SSL_get_cipher_list(const SSL *s, int n) | |
* preference */ | |
STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx) | |
{ | |
- if (ctx != NULL) | |
- return ctx->cipher_list; | |
+ if (ctx != NULL && ctx->cipher_list != NULL) | |
+ return ctx->cipher_list->ciphers; | |
return NULL; | |
} | |
@@ -2934,7 +3000,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) | |
ret->tls13_ciphersuites, | |
&ret->cipher_list, &ret->cipher_list_by_id, | |
SSL_DEFAULT_CIPHER_LIST, ret->cert) | |
- || sk_SSL_CIPHER_num(ret->cipher_list) <= 0) { | |
+ || sk_SSL_CIPHER_num(ret->cipher_list->ciphers) <= 0) { | |
SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_LIBRARY_HAS_NO_CIPHERS); | |
goto err2; | |
} | |
@@ -3107,7 +3173,7 @@ void SSL_CTX_free(SSL_CTX *a) | |
#ifndef OPENSSL_NO_CT | |
CTLOG_STORE_free(a->ctlog_store); | |
#endif | |
- sk_SSL_CIPHER_free(a->cipher_list); | |
+ ssl_cipher_preference_list_free(a->cipher_list); | |
sk_SSL_CIPHER_free(a->cipher_list_by_id); | |
sk_SSL_CIPHER_free(a->tls13_ciphersuites); | |
ssl_cert_free(a->cert); | |
@@ -3657,6 +3723,35 @@ const char *SSL_get_version(const SSL *s) | |
return ssl_protocol_to_string(s->version); | |
} | |
+const char *ssl_version_tls13_to_string(int version) | |
+{ | |
+ switch(version) | |
+ { | |
+ case TLS1_3_VERSION_DRAFT_23: | |
+ return "23"; | |
+ | |
+ case TLS1_3_VERSION_DRAFT_26: | |
+ return "26"; | |
+ | |
+ case TLS1_3_VERSION_DRAFT_27: | |
+ return "27"; | |
+ | |
+ case TLS1_3_VERSION_DRAFT: | |
+ return "28"; | |
+ | |
+ case TLS1_3_VERSION: | |
+ return ""; | |
+ | |
+ default: | |
+ return ""; | |
+ } | |
+} | |
+ | |
+const char *SSL_get_version_tls13(const SSL *s) | |
+{ | |
+ return ssl_version_tls13_to_string(s->version_draft); | |
+} | |
+ | |
SSL *SSL_dup(SSL *s) | |
{ | |
STACK_OF(X509_NAME) *sk; | |
@@ -3756,13 +3851,15 @@ SSL *SSL_dup(SSL *s) | |
/* dup the cipher_list and cipher_list_by_id stacks */ | |
if (s->cipher_list != NULL) { | |
- if ((ret->cipher_list = sk_SSL_CIPHER_dup(s->cipher_list)) == NULL) | |
+ ret->cipher_list = ssl_cipher_preference_list_dup(s->cipher_list); | |
+ if (ret->cipher_list == NULL) | |
goto err; | |
} | |
- if (s->cipher_list_by_id != NULL) | |
- if ((ret->cipher_list_by_id = sk_SSL_CIPHER_dup(s->cipher_list_by_id)) | |
- == NULL) | |
+ if (s->cipher_list_by_id != NULL) { | |
+ ret->cipher_list_by_id = sk_SSL_CIPHER_dup(s->cipher_list_by_id); | |
+ if (ret->cipher_list_by_id == NULL) | |
goto err; | |
+ } | |
/* Dup the client_CA list */ | |
if (s->ca_names != NULL) { | |
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h | |
index 8afb117372..00a36e7111 100644 | |
--- a/ssl/ssl_locl.h | |
+++ b/ssl/ssl_locl.h | |
@@ -502,6 +502,7 @@ struct ssl_method_st { | |
struct ssl_session_st { | |
int ssl_version; /* what ssl version session info is being kept | |
* in here? */ | |
+ int ssl_version_draft; | |
size_t master_key_length; | |
/* TLSv1.3 early_secret used for external PSKs */ | |
@@ -737,9 +738,46 @@ typedef struct ssl_ctx_ext_secure_st { | |
unsigned char tick_aes_key[TLSEXT_TICK_KEY_LENGTH]; | |
} SSL_CTX_EXT_SECURE; | |
+/* ssl_cipher_preference_list_st contains a list of SSL_CIPHERs with | |
+ * equal-preference groups. For TLS clients, the groups are moot because the | |
+ * server picks the cipher and groups cannot be expressed on the wire. However, | |
+ * for servers, the equal-preference groups allow the client's preferences to | |
+ * be partially respected. (This only has an effect with | |
+ * SSL_OP_CIPHER_SERVER_PREFERENCE). | |
+ * | |
+ * The equal-preference groups are expressed by grouping SSL_CIPHERs together. | |
+ * All elements of a group have the same priority: no ordering is expressed | |
+ * within a group. | |
+ * | |
+ * The values in |ciphers| are in one-to-one correspondence with | |
+ * |in_group_flags|. (That is, sk_SSL_CIPHER_num(ciphers) is the number of | |
+ * bytes in |in_group_flags|.) The bytes in |in_group_flags| are either 1, to | |
+ * indicate that the corresponding SSL_CIPHER is not the last element of a | |
+ * group, or 0 to indicate that it is. | |
+ * | |
+ * For example, if |in_group_flags| contains all zeros then that indicates a | |
+ * traditional, fully-ordered preference. Every SSL_CIPHER is the last element | |
+ * of the group (i.e. they are all in a one-element group). | |
+ * | |
+ * For a more complex example, consider: | |
+ * ciphers: A B C D E F | |
+ * in_group_flags: 1 1 0 0 1 0 | |
+ * | |
+ * That would express the following, order: | |
+ * | |
+ * A E | |
+ * B -> D -> F | |
+ * C | |
+ */ | |
+struct ssl_cipher_preference_list_st { | |
+ STACK_OF(SSL_CIPHER) *ciphers; | |
+ uint8_t *in_group_flags; | |
+}; | |
+ | |
+ | |
struct ssl_ctx_st { | |
const SSL_METHOD *method; | |
- STACK_OF(SSL_CIPHER) *cipher_list; | |
+ struct ssl_cipher_preference_list_st *cipher_list; | |
/* same as above but sorted for lookup */ | |
STACK_OF(SSL_CIPHER) *cipher_list_by_id; | |
/* TLSv1.3 specific ciphersuites */ | |
@@ -1074,6 +1112,8 @@ struct ssl_st { | |
* DTLS1_VERSION) | |
*/ | |
int version; | |
+ /* TODO(TLS1.3): Remove this before release */ | |
+ int version_draft; | |
/* SSLv3 */ | |
const SSL_METHOD *method; | |
/* | |
@@ -1132,7 +1172,7 @@ struct ssl_st { | |
/* Per connection DANE state */ | |
SSL_DANE dane; | |
/* crypto */ | |
- STACK_OF(SSL_CIPHER) *cipher_list; | |
+ struct ssl_cipher_preference_list_st *cipher_list; | |
STACK_OF(SSL_CIPHER) *cipher_list_by_id; | |
/* TLSv1.3 specific ciphersuites */ | |
STACK_OF(SSL_CIPHER) *tls13_ciphersuites; | |
@@ -2214,6 +2254,7 @@ struct openssl_ssl_test_functions { | |
}; | |
const char *ssl_protocol_to_string(int version); | |
+const char *ssl_version_tls13_to_string(int version); | |
/* Returns true if certificate and private key for 'idx' are present */ | |
static ossl_inline int ssl_has_cert(const SSL *s, int idx) | |
@@ -2253,7 +2294,7 @@ __owur int ssl_cipher_ptr_id_cmp(const SSL_CIPHER *const *ap, | |
const SSL_CIPHER *const *bp); | |
__owur STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, | |
STACK_OF(SSL_CIPHER) *tls13_ciphersuites, | |
- STACK_OF(SSL_CIPHER) **cipher_list, | |
+ struct ssl_cipher_preference_list_st **cipher_list, | |
STACK_OF(SSL_CIPHER) **cipher_list_by_id, | |
const char *rule_str, | |
CERT *c); | |
@@ -2263,6 +2304,13 @@ __owur int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites, | |
STACK_OF(SSL_CIPHER) **scsvs, int sslv2format, | |
int fatal); | |
void ssl_update_cache(SSL *s, int mode); | |
+struct ssl_cipher_preference_list_st* ssl_cipher_preference_list_dup( | |
+ struct ssl_cipher_preference_list_st *cipher_list); | |
+void ssl_cipher_preference_list_free( | |
+ struct ssl_cipher_preference_list_st *cipher_list); | |
+struct ssl_cipher_preference_list_st* ssl_cipher_preference_list_from_ciphers( | |
+ STACK_OF(SSL_CIPHER) *ciphers); | |
+struct ssl_cipher_preference_list_st* ssl_get_cipher_preferences(SSL *s); | |
__owur int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, | |
const EVP_MD **md, int *mac_pkey_type, | |
size_t *mac_secret_size, SSL_COMP **comp, | |
@@ -2346,7 +2394,7 @@ __owur unsigned long ssl3_output_cert_chain(SSL *s, WPACKET *pkt, | |
CERT_PKEY *cpk); | |
__owur const SSL_CIPHER *ssl3_choose_cipher(SSL *ssl, | |
STACK_OF(SSL_CIPHER) *clnt, | |
- STACK_OF(SSL_CIPHER) *srvr); | |
+ struct ssl_cipher_preference_list_st *srvr); | |
__owur int ssl3_digest_cached_records(SSL *s, int keep); | |
__owur int ssl3_new(SSL *s); | |
void ssl3_free(SSL *s); | |
diff --git a/ssl/ssl_txt.c b/ssl/ssl_txt.c | |
index cf6e4c3c05..1cde358cbc 100644 | |
--- a/ssl/ssl_txt.c | |
+++ b/ssl/ssl_txt.c | |
@@ -40,8 +40,17 @@ int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x) | |
istls13 = (x->ssl_version == TLS1_3_VERSION); | |
if (BIO_puts(bp, "SSL-Session:\n") <= 0) | |
goto err; | |
+ | |
s = ssl_protocol_to_string(x->ssl_version); | |
- if (BIO_printf(bp, " Protocol : %s\n", s) <= 0) | |
+ if (BIO_printf(bp, " Protocol : %s", s) <= 0) | |
+ goto err; | |
+ | |
+ s = ssl_version_tls13_to_string(x->ssl_version_draft); | |
+ if (strlen(s) > 0) | |
+ if (BIO_printf(bp, " (draft %s)", s) <= 0) | |
+ goto err; | |
+ | |
+ if (BIO_puts(bp, "\n") <= 0) | |
goto err; | |
if (x->cipher == NULL) { | |
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c | |
index 8422161dc1..6e59b01d42 100644 | |
--- a/ssl/statem/extensions.c | |
+++ b/ssl/statem/extensions.c | |
@@ -998,7 +998,9 @@ static int final_server_name(SSL *s, unsigned int context, int sent) | |
switch (ret) { | |
case SSL_TLSEXT_ERR_ALERT_FATAL: | |
- SSLfatal(s, altmp, SSL_F_FINAL_SERVER_NAME, SSL_R_CALLBACK_FAILED); | |
+ s->statem.in_init = 1; | |
+ s->statem.state = MSG_FLOW_ERROR; | |
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_F_FINAL_RENEGOTIATE); | |
return 0; | |
case SSL_TLSEXT_ERR_ALERT_WARNING: | |
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c | |
index 4b5e6fe2b8..99981c9e37 100644 | |
--- a/ssl/statem/extensions_clnt.c | |
+++ b/ssl/statem/extensions_clnt.c | |
@@ -530,8 +530,25 @@ EXT_RETURN tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, | |
return EXT_RETURN_FAIL; | |
} | |
+ /* | |
+ * TODO(TLS1.3): There is some discussion on the TLS list as to whether | |
+ * we should include versions <TLS1.2. For the moment we do. To be | |
+ * reviewed later. | |
+ */ | |
for (currv = max_version; currv >= min_version; currv--) { | |
- if (!WPACKET_put_bytes_u16(pkt, currv)) { | |
+ /* TODO(TLS1.3): Remove this first if clause prior to release!! */ | |
+ if (currv == TLS1_3_VERSION) { | |
+ if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION) | |
+ || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT) | |
+ || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT_27) | |
+ || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT_26) | |
+ || !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT_23)) { | |
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, | |
+ SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS, | |
+ ERR_R_INTERNAL_ERROR); | |
+ return EXT_RETURN_FAIL; | |
+ } | |
+ } else if (!WPACKET_put_bytes_u16(pkt, currv)) { | |
SSLfatal(s, SSL_AD_INTERNAL_ERROR, | |
SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_VERSIONS, | |
ERR_R_INTERNAL_ERROR); | |
@@ -1760,6 +1777,15 @@ int tls_parse_stoc_supported_versions(SSL *s, PACKET *pkt, unsigned int context, | |
return 0; | |
} | |
+ /* TODO(TLS1.3): Remove this before release */ | |
+ if (version == TLS1_3_VERSION_DRAFT | |
+ || version == TLS1_3_VERSION_DRAFT_27 | |
+ || version == TLS1_3_VERSION_DRAFT_26 | |
+ || version == TLS1_3_VERSION_DRAFT_23) { | |
+ s->version_draft = version; | |
+ version = TLS1_3_VERSION; | |
+ } | |
+ | |
/* | |
* The only protocol version we support which is valid in this extension in | |
* a ServerHello is TLSv1.3 therefore we shouldn't be getting anything else. | |
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c | |
index 0f2b22392b..6c1ce9813f 100644 | |
--- a/ssl/statem/extensions_srvr.c | |
+++ b/ssl/statem/extensions_srvr.c | |
@@ -897,7 +897,8 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, | |
} | |
if (!WPACKET_put_bytes_u16(&hrrpkt, TLSEXT_TYPE_supported_versions) | |
|| !WPACKET_start_sub_packet_u16(&hrrpkt) | |
- || !WPACKET_put_bytes_u16(&hrrpkt, s->version) | |
+ /* TODO(TLS1.3): Fix this before release */ | |
+ || !WPACKET_put_bytes_u16(&hrrpkt, s->version_draft) | |
|| !WPACKET_close(&hrrpkt)) { | |
WPACKET_cleanup(&hrrpkt); | |
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE, | |
@@ -1652,7 +1653,8 @@ EXT_RETURN tls_construct_stoc_supported_versions(SSL *s, WPACKET *pkt, | |
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions) | |
|| !WPACKET_start_sub_packet_u16(pkt) | |
- || !WPACKET_put_bytes_u16(pkt, s->version) | |
+ /* TODO(TLS1.3): Update to remove the TLSv1.3 draft indicator */ | |
+ || !WPACKET_put_bytes_u16(pkt, s->version_draft) | |
|| !WPACKET_close(pkt)) { | |
SSLfatal(s, SSL_AD_INTERNAL_ERROR, | |
SSL_F_TLS_CONSTRUCT_STOC_SUPPORTED_VERSIONS, | |
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c | |
index 8c658da899..08b84dfe32 100644 | |
--- a/ssl/statem/statem_clnt.c | |
+++ b/ssl/statem/statem_clnt.c | |
@@ -1631,6 +1631,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) | |
} | |
s->session->ssl_version = s->version; | |
+ s->session->ssl_version_draft = s->version_draft; | |
/* | |
* In TLSv1.2 and below we save the session id we were sent so we can | |
* resume it later. In TLSv1.3 the session id we were sent is just an | |
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c | |
index 508bb88767..ee927baf64 100644 | |
--- a/ssl/statem/statem_lib.c | |
+++ b/ssl/statem/statem_lib.c | |
@@ -1753,6 +1753,8 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd) | |
unsigned int best_vers = 0; | |
const SSL_METHOD *best_method = NULL; | |
PACKET versionslist; | |
+ /* TODO(TLS1.3): Remove this before release */ | |
+ unsigned int orig_candidate = 0; | |
suppversions->parsed = 1; | |
@@ -1774,6 +1776,23 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd) | |
return SSL_R_BAD_LEGACY_VERSION; | |
while (PACKET_get_net_2(&versionslist, &candidate_vers)) { | |
+ /* TODO(TLS1.3): Remove this before release */ | |
+ if (candidate_vers == TLS1_3_VERSION | |
+ || candidate_vers == TLS1_3_VERSION_DRAFT | |
+ || candidate_vers == TLS1_3_VERSION_DRAFT_26 | |
+ || candidate_vers == TLS1_3_VERSION_DRAFT_23) { | |
+ if (best_vers == TLS1_3_VERSION | |
+ && (orig_candidate > candidate_vers | |
+ || orig_candidate == TLS1_3_VERSION)) | |
+ continue; | |
+ orig_candidate = candidate_vers; | |
+ candidate_vers = TLS1_3_VERSION; | |
+ } | |
+ /* | |
+ * TODO(TLS1.3): There is some discussion on the TLS list about | |
+ * whether to ignore versions <TLS1.2 in supported_versions. At the | |
+ * moment we honour them if present. To be reviewed later | |
+ */ | |
if (version_cmp(s, candidate_vers, best_vers) <= 0) | |
continue; | |
if (ssl_version_supported(s, candidate_vers, &best_method)) | |
@@ -1796,6 +1815,9 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd) | |
} | |
check_for_downgrade(s, best_vers, dgrd); | |
s->version = best_vers; | |
+ /* TODO(TLS1.3): Remove this before release */ | |
+ if (best_vers == TLS1_3_VERSION) | |
+ s->version_draft = orig_candidate; | |
s->method = best_method; | |
return 0; | |
} | |
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c | |
index 346b1e3989..0a747f39ce 100644 | |
--- a/ssl/statem/statem_srvr.c | |
+++ b/ssl/statem/statem_srvr.c | |
@@ -1742,7 +1742,7 @@ static int tls_early_post_process_client_hello(SSL *s) | |
/* For TLSv1.3 we must select the ciphersuite *before* session resumption */ | |
if (SSL_IS_TLS13(s)) { | |
const SSL_CIPHER *cipher = | |
- ssl3_choose_cipher(s, ciphers, SSL_get_ciphers(s)); | |
+ ssl3_choose_cipher(s, ciphers, ssl_get_cipher_preferences(s)); | |
if (cipher == NULL) { | |
SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, | |
@@ -1923,7 +1923,7 @@ static int tls_early_post_process_client_hello(SSL *s) | |
/* check if some cipher was preferred by call back */ | |
if (pref_cipher == NULL) | |
pref_cipher = ssl3_choose_cipher(s, s->session->ciphers, | |
- SSL_get_ciphers(s)); | |
+ ssl_get_cipher_preferences(s)); | |
if (pref_cipher == NULL) { | |
SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, | |
SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, | |
@@ -1932,8 +1932,9 @@ static int tls_early_post_process_client_hello(SSL *s) | |
} | |
s->session->cipher = pref_cipher; | |
- sk_SSL_CIPHER_free(s->cipher_list); | |
- s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); | |
+ ssl_cipher_preference_list_free(s->cipher_list); | |
+ s->cipher_list = ssl_cipher_preference_list_from_ciphers( | |
+ s->session->ciphers); | |
sk_SSL_CIPHER_free(s->cipher_list_by_id); | |
s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); | |
} | |
@@ -2245,7 +2246,7 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst) | |
/* In TLSv1.3 we selected the ciphersuite before resumption */ | |
if (!SSL_IS_TLS13(s)) { | |
cipher = | |
- ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s)); | |
+ ssl3_choose_cipher(s, s->session->ciphers, ssl_get_cipher_preferences(s)); | |
if (cipher == NULL) { | |
SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE, | |
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c | |
index be3039af38..99c4ddcb41 100644 | |
--- a/ssl/t1_trce.c | |
+++ b/ssl/t1_trce.c | |
@@ -65,6 +65,11 @@ static const ssl_trace_tbl ssl_version_tbl[] = { | |
{TLS1_1_VERSION, "TLS 1.1"}, | |
{TLS1_2_VERSION, "TLS 1.2"}, | |
{TLS1_3_VERSION, "TLS 1.3"}, | |
+ /* TODO(TLS1.3): Remove these lines before release */ | |
+ {TLS1_3_VERSION_DRAFT_23, TLS1_3_VERSION_DRAFT_TXT_23}, | |
+ {TLS1_3_VERSION_DRAFT_26, TLS1_3_VERSION_DRAFT_TXT_26}, | |
+ {TLS1_3_VERSION_DRAFT_27, TLS1_3_VERSION_DRAFT_TXT_27}, | |
+ {TLS1_3_VERSION_DRAFT, TLS1_3_VERSION_DRAFT_TXT}, | |
{DTLS1_VERSION, "DTLS 1.0"}, | |
{DTLS1_2_VERSION, "DTLS 1.2"}, | |
{DTLS1_BAD_VER, "DTLS 1.0 (bad)"} | |
@@ -638,8 +643,19 @@ static int ssl_print_version(BIO *bio, int indent, const char *name, | |
if (*pmsglen < 2) | |
return 0; | |
vers = ((*pmsg)[0] << 8) | (*pmsg)[1]; | |
- if (version != NULL) | |
- *version = vers; | |
+ if (version != NULL) { | |
+ /* TODO(TLS1.3): Remove the draft conditional here before release */ | |
+ switch(vers) { | |
+ case TLS1_3_VERSION_DRAFT_23: | |
+ case TLS1_3_VERSION_DRAFT_26: | |
+ case TLS1_3_VERSION_DRAFT_27: | |
+ case TLS1_3_VERSION_DRAFT: | |
+ *version = TLS1_3_VERSION; | |
+ break; | |
+ default: | |
+ *version = vers; | |
+ } | |
+ } | |
BIO_indent(bio, indent, 80); | |
BIO_printf(bio, "%s=0x%x (%s)\n", | |
name, vers, ssl_trace_str(vers, ssl_version_tbl)); | |
diff --git a/util/libssl.num b/util/libssl.num | |
index ccf73411a9..9c53af24a5 100644 | |
--- a/util/libssl.num | |
+++ b/util/libssl.num | |
@@ -497,3 +497,5 @@ SSL_get_recv_max_early_data 497 1_1_1 EXIST::FUNCTION: | |
SSL_CTX_get_recv_max_early_data 498 1_1_1 EXIST::FUNCTION: | |
SSL_CTX_set_recv_max_early_data 499 1_1_1 EXIST::FUNCTION: | |
SSL_CTX_set_post_handshake_auth 500 1_1_1 EXIST::FUNCTION: | |
+SSL_get_version_tls13 501 1_1_1 EXIST::FUNCTION: | |
+ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment