diff --git a/README.md b/README.md
index 8ee7d0f..b12958f 100644
--- a/README.md
+++ b/README.md
@@ -45,9 +45,9 @@ Here is the basic patch content.
| Patch file name | Patch list |
| :--- | :--- |
-| openssl-equal-1.1.1a.patch
openssl-equal-3.0.0-dev.patch | Support **final (TLS 1.3)**, TLS 1.3 cipher settings **_can not_** be changed on _nginx_. |
-| openssl-equal-1.1.1a_ciphers.patch
openssl-equal-3.0.0-dev_ciphers.patch | Support **final (TLS 1.3)**, TLS 1.3 cipher settings **_can_** be changed on _nginx_. |
-| openssl-1.1.1a-chacha_draft.patch
openssl-3.0.0-dev-chacha_draft.patch | A draft version of chacha20-poly1305 is available. [View issue](https://github.com/hakasenyang/openssl-patch/issues/1#issuecomment-427554824) |
+| openssl-equal-1.1.1(x).patch
openssl-equal-3.0.0-dev.patch | Support **final (TLS 1.3)**, TLS 1.3 cipher settings **_can not_** be changed on _nginx_. |
+| openssl-equal-1.1.1(x)_ciphers.patch
openssl-equal-3.0.0-dev_ciphers.patch | Support **final (TLS 1.3)**, TLS 1.3 cipher settings **_can_** be changed on _nginx_. |
+| openssl-1.1.1(x)-chacha_draft.patch
openssl-3.0.0-dev-chacha_draft.patch | A draft version of chacha20-poly1305 is available. [View issue](https://github.com/hakasenyang/openssl-patch/issues/1#issuecomment-427554824) |
| openssl-1.1.1a-tls13_draft.patch | Only for **TLS 1.3 draft 23, 26, 28, final support patch**. |
| openssl-1.1.1a-tls13_nginx_config.patch | You can set TLS 1.3 ciphere in nginx. ex) TLS13+AESGCM+AES128 |
| openssl-1.1.1c-prioritize_chacha_draft.patch | Priority applied patch for CHACHA20 and CHACHA20-DRAFT. [View Pull Request](https://github.com/hakasenyang/openssl-patch/pull/17) |
diff --git a/openssl-1.1.1d-chacha_draft.patch b/openssl-1.1.1d-chacha_draft.patch
new file mode 100644
index 0000000..08d8321
--- /dev/null
+++ b/openssl-1.1.1d-chacha_draft.patch
@@ -0,0 +1,509 @@
+diff --git a/crypto/evp/c_allc.c b/crypto/evp/c_allc.c
+index 086b3c4d51..5699901f7d 100644
+--- a/crypto/evp/c_allc.c
++++ b/crypto/evp/c_allc.c
+@@ -261,6 +261,7 @@ void openssl_add_all_ciphers_int(void)
+ EVP_add_cipher(EVP_chacha20());
+ # ifndef OPENSSL_NO_POLY1305
+ EVP_add_cipher(EVP_chacha20_poly1305());
++ EVP_add_cipher(EVP_chacha20_poly1305_draft());
+ # endif
+ #endif
+ }
+diff --git a/crypto/evp/e_chacha20_poly1305.c b/crypto/evp/e_chacha20_poly1305.c
+index 600365d2f0..fce66d074d 100644
+--- a/crypto/evp/e_chacha20_poly1305.c
++++ b/crypto/evp/e_chacha20_poly1305.c
+@@ -156,6 +156,7 @@ typedef struct {
+ struct { uint64_t aad, text; } len;
+ int aad, mac_inited, tag_len, nonce_len;
+ size_t tls_payload_length;
++ unsigned char draft:1;
+ } EVP_CHACHA_AEAD_CTX;
+
+ # define NO_TLS_PAYLOAD_LENGTH ((size_t)-1)
+@@ -176,6 +177,7 @@ static int chacha20_poly1305_init_key(EVP_CIPHER_CTX *ctx,
+ actx->aad = 0;
+ actx->mac_inited = 0;
+ actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
++ actx->draft = 0;
+
+ if (iv != NULL) {
+ unsigned char temp[CHACHA_CTR_SIZE] = { 0 };
+@@ -197,6 +199,27 @@ static int chacha20_poly1305_init_key(EVP_CIPHER_CTX *ctx,
+ return 1;
+ }
+
++static int chacha20_poly1305_draft_init_key(EVP_CIPHER_CTX *ctx,
++ const unsigned char *inkey,
++ const unsigned char *iv, int enc)
++{
++ EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
++
++ if (!inkey)
++ return 1;
++
++ actx->len.aad = 0;
++ actx->len.text = 0;
++ actx->aad = 0;
++ actx->mac_inited = 0;
++ actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
++ actx->draft = 1;
++
++ chacha_init_key(ctx, inkey, NULL, enc);
++
++ return 1;
++}
++
+ # if !defined(OPENSSL_SMALL_FOOTPRINT)
+
+ # if defined(POLY1305_ASM) && (defined(__x86_64) || defined(__x86_64__) || \
+@@ -367,10 +390,11 @@ static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ {
+ EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
+ size_t rem, plen = actx->tls_payload_length;
++ uint64_t thirteen = EVP_AEAD_TLS1_AAD_LEN;
+
+ if (!actx->mac_inited) {
+ # if !defined(OPENSSL_SMALL_FOOTPRINT)
+- if (plen != NO_TLS_PAYLOAD_LENGTH && out != NULL)
++ if (plen != NO_TLS_PAYLOAD_LENGTH && out != NULL && !actx->draft)
+ return chacha20_poly1305_tls_cipher(ctx, out, in, len);
+ # endif
+ actx->key.counter[0] = 0;
+@@ -397,9 +421,14 @@ static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ return len;
+ } else { /* plain- or ciphertext */
+ if (actx->aad) { /* wrap up aad */
+- if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))
+- Poly1305_Update(POLY1305_ctx(actx), zero,
+- POLY1305_BLOCK_SIZE - rem);
++ if (actx->draft) {
++ thirteen = actx->len.aad;
++ Poly1305_Update(POLY1305_ctx(actx), (const unsigned char *)&thirteen, sizeof(thirteen));
++ } else {
++ if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))
++ Poly1305_Update(POLY1305_ctx(actx), zero,
++ POLY1305_BLOCK_SIZE - rem);
++ }
+ actx->aad = 0;
+ }
+
+@@ -432,40 +461,52 @@ static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ } is_endian = { 1 };
+ unsigned char temp[POLY1305_BLOCK_SIZE];
+
++ if (actx->draft) {
++ thirteen = actx->len.text;
++ Poly1305_Update(POLY1305_ctx(actx), (const unsigned char *)&thirteen, sizeof(thirteen));
++ }
++
+ if (actx->aad) { /* wrap up aad */
+- if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))
+- Poly1305_Update(POLY1305_ctx(actx), zero,
+- POLY1305_BLOCK_SIZE - rem);
++ if (actx->draft) {
++ thirteen = actx->len.aad;
++ Poly1305_Update(POLY1305_ctx(actx), (const unsigned char *)&thirteen, sizeof(thirteen));
++ } else {
++ if ((rem = (size_t)actx->len.aad % POLY1305_BLOCK_SIZE))
++ Poly1305_Update(POLY1305_ctx(actx), zero,
++ POLY1305_BLOCK_SIZE - rem);
++ }
+ actx->aad = 0;
+ }
+
+- if ((rem = (size_t)actx->len.text % POLY1305_BLOCK_SIZE))
+- Poly1305_Update(POLY1305_ctx(actx), zero,
+- POLY1305_BLOCK_SIZE - rem);
++ if (!actx->draft) {
++ if ((rem = (size_t)actx->len.text % POLY1305_BLOCK_SIZE))
++ Poly1305_Update(POLY1305_ctx(actx), zero,
++ POLY1305_BLOCK_SIZE - rem);
+
+- if (is_endian.little) {
+- Poly1305_Update(POLY1305_ctx(actx),
+- (unsigned char *)&actx->len, POLY1305_BLOCK_SIZE);
+- } else {
+- temp[0] = (unsigned char)(actx->len.aad);
+- temp[1] = (unsigned char)(actx->len.aad>>8);
+- temp[2] = (unsigned char)(actx->len.aad>>16);
+- temp[3] = (unsigned char)(actx->len.aad>>24);
+- temp[4] = (unsigned char)(actx->len.aad>>32);
+- temp[5] = (unsigned char)(actx->len.aad>>40);
+- temp[6] = (unsigned char)(actx->len.aad>>48);
+- temp[7] = (unsigned char)(actx->len.aad>>56);
+-
+- temp[8] = (unsigned char)(actx->len.text);
+- temp[9] = (unsigned char)(actx->len.text>>8);
+- temp[10] = (unsigned char)(actx->len.text>>16);
+- temp[11] = (unsigned char)(actx->len.text>>24);
+- temp[12] = (unsigned char)(actx->len.text>>32);
+- temp[13] = (unsigned char)(actx->len.text>>40);
+- temp[14] = (unsigned char)(actx->len.text>>48);
+- temp[15] = (unsigned char)(actx->len.text>>56);
+-
+- Poly1305_Update(POLY1305_ctx(actx), temp, POLY1305_BLOCK_SIZE);
++ if (is_endian.little) {
++ Poly1305_Update(POLY1305_ctx(actx),
++ (unsigned char *)&actx->len, POLY1305_BLOCK_SIZE);
++ } else {
++ temp[0] = (unsigned char)(actx->len.aad);
++ temp[1] = (unsigned char)(actx->len.aad>>8);
++ temp[2] = (unsigned char)(actx->len.aad>>16);
++ temp[3] = (unsigned char)(actx->len.aad>>24);
++ temp[4] = (unsigned char)(actx->len.aad>>32);
++ temp[5] = (unsigned char)(actx->len.aad>>40);
++ temp[6] = (unsigned char)(actx->len.aad>>48);
++ temp[7] = (unsigned char)(actx->len.aad>>56);
++
++ temp[8] = (unsigned char)(actx->len.text);
++ temp[9] = (unsigned char)(actx->len.text>>8);
++ temp[10] = (unsigned char)(actx->len.text>>16);
++ temp[11] = (unsigned char)(actx->len.text>>24);
++ temp[12] = (unsigned char)(actx->len.text>>32);
++ temp[13] = (unsigned char)(actx->len.text>>40);
++ temp[14] = (unsigned char)(actx->len.text>>48);
++ temp[15] = (unsigned char)(actx->len.text>>56);
++
++ Poly1305_Update(POLY1305_ctx(actx), temp, POLY1305_BLOCK_SIZE);
++ }
+ }
+ Poly1305_Final(POLY1305_ctx(actx), ctx->encrypt ? actx->tag
+ : temp);
+@@ -535,12 +576,14 @@ static int chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
+ return 1;
+
+ case EVP_CTRL_AEAD_SET_IVLEN:
++ if (actx->draft) return -1;
+ if (arg <= 0 || arg > CHACHA20_POLY1305_MAX_IVLEN)
+ return 0;
+ actx->nonce_len = arg;
+ return 1;
+
+ case EVP_CTRL_AEAD_SET_IV_FIXED:
++ if (actx->draft) return -1;
+ if (arg != 12)
+ return 0;
+ actx->nonce[0] = actx->key.counter[1]
+@@ -624,9 +667,32 @@ static EVP_CIPHER chacha20_poly1305 = {
+ NULL /* app_data */
+ };
+
++static EVP_CIPHER chacha20_poly1305_draft = {
++ NID_chacha20_poly1305_draft,
++ 1, /* block_size */
++ CHACHA_KEY_SIZE, /* key_len */
++ 0, /* iv_len, none */
++ EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_CUSTOM_IV |
++ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
++ EVP_CIPH_CUSTOM_COPY | EVP_CIPH_FLAG_CUSTOM_CIPHER,
++ chacha20_poly1305_draft_init_key,
++ chacha20_poly1305_cipher,
++ chacha20_poly1305_cleanup,
++ 0, /* 0 moves context-specific structure allocation to ctrl */
++ NULL, /* set_asn1_parameters */
++ NULL, /* get_asn1_parameters */
++ chacha20_poly1305_ctrl,
++ NULL /* app_data */
++};
++
+ const EVP_CIPHER *EVP_chacha20_poly1305(void)
+ {
+ return(&chacha20_poly1305);
+ }
++
++const EVP_CIPHER *EVP_chacha20_poly1305_draft(void)
++{
++ return(&chacha20_poly1305_draft);
++}
+ # endif
+ #endif
+diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h
+index ea91db660b..f2479dcfb8 100644
+--- a/crypto/objects/obj_dat.h
++++ b/crypto/objects/obj_dat.h
+@@ -1078,7 +1078,7 @@ static const unsigned char so[7762] = {
+ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0D, /* [ 7753] OBJ_hmacWithSHA512_256 */
+ };
+
+-#define NUM_NID 1195
++#define NUM_NID 1196
+ static const ASN1_OBJECT nid_objs[NUM_NID] = {
+ {"UNDEF", "undefined", NID_undef},
+ {"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]},
+@@ -2275,9 +2275,10 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = {
+ {"magma-mac", "magma-mac", NID_magma_mac},
+ {"hmacWithSHA512-224", "hmacWithSHA512-224", NID_hmacWithSHA512_224, 8, &so[7745]},
+ {"hmacWithSHA512-256", "hmacWithSHA512-256", NID_hmacWithSHA512_256, 8, &so[7753]},
++ {"ChaCha20-Poly1305-D", "chacha20-poly1305-draft", NID_chacha20_poly1305_draft},
+ };
+
+-#define NUM_SN 1186
++#define NUM_SN 1187
+ static const unsigned int sn_objs[NUM_SN] = {
+ 364, /* "AD_DVCS" */
+ 419, /* "AES-128-CBC" */
+@@ -2395,6 +2396,7 @@ static const unsigned int sn_objs[NUM_SN] = {
+ 417, /* "CSPName" */
+ 1019, /* "ChaCha20" */
+ 1018, /* "ChaCha20-Poly1305" */
++ 1195, /* "ChaCha20-Poly1305-D" */
+ 367, /* "CrlID" */
+ 391, /* "DC" */
+ 31, /* "DES-CBC" */
+@@ -3467,7 +3469,7 @@ static const unsigned int sn_objs[NUM_SN] = {
+ 1093, /* "x509ExtAdmission" */
+ };
+
+-#define NUM_LN 1186
++#define NUM_LN 1187
+ static const unsigned int ln_objs[NUM_LN] = {
+ 363, /* "AD Time Stamping" */
+ 405, /* "ANSI X9.62" */
+@@ -3846,6 +3848,7 @@ static const unsigned int ln_objs[NUM_LN] = {
+ 883, /* "certificateRevocationList" */
+ 1019, /* "chacha20" */
+ 1018, /* "chacha20-poly1305" */
++ 1195, /* "chacha20-poly1305-draft" */
+ 54, /* "challengePassword" */
+ 407, /* "characteristic-two-field" */
+ 395, /* "clearance" */
+diff --git a/crypto/objects/obj_mac.num b/crypto/objects/obj_mac.num
+index 1b6a9c61a1..c81ca25a53 100644
+--- a/crypto/objects/obj_mac.num
++++ b/crypto/objects/obj_mac.num
+@@ -1192,3 +1192,4 @@ magma_cfb 1191
+ magma_mac 1192
+ hmacWithSHA512_224 1193
+ hmacWithSHA512_256 1194
++chacha20_poly1305_draft 1195
+diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt
+index 5b2bb54eb9..b6523a6993 100644
+--- a/crypto/objects/objects.txt
++++ b/crypto/objects/objects.txt
+@@ -1534,6 +1534,7 @@ sm-scheme 104 7 : SM4-CTR : sm4-ctr
+ : AES-192-CBC-HMAC-SHA256 : aes-192-cbc-hmac-sha256
+ : AES-256-CBC-HMAC-SHA256 : aes-256-cbc-hmac-sha256
+ : ChaCha20-Poly1305 : chacha20-poly1305
++ : ChaCha20-Poly1305-D : chacha20-poly1305-draft
+ : ChaCha20 : chacha20
+
+ ISO-US 10046 2 1 : dhpublicnumber : X9.42 DH
+diff --git a/include/openssl/evp.h b/include/openssl/evp.h
+index dd1117d0fe..accc766b3b 100644
+--- a/include/openssl/evp.h
++++ b/include/openssl/evp.h
+@@ -915,6 +915,7 @@ const EVP_CIPHER *EVP_camellia_256_ctr(void);
+ const EVP_CIPHER *EVP_chacha20(void);
+ # ifndef OPENSSL_NO_POLY1305
+ const EVP_CIPHER *EVP_chacha20_poly1305(void);
++const EVP_CIPHER *EVP_chacha20_poly1305_draft(void);
+ # endif
+ # endif
+
+diff --git a/include/openssl/obj_mac.h b/include/openssl/obj_mac.h
+index 47dafe48d0..18805c7562 100644
+--- a/include/openssl/obj_mac.h
++++ b/include/openssl/obj_mac.h
+@@ -4807,6 +4807,10 @@
+ #define LN_chacha20_poly1305 "chacha20-poly1305"
+ #define NID_chacha20_poly1305 1018
+
++#define SN_chacha20_poly1305_draft "ChaCha20-Poly1305-D"
++#define LN_chacha20_poly1305_draft "chacha20-poly1305-draft"
++#define NID_chacha20_poly1305_draft 1195
++
+ #define SN_chacha20 "ChaCha20"
+ #define LN_chacha20 "chacha20"
+ #define NID_chacha20 1019
+diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
+index 6724ccf2d2..0365760200 100644
+--- a/include/openssl/ssl.h
++++ b/include/openssl/ssl.h
+@@ -125,6 +125,7 @@ extern "C" {
+ # define SSL_TXT_CAMELLIA256 "CAMELLIA256"
+ # define SSL_TXT_CAMELLIA "CAMELLIA"
+ # define SSL_TXT_CHACHA20 "CHACHA20"
++# define SSL_TXT_CHACHA20_D "CHACHA20-D"
+ # define SSL_TXT_GOST "GOST89"
+ # define SSL_TXT_ARIA "ARIA"
+ # define SSL_TXT_ARIA_GCM "ARIAGCM"
+diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
+index e13b5dd4bc..53d43c121e 100644
+--- a/include/openssl/tls1.h
++++ b/include/openssl/tls1.h
+@@ -597,7 +597,12 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
+ # define TLS1_CK_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 0x0300C09A
+ # define TLS1_CK_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 0x0300C09B
+
+-/* draft-ietf-tls-chacha20-poly1305-03 */
++/* Chacha20-Poly1305-Draft ciphersuites from draft-agl-tls-chacha20poly1305-04 */
++# define TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_D 0x0300CC13
++# define TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_D 0x0300CC14
++# define TLS1_CK_DHE_RSA_WITH_CHACHA20_POLY1305_D 0x0300CC15
++
++/* Chacha20-Poly1305 ciphersuites from RFC7905 */
+ # define TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305 0x0300CCA8
+ # define TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 0x0300CCA9
+ # define TLS1_CK_DHE_RSA_WITH_CHACHA20_POLY1305 0x0300CCAA
+@@ -762,6 +767,9 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
+ # define TLS1_RFC_DHE_RSA_WITH_CHACHA20_POLY1305 "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
+ # define TLS1_RFC_ECDHE_RSA_WITH_CHACHA20_POLY1305 "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
+ # define TLS1_RFC_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
++# define TLS1_RFC_DHE_RSA_WITH_CHACHA20_POLY1305_D "OLD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
++# define TLS1_RFC_ECDHE_RSA_WITH_CHACHA20_POLY1305_D "OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
++# define TLS1_RFC_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_D "OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
+ # define TLS1_RFC_PSK_WITH_CHACHA20_POLY1305 "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256"
+ # define TLS1_RFC_ECDHE_PSK_WITH_CHACHA20_POLY1305 "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256"
+ # define TLS1_RFC_DHE_PSK_WITH_CHACHA20_POLY1305 "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256"
+@@ -1090,7 +1098,12 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
+ # define TLS1_TXT_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 "ECDH-RSA-CAMELLIA128-SHA256"
+ # define TLS1_TXT_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 "ECDH-RSA-CAMELLIA256-SHA384"
+
+-/* draft-ietf-tls-chacha20-poly1305-03 */
++/* Chacha20-Poly1305-Draft ciphersuites from draft-agl-tls-chacha20poly1305-04 */
++# define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_D "ECDHE-RSA-CHACHA20-POLY1305-OLD"
++# define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_D "ECDHE-ECDSA-CHACHA20-POLY1305-OLD"
++# define TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305_D "DHE-RSA-CHACHA20-POLY1305-OLD"
++
++/* Chacha20-Poly1305 ciphersuites from RFC7905 */
+ # define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 "ECDHE-RSA-CHACHA20-POLY1305"
+ # define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 "ECDHE-ECDSA-CHACHA20-POLY1305"
+ # define TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305 "DHE-RSA-CHACHA20-POLY1305"
+diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
+index d7dbf99954..ee3293b5ce 100644
+--- a/ssl/s3_lib.c
++++ b/ssl/s3_lib.c
+@@ -2082,6 +2082,54 @@ static SSL_CIPHER ssl3_ciphers[] = {
+ 256,
+ 256,
+ },
++ {
++ 1,
++ TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305_D,
++ TLS1_RFC_DHE_RSA_WITH_CHACHA20_POLY1305_D,
++ TLS1_CK_DHE_RSA_WITH_CHACHA20_POLY1305_D,
++ SSL_kDHE,
++ SSL_aRSA,
++ SSL_CHACHA20POLY1305_D,
++ SSL_AEAD,
++ TLS1_2_VERSION, TLS1_2_VERSION,
++ DTLS1_2_VERSION, DTLS1_2_VERSION,
++ SSL_HIGH,
++ SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
++ 256,
++ 256,
++ },
++ {
++ 1,
++ TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_D,
++ TLS1_RFC_ECDHE_RSA_WITH_CHACHA20_POLY1305_D,
++ TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_D,
++ SSL_kECDHE,
++ SSL_aRSA,
++ SSL_CHACHA20POLY1305_D,
++ SSL_AEAD,
++ TLS1_2_VERSION, TLS1_2_VERSION,
++ DTLS1_2_VERSION, DTLS1_2_VERSION,
++ SSL_HIGH,
++ SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
++ 256,
++ 256,
++ },
++ {
++ 1,
++ TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_D,
++ TLS1_RFC_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_D,
++ TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_D,
++ SSL_kECDHE,
++ SSL_aECDSA,
++ SSL_CHACHA20POLY1305_D,
++ SSL_AEAD,
++ TLS1_2_VERSION, TLS1_2_VERSION,
++ DTLS1_2_VERSION, DTLS1_2_VERSION,
++ SSL_HIGH,
++ SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256,
++ 256,
++ 256,
++ },
+ {
+ 1,
+ TLS1_TXT_PSK_WITH_CHACHA20_POLY1305,
+diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
+index b60d67aa0d..ce750c4425 100644
+--- a/ssl/ssl_ciph.c
++++ b/ssl/ssl_ciph.c
+@@ -43,7 +43,8 @@
+ #define SSL_ENC_CHACHA_IDX 19
+ #define SSL_ENC_ARIA128GCM_IDX 20
+ #define SSL_ENC_ARIA256GCM_IDX 21
+-#define SSL_ENC_NUM_IDX 22
++#define SSL_ENC_CHACHA20_D_IDX 22
++#define SSL_ENC_NUM_IDX 23
+
+ /* NB: make sure indices in these tables match values above */
+
+@@ -76,6 +77,7 @@ static const ssl_cipher_table ssl_cipher_table_cipher[SSL_ENC_NUM_IDX] = {
+ {SSL_CHACHA20POLY1305, NID_chacha20_poly1305}, /* SSL_ENC_CHACHA_IDX 19 */
+ {SSL_ARIA128GCM, NID_aria_128_gcm}, /* SSL_ENC_ARIA128GCM_IDX 20 */
+ {SSL_ARIA256GCM, NID_aria_256_gcm}, /* SSL_ENC_ARIA256GCM_IDX 21 */
++ {SSL_CHACHA20POLY1305_D, NID_chacha20_poly1305_draft}, /* SSL_ENC_CHACHA20POLY1305_IDX 22 */
+ };
+
+ static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX];
+@@ -275,6 +277,7 @@ static const SSL_CIPHER cipher_aliases[] = {
+ {0, SSL_TXT_CAMELLIA256, NULL, 0, 0, 0, SSL_CAMELLIA256},
+ {0, SSL_TXT_CAMELLIA, NULL, 0, 0, 0, SSL_CAMELLIA},
+ {0, SSL_TXT_CHACHA20, NULL, 0, 0, 0, SSL_CHACHA20},
++ {0, SSL_TXT_CHACHA20_D, NULL, 0, 0, 0, SSL_CHACHA20POLY1305_D},
+
+ {0, SSL_TXT_ARIA, NULL, 0, 0, 0, SSL_ARIA},
+ {0, SSL_TXT_ARIA_GCM, NULL, 0, 0, 0, SSL_ARIA128GCM | SSL_ARIA256GCM},
+@@ -1791,6 +1794,9 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
+ case SSL_CHACHA20POLY1305:
+ enc = "CHACHA20/POLY1305(256)";
+ break;
++ case SSL_CHACHA20POLY1305_D:
++ enc = "CHACHA20/POLY1305-Draft(256)";
++ break;
+ default:
+ enc = "unknown";
+ break;
+@@ -2115,7 +2121,7 @@ int ssl_cipher_get_overhead(const SSL_CIPHER *c, size_t *mac_overhead,
+ out = EVP_CCM_TLS_EXPLICIT_IV_LEN + 16;
+ } else if (c->algorithm_enc & (SSL_AES128CCM8 | SSL_AES256CCM8)) {
+ out = EVP_CCM_TLS_EXPLICIT_IV_LEN + 8;
+- } else if (c->algorithm_enc & SSL_CHACHA20POLY1305) {
++ } else if (c->algorithm_enc & (SSL_CHACHA20POLY1305 | SSL_CHACHA20POLY1305_D)) {
+ out = 16;
+ } else if (c->algorithm_mac & SSL_AEAD) {
+ /* We're supposed to have handled all the AEAD modes above */
+diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
+index fa0f6d018c..f2a95c263a 100644
+--- a/ssl/ssl_locl.h
++++ b/ssl/ssl_locl.h
+@@ -230,12 +230,13 @@
+ # define SSL_CHACHA20POLY1305 0x00080000U
+ # define SSL_ARIA128GCM 0x00100000U
+ # define SSL_ARIA256GCM 0x00200000U
++# define SSL_CHACHA20POLY1305_D 0x00400000U
+
+ # define SSL_AESGCM (SSL_AES128GCM | SSL_AES256GCM)
+ # define SSL_AESCCM (SSL_AES128CCM | SSL_AES256CCM | SSL_AES128CCM8 | SSL_AES256CCM8)
+ # define SSL_AES (SSL_AES128|SSL_AES256|SSL_AESGCM|SSL_AESCCM)
+ # define SSL_CAMELLIA (SSL_CAMELLIA128|SSL_CAMELLIA256)
+-# define SSL_CHACHA20 (SSL_CHACHA20POLY1305)
++# define SSL_CHACHA20 (SSL_CHACHA20POLY1305 | SSL_CHACHA20POLY1305_D)
+ # define SSL_ARIAGCM (SSL_ARIA128GCM | SSL_ARIA256GCM)
+ # define SSL_ARIA (SSL_ARIAGCM)
+
+diff --git a/util/libcrypto.num b/util/libcrypto.num
+index 474f9f950d..bc65f22deb 100644
+--- a/util/libcrypto.num
++++ b/util/libcrypto.num
+@@ -4580,3 +4580,4 @@ EVP_PKEY_meth_get_digest_custom 4533 1_1_1 EXIST::FUNCTION:
+ OPENSSL_INIT_set_config_filename 4534 1_1_1b EXIST::FUNCTION:STDIO
+ OPENSSL_INIT_set_config_file_flags 4535 1_1_1b EXIST::FUNCTION:STDIO
+ EVP_PKEY_get0_engine 4536 1_1_1c EXIST::FUNCTION:ENGINE
++EVP_chacha20_poly1305_draft 4537 1_1_1d EXIST::FUNCTION:CHACHA,POLY1305
diff --git a/openssl-equal-1.1.1d.patch b/openssl-equal-1.1.1d.patch
new file mode 100644
index 0000000..83c273a
--- /dev/null
+++ b/openssl-equal-1.1.1d.patch
@@ -0,0 +1,1071 @@
+diff --git a/doc/man1/ciphers.pod b/doc/man1/ciphers.pod
+index faf9e53814..428df515f1 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 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 6724ccf2d2..81a5538977 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 a50a075b42..e9abb98d4f 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_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA 293
+ # define SSL_R_NOT_ON_RECORD_BOUNDARY 182
+ # define SSL_R_NOT_REPLACING_CERTIFICATE 289
+@@ -727,9 +729,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/ssl/s3_lib.c b/ssl/s3_lib.c
+index d7dbf99954..7abac4dda1 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,
+@@ -4123,6 +4123,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
+@@ -4132,16 +4143,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 */
+
+@@ -4168,54 +4187,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;
+ }
+
+@@ -4246,14 +4224,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
+@@ -4275,10 +4255,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);
+@@ -4295,6 +4275,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) {
+@@ -4302,14 +4290,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);
+
+@@ -4321,13 +4302,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 b60d67aa0d..4607b776de 100644
+--- a/ssl/ssl_ciph.c
++++ b/ssl/ssl_ciph.c
+@@ -192,6 +192,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;
+
+@@ -681,6 +682,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++;
+ }
+
+@@ -774,8 +776,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;
+@@ -783,9 +785,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)
+@@ -862,6 +864,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 */
+@@ -869,6 +872,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 */
+@@ -880,6 +884,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)
+@@ -947,8 +952,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;
+@@ -962,7 +967,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;
+
+@@ -973,18 +978,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;
+ }
+@@ -1026,7 +1079,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;
+ }
+@@ -1205,8 +1258,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++;
+@@ -1215,6 +1268,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;
+ }
+
+@@ -1379,7 +1437,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);
+ }
+
+@@ -1392,7 +1450,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);
+ }
+
+@@ -1401,17 +1459,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.
+@@ -1460,16 +1521,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);
+
+ /*
+@@ -1478,13 +1539,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);
+
+ /*
+@@ -1492,16 +1553,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);
+
+ /*
+@@ -1517,7 +1578,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);
+
+ /*
+@@ -1533,15 +1594,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.
+@@ -1555,9 +1616,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,
+@@ -1582,27 +1642,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;
+ }
+
+ /*
+@@ -1611,26 +1679,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 4b12ed1485..cd1a95d1d2 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_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA),
+ "mixed handshake and non handshake data"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_ON_RECORD_BOUNDARY),
+@@ -1201,11 +1204,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 40ab87480d..78fcb80035 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);
+ sk_SSL_CIPHER_free(s->peer_ciphers);
+@@ -2430,9 +2496,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;
+@@ -2506,8 +2572,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;
+ }
+
+@@ -2957,7 +3023,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;
+ }
+@@ -3133,7 +3199,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);
+@@ -3811,13 +3877,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 (!dup_ca_names(&ret->ca_names, s->ca_names)
+diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
+index fa0f6d018c..3ffc46efd9 100644
+--- a/ssl/ssl_locl.h
++++ b/ssl/ssl_locl.h
+@@ -733,9 +733,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 */
+@@ -1131,7 +1168,7 @@ struct ssl_st {
+ SSL_DANE dane;
+ /* crypto */
+ STACK_OF(SSL_CIPHER) *peer_ciphers;
+- 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;
+@@ -2269,7 +2306,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);
+@@ -2279,6 +2316,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,
+@@ -2362,7 +2406,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/statem_srvr.c b/ssl/statem/statem_srvr.c
+index e7e95c74e7..543d00b1d0 100644
+--- a/ssl/statem/statem_srvr.c
++++ b/ssl/statem/statem_srvr.c
+@@ -1748,7 +1748,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,
+@@ -1929,7 +1929,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->peer_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,
+@@ -1938,8 +1938,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->peer_ciphers);
++ ssl_cipher_preference_list_free(s->cipher_list);
++ s->cipher_list = ssl_cipher_preference_list_from_ciphers(
++ s->peer_ciphers);
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->peer_ciphers);
+ }
+@@ -2253,7 +2254,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->peer_ciphers, SSL_get_ciphers(s));
++ ssl3_choose_cipher(s, s->peer_ciphers, ssl_get_cipher_preferences(s));
+
+ if (cipher == NULL) {
+ SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,
diff --git a/openssl-equal-1.1.1d_ciphers.patch b/openssl-equal-1.1.1d_ciphers.patch
new file mode 100644
index 0000000..a95d469
--- /dev/null
+++ b/openssl-equal-1.1.1d_ciphers.patch
@@ -0,0 +1,1147 @@
+diff --git a/doc/man1/ciphers.pod b/doc/man1/ciphers.pod
+index faf9e53814..428df515f1 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 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 6724ccf2d2..81a5538977 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 a50a075b42..e9abb98d4f 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_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA 293
+ # define SSL_R_NOT_ON_RECORD_BOUNDARY 182
+ # define SSL_R_NOT_REPLACING_CERTIFICATE 289
+@@ -727,9 +729,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/ssl/s3_lib.c b/ssl/s3_lib.c
+index d7dbf99954..da73406940 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,
+@@ -199,7 +205,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,
+@@ -264,7 +270,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,
+@@ -328,7 +334,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,
+@@ -4123,6 +4129,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
+@@ -4132,16 +4149,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 */
+
+@@ -4168,54 +4193,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;
+ }
+
+@@ -4246,14 +4230,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
+@@ -4275,10 +4261,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);
+@@ -4295,6 +4281,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) {
+@@ -4302,14 +4296,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);
+
+@@ -4321,13 +4308,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 b60d67aa0d..4607b776de 100644
+--- a/ssl/ssl_ciph.c
++++ b/ssl/ssl_ciph.c
+@@ -192,6 +192,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;
+
+@@ -681,6 +682,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++;
+ }
+
+@@ -774,8 +776,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;
+@@ -783,9 +785,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)
+@@ -862,6 +864,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 */
+@@ -869,6 +872,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 */
+@@ -880,6 +884,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)
+@@ -947,8 +952,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;
+@@ -962,7 +967,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;
+
+@@ -973,18 +978,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;
+ }
+@@ -1026,7 +1079,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;
+ }
+@@ -1205,8 +1258,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++;
+@@ -1215,6 +1268,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;
+ }
+
+@@ -1379,7 +1437,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);
+ }
+
+@@ -1392,7 +1450,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);
+ }
+
+@@ -1401,17 +1459,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.
+@@ -1460,16 +1521,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);
+
+ /*
+@@ -1478,13 +1539,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);
+
+ /*
+@@ -1492,16 +1553,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);
+
+ /*
+@@ -1517,7 +1578,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);
+
+ /*
+@@ -1533,15 +1594,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.
+@@ -1555,9 +1616,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,
+@@ -1582,27 +1642,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;
+ }
+
+ /*
+@@ -1611,26 +1679,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 4b12ed1485..cd1a95d1d2 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_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA),
+ "mixed handshake and non handshake data"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_ON_RECORD_BOUNDARY),
+@@ -1201,11 +1204,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 40ab87480d..78fcb80035 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);
+ sk_SSL_CIPHER_free(s->peer_ciphers);
+@@ -2430,9 +2496,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;
+@@ -2506,8 +2572,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;
+ }
+
+@@ -2957,7 +3023,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;
+ }
+@@ -3133,7 +3199,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);
+@@ -3811,13 +3877,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 (!dup_ca_names(&ret->ca_names, s->ca_names)
+diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
+index fa0f6d018c..3ffc46efd9 100644
+--- a/ssl/ssl_locl.h
++++ b/ssl/ssl_locl.h
+@@ -733,9 +733,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 */
+@@ -1131,7 +1168,7 @@ struct ssl_st {
+ SSL_DANE dane;
+ /* crypto */
+ STACK_OF(SSL_CIPHER) *peer_ciphers;
+- 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;
+@@ -2269,7 +2306,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);
+@@ -2279,6 +2316,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,
+@@ -2362,7 +2406,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/statem_srvr.c b/ssl/statem/statem_srvr.c
+index e7e95c74e7..543d00b1d0 100644
+--- a/ssl/statem/statem_srvr.c
++++ b/ssl/statem/statem_srvr.c
+@@ -1748,7 +1748,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,
+@@ -1929,7 +1929,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->peer_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,
+@@ -1938,8 +1938,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->peer_ciphers);
++ ssl_cipher_preference_list_free(s->cipher_list);
++ s->cipher_list = ssl_cipher_preference_list_from_ciphers(
++ s->peer_ciphers);
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->peer_ciphers);
+ }
+@@ -2253,7 +2254,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->peer_ciphers, SSL_get_ciphers(s));
++ ssl3_choose_cipher(s, s->peer_ciphers, ssl_get_cipher_preferences(s));
+
+ if (cipher == NULL) {
+ SSLfatal(s, SSL_AD_HANDSHAKE_FAILURE,