From 8d3b5227599bb181f8cddba8b4c0b12c75cbca7a Mon Sep 17 00:00:00 2001 From: Hakase <hakase@hakase.app> Date: Thu, 27 Sep 2018 02:31:20 +0900 Subject: [PATCH] Add nginx Renegotiation bugfix and OpenSSL 1.1.2-dev patch --- README.md | 17 +- ...x_openssl-1.1.x_renegotiation_bugfix.patch | 25 + openssl-equal-1.1.2-dev.patch | 1273 ++++++++++++++++ openssl-equal-1.1.2-dev_ciphers.patch | 1308 +++++++++++++++++ 4 files changed, 2618 insertions(+), 5 deletions(-) create mode 100644 nginx_openssl-1.1.x_renegotiation_bugfix.patch create mode 100644 openssl-equal-1.1.2-dev.patch create mode 100644 openssl-equal-1.1.2-dev_ciphers.patch diff --git a/README.md b/README.md index 056c507..4de057b 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,8 @@ Here is the basic patch content. | Patch file name | Patch list | | :--- | :--- | -| openssl-equal-1.1.1.patch | Support **final (TLS 1.3)**, TLS 1.3 cipher settings **_can not_** be changed on _nginx_. | -| openssl-equal-1.1.1_ciphers.patch | Support **final (TLS 1.3)**, TLS 1.3 cipher settings **_can_** be changed on _nginx_. | +| openssl-equal-1.1.1.patch<br>openssl-equal-1.1.2-dev.patch | Support **final (TLS 1.3)**, TLS 1.3 cipher settings **_can not_** be changed on _nginx_. | +| openssl-equal-1.1.1_ciphers.patch<br>openssl-equal-1.1.2-dev_ciphers.patch | Support **final (TLS 1.3)**, TLS 1.3 cipher settings **_can_** be changed on _nginx_. | | openssl-ignore_log_strict-sni.patch | When using nginx_strict-sni.patch, nginx ignores the error in error.log. [View issue](https://github.com/hakasenyang/openssl-patch/issues/1#issuecomment-421594901) | **The "_ciphers" patch file is a temporary change to the TLS 1.3 configuration.** @@ -68,6 +68,7 @@ Example of setting TLS 1.3 cipher in nginx: | remove_nginx_server_header.patch | Remove nginx server header. (http2, http1.1) | | nginx_hpack_remove_server_header_1.15.3.patch | HPACK + Remove nginx server header. (http2, http1.1) | | nginx_strict-sni.patch | Enable **Strict-SNI**. Thanks [@JemmyLoveJenny](https://github.com/JemmyLoveJenny). [View issue](https://github.com/hakasenyang/openssl-patch/issues/1#issuecomment-421551872) | +| nginx_openssl-1.1.x_renegotiation_bugfix.patch | Bugfix **Secure Client-Initiated Renegotiation**. (Check testssl.sh) OpenSSL >= 1.1.1 | ## How To Use? @@ -77,7 +78,7 @@ Example of setting TLS 1.3 cipher in nginx: git clone https://github.com/openssl/openssl.git git clone https://github.com/hakasenyang/openssl-patch.git cd openssl -patch -p1 < ../openssl-patch/openssl-equal-1.1.1_ciphers.patch +patch -p1 < ../openssl-patch/openssl-equal-1.1.2-dev_ciphers.patch ``` And then use --with-openssl in nginx or build after ./config. @@ -116,6 +117,12 @@ Finally, build nginx. Example patch is [here](https://github.com/hakasenyang/nginx-build/blob/master/strict-sni-example.patch). (nginx) +### nginx OpenSSL-1.1.x Renegotiation Bugfix + +Run it from the nginx directory. + +``curl https://raw.githubusercontent.com/hakasenyang/openssl-patch/master/nginx_openssl-1.1.x_renegotiation_bugfix.patch | patch -p1`` + ## nginx Configuration ### HPACK Patch @@ -130,12 +137,12 @@ ssl_ecdh_curve X25519:P-256:P-384; ssl_prefer_server_ciphers on; ``` -### OpenSSL-1.1.1 ciphers (draft 23, 26, 28, final) +### OpenSSL-1.1.x (> 1.1.1) ciphers (draft 23, 26, 28, final) ``` [EECDH+ECDSA+AESGCM+AES128|EECDH+ECDSA+CHACHA20]:EECDH+ECDSA+AESGCM+AES256:EECDH+ECDSA+AES128+SHA:EECDH+ECDSA+AES256+SHA:[EECDH+aRSA+AESGCM+AES128|EECDH+aRSA+CHACHA20]:EECDH+aRSA+AESGCM+AES256:EECDH+aRSA+AES128+SHA:EECDH+aRSA+AES256+SHA:RSA+AES128+SHA:RSA+AES256+SHA:RSA+3DES ``` -### OpenSSL-1.1.1_ciphers ciphers (draft 23, 26, 28, final) +### OpenSSL-1.1.x_ciphers (> 1.1.1) ciphers (draft 23, 26, 28, final) ``` [TLS13+AESGCM+AES128|TLS13+AESGCM+AES256|TLS13+CHACHA20]:[EECDH+ECDSA+AESGCM+AES128|EECDH+ECDSA+CHACHA20]:EECDH+ECDSA+AESGCM+AES256:EECDH+ECDSA+AES128+SHA:EECDH+ECDSA+AES256+SHA:[EECDH+aRSA+AESGCM+AES128|EECDH+aRSA+CHACHA20]:EECDH+aRSA+AESGCM+AES256:EECDH+aRSA+AES128+SHA:EECDH+aRSA+AES256+SHA:RSA+AES128+SHA:RSA+AES256+SHA:RSA+3DES ``` diff --git a/nginx_openssl-1.1.x_renegotiation_bugfix.patch b/nginx_openssl-1.1.x_renegotiation_bugfix.patch new file mode 100644 index 0000000..b896c83 --- /dev/null +++ b/nginx_openssl-1.1.x_renegotiation_bugfix.patch @@ -0,0 +1,25 @@ +diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c +index 3a0e150d..f080b2d7 100644 +--- a/src/event/ngx_event_openssl.c ++++ b/src/event/ngx_event_openssl.c +@@ -350,6 +350,10 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) + SSL_CTX_set_max_proto_version(ssl->ctx, TLS1_3_VERSION); + #endif + ++#ifdef SSL_OP_NO_RENEGOTIATION ++ SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_RENEGOTIATION); ++#endif ++ + #ifdef SSL_OP_NO_COMPRESSION + SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION); + #endif +@@ -1294,9 +1298,6 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) + } else { + SSL_set_accept_state(sc->connection); + +-#ifdef SSL_OP_NO_RENEGOTIATION +- SSL_set_options(sc->connection, SSL_OP_NO_RENEGOTIATION); +-#endif + } + + if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) { diff --git a/openssl-equal-1.1.2-dev.patch b/openssl-equal-1.1.2-dev.patch new file mode 100644 index 0000000..38ce6ea --- /dev/null +++ b/openssl-equal-1.1.2-dev.patch @@ -0,0 +1,1273 @@ +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..c31597584b 100644 +--- a/include/openssl/ssl.h ++++ b/include/openssl/ssl.h +@@ -173,12 +173,12 @@ extern "C" { + # define SSL_DEFAULT_CIPHER_LIST "ALL:!COMPLEMENTOFDEFAULT:!eNULL" + /* This is the default set of TLSv1.3 ciphersuites */ + # if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) +-# define TLS_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384:" \ ++# define TLS_DEFAULT_CIPHERSUITES "TLS_AES_128_GCM_SHA256:" \ + "TLS_CHACHA20_POLY1305_SHA256:" \ +- "TLS_AES_128_GCM_SHA256" ++ "TLS_AES_256_GCM_SHA384" + # else +-# define TLS_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384:" \ +- "TLS_AES_128_GCM_SHA256" ++# define TLS_DEFAULT_CIPHERSUITES "TLS_AES_128_GCM_SHA256:" \ ++ "TLS_AES_256_GCM_SHA384" + #endif + /* + * As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always +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..5a3f9e2c27 100644 +--- a/ssl/s3_lib.c ++++ b/ssl/s3_lib.c +@@ -167,7 +167,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 +232,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 +296,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 +4104,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 +4124,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 +4168,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 +4205,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 +4236,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 +4256,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 +4271,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 +4283,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..165f1c83b1 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; + +@@ -679,6 +680,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 +774,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 +783,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 +862,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 +870,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 +882,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 +950,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 +965,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 +976,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; + } +@@ -1024,7 +1077,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 +1256,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 +1266,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 +1435,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 +1448,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 +1457,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, i, tls13_len; + 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; ++ const SSL_CIPHER **ca_list = NULL, *tmp = 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 +1519,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 +1537,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 +1551,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 +1576,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 +1592,15 @@ 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); + + /* 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 +1614,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,27 +1640,35 @@ 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; ++ ++ in_group_flags = OPENSSL_malloc(num_of_ciphers); ++ if (!in_group_flags) ++ goto err; + + /* Add TLSv1.3 ciphers first - we always prefer those if possible */ +- for (i = 0; i < sk_SSL_CIPHER_num(tls13_ciphersuites); i++) { ++ tls13_len = sk_SSL_CIPHER_num(tls13_ciphersuites); ++ for (i = 0; i < tls13_len; i++) { ++ tmp = sk_SSL_CIPHER_value(tls13_ciphersuites, i); + if (!sk_SSL_CIPHER_push(cipherstack, +- sk_SSL_CIPHER_value(tls13_ciphersuites, i))) { +- sk_SSL_CIPHER_free(cipherstack); +- return NULL; ++ tmp)) ++ goto err; ++ /* Temporary - AES128, CHACHA20 priority adjustment of TLS 1.3. */ ++ if (tmp->algorithm_enc == SSL_AES128GCM && ++ tls13_len > (i + 1)) { ++ tmp = sk_SSL_CIPHER_value(tls13_ciphersuites, i + 1); ++ in_group_flags[num_in_group_flags++] = (tmp->algorithm_enc == SSL_CHACHA20POLY1305) ? 1 : 0; + } ++ else ++ in_group_flags[num_in_group_flags++] = 0; + } + + /* +@@ -1609,26 +1677,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..a80c81ac9e 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); +@@ -3756,13 +3822,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 c22c1f9ee8..cf1b0c6081 100644 +--- a/ssl/ssl_locl.h ++++ b/ssl/ssl_locl.h +@@ -741,9 +741,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 */ +@@ -1078,6 +1115,8 @@ struct ssl_st { + * DTLS1_VERSION) + */ + int version; ++ /* TODO(TLS1.3): Remove this before release */ ++ int version_draft; + /* SSLv3 */ + const SSL_METHOD *method; + /* +@@ -1136,7 +1175,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; +@@ -2257,7 +2296,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); +@@ -2267,6 +2306,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, +@@ -2350,7 +2396,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/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_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 95f83c8462..ed69108a62 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); + } +@@ -2247,7 +2248,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/openssl-equal-1.1.2-dev_ciphers.patch b/openssl-equal-1.1.2-dev_ciphers.patch new file mode 100644 index 0000000..ffa527e --- /dev/null +++ b/openssl-equal-1.1.2-dev_ciphers.patch @@ -0,0 +1,1308 @@ +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/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..a80c81ac9e 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); +@@ -3756,13 +3822,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 c22c1f9ee8..cf1b0c6081 100644 +--- a/ssl/ssl_locl.h ++++ b/ssl/ssl_locl.h +@@ -741,9 +741,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 */ +@@ -1078,6 +1115,8 @@ struct ssl_st { + * DTLS1_VERSION) + */ + int version; ++ /* TODO(TLS1.3): Remove this before release */ ++ int version_draft; + /* SSLv3 */ + const SSL_METHOD *method; + /* +@@ -1136,7 +1175,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; +@@ -2257,7 +2296,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); +@@ -2267,6 +2306,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, +@@ -2350,7 +2396,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/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_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 95f83c8462..ed69108a62 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); + } +@@ -2247,7 +2248,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));