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));