[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Wed Mar 14 11:05:02 UTC 2018


The branch master has been updated
       via  fa25763b5528b56b448d64bfbaeac54905b0c80d (commit)
       via  74826901379bf190a9c3b3ceaaca0493454e3536 (commit)
       via  2b527b9b3233eb312a4bf17b044660aa213883b6 (commit)
       via  9d2674cd232ab51f5ae7952a63a614b688145527 (commit)
       via  e54b3ccdbe42d614890fb43cee274e6b14e741dd (commit)
       via  f865b08143b453962ad4afccd69e698d13c60f77 (commit)
      from  5b68d1792021463b7cd5d76c82b251d61a56d869 (commit)


- Log -----------------------------------------------------------------
commit fa25763b5528b56b448d64bfbaeac54905b0c80d
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 14 10:43:53 2018 +0000

    Put the default set of TLSv1.3 ciphersuites in a header file
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5392)

commit 74826901379bf190a9c3b3ceaaca0493454e3536
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Mar 12 10:48:32 2018 +0000

    Fix clienthellotest for new TLSv1.3 ciphersuite configuration
    
    A place in clienthellotest was missed in converting to the new mechanism
    for configuration of TLSv1.3 ciphersuites.
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5392)

commit 2b527b9b3233eb312a4bf17b044660aa213883b6
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Feb 21 17:47:12 2018 +0000

    Update CHANGES with details of TLSv1.3 ciphersuite configuration
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5392)

commit 9d2674cd232ab51f5ae7952a63a614b688145527
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Feb 21 17:23:11 2018 +0000

    Add documentation for TLSv1.3 ciphersuite configuration
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5392)

commit e54b3ccdbe42d614890fb43cee274e6b14e741dd
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Feb 19 12:07:18 2018 +0000

    Update s_time to be allow configuration of TLSv1.3 ciphersuites
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5392)

commit f865b08143b453962ad4afccd69e698d13c60f77
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Feb 16 11:26:02 2018 +0000

    Split configuration of TLSv1.3 ciphers from older ciphers
    
    With the current mechanism, old cipher strings that used to work in 1.1.0,
    may inadvertently disable all TLSv1.3 ciphersuites causing connections to
    fail. This is confusing for users.
    
    In reality TLSv1.3 are quite different to older ciphers. They are much
    simpler and there are only a small number of them so, arguably, they don't
    need the same level of control that the older ciphers have.
    
    This change splits the configuration of TLSv1.3 ciphers from older ones.
    By default the TLSv1.3 ciphers are on, so you cannot inadvertently disable
    them through your existing config.
    
    Fixes #5359
    
    Reviewed-by: Tim Hudson <tjh at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/5392)

-----------------------------------------------------------------------

Summary of changes:
 CHANGES                                 |  16 ++-
 apps/apps.h                             |   6 +-
 apps/ciphers.c                          |  14 ++-
 apps/s_time.c                           |  24 ++--
 crypto/err/openssl.txt                  |   1 +
 doc/man1/ciphers.pod                    |  26 +++--
 doc/man1/s_client.pod                   |  19 +++-
 doc/man1/s_server.pod                   |  20 +++-
 doc/man1/s_time.pod                     |  19 +++-
 doc/man3/SSL_CONF_cmd.pod               |  25 ++++-
 doc/man3/SSL_CTX_set_cipher_list.pod    |  50 ++++++++-
 include/openssl/ssl.h                   |   7 ++
 include/openssl/sslerr.h                |   1 +
 include/openssl/tls1.h                  |  12 --
 ssl/s3_lib.c                            | 192 +++++++++++++++++---------------
 ssl/ssl_ciph.c                          |  21 +++-
 ssl/ssl_conf.c                          |  13 +++
 ssl/ssl_err.c                           |   1 +
 ssl/ssl_lib.c                           | 119 +++++++++++++++++++-
 ssl/ssl_locl.h                          |  12 +-
 test/cipherlist_test.c                  |  14 +--
 test/clienthellotest.c                  |   7 +-
 test/fatalerrtest.c                     |   4 +
 test/recipes/70-test_sslsigalgs.t       |  18 +--
 test/recipes/70-test_tls13hrr.t         |   5 +-
 test/recipes/70-test_tls13psk.t         |   6 +-
 test/recipes/80-test_ssl_old.t          |  21 +++-
 test/ssl-tests/02-protocol-version.conf |   2 +
 test/ssl-tests/protocol_version.pm      |   2 +
 test/sslapitest.c                       |  22 ++--
 test/sslcorrupttest.c                   |  12 +-
 test/ssltest_old.c                      |  17 ++-
 util/libssl.num                         |   2 +
 util/perl/TLSProxy/Proxy.pm             |  30 ++++-
 34 files changed, 541 insertions(+), 219 deletions(-)

diff --git a/CHANGES b/CHANGES
index dcbe291..0e275c3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,15 @@
 
  Changes between 1.1.0g and 1.1.1 [xx XXX xxxx]
 
+  *) Separated TLSv1.3 ciphersuite configuration out from TLSv1.2 ciphersuite
+     configuration. TLSv1.3 ciphersuites are not compatible with TLSv1.2 and
+     below. Similarly TLSv1.2 ciphersuites are not compatible with TLSv1.3.
+     In order to avoid issues where legacy TLSv1.2 ciphersuite configuration
+     would otherwise inadvertently disable all TLSv1.3 ciphersuites the
+     configuraton has been separated out. See the ciphers man page or the
+     SSL_CTX_set_ciphersuites() man page for more information.
+     [Matt Caswell]
+
   *) On POSIX (BSD, Linux, ...) systems the ocsp(1) command running
      in responder mode now supports the new "-multi" option, which
      spawns the specified number of child processes to handle OCSP
@@ -35,12 +44,7 @@
 
   *) Support for TLSv1.3 added. Note that users upgrading from an earlier
      version of OpenSSL should review their configuration settings to ensure
-     that they are still appropriate for TLSv1.3. In particular if no TLSv1.3
-     ciphersuites are enabled then OpenSSL will refuse to make a connection
-     unless (1) TLSv1.3 is explicitly disabled or (2) the ciphersuite
-     configuration is updated to include suitable ciphersuites. The DEFAULT
-     ciphersuite configuration does include TLSv1.3 ciphersuites. For further
-     information on this and other related issues please see:
+     that they are still appropriate for TLSv1.3. For further information see:
      https://www.openssl.org/blog/blog/2018/02/08/tlsv1.3/
 
      NOTE: In this pre-release of OpenSSL a draft version of the
diff --git a/apps/apps.h b/apps/apps.h
index aa63527..8f2590e 100644
--- a/apps/apps.h
+++ b/apps/apps.h
@@ -229,7 +229,7 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate,
         OPT_S_ONRESUMP, OPT_S_NOLEGACYCONN, OPT_S_ALLOW_NO_DHE_KEX, \
         OPT_S_PRIORITIZE_CHACHA, \
         OPT_S_STRICT, OPT_S_SIGALGS, OPT_S_CLIENTSIGALGS, OPT_S_GROUPS, \
-        OPT_S_CURVES, OPT_S_NAMEDCURVE, OPT_S_CIPHER, \
+        OPT_S_CURVES, OPT_S_NAMEDCURVE, OPT_S_CIPHER, OPT_S_CIPHERSUITES, \
         OPT_S_RECORD_PADDING, OPT_S_DEBUGBROKE, OPT_S_COMP, \
         OPT_S_NO_RENEGOTIATION, OPT_S_NO_MIDDLEBOX, OPT_S__LAST
 
@@ -272,7 +272,8 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate,
             "Groups to advertise (colon-separated list)" }, \
         {"named_curve", OPT_S_NAMEDCURVE, 's', \
             "Elliptic curve used for ECDHE (server-side only)" }, \
-        {"cipher", OPT_S_CIPHER, 's', "Specify cipher list to be used"}, \
+        {"cipher", OPT_S_CIPHER, 's', "Specify TLSv1.2 and below cipher list to be used"}, \
+        {"ciphersuites", OPT_S_CIPHERSUITES, 's', "Specify TLSv1.3 ciphersuites to be used"}, \
         {"record_padding", OPT_S_RECORD_PADDING, 's', \
             "Block size to pad TLS 1.3 records to."}, \
         {"debug_broken_protocol", OPT_S_DEBUGBROKE, '-', \
@@ -305,6 +306,7 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate,
         case OPT_S_CURVES: \
         case OPT_S_NAMEDCURVE: \
         case OPT_S_CIPHER: \
+        case OPT_S_CIPHERSUITES: \
         case OPT_S_RECORD_PADDING: \
         case OPT_S_NO_RENEGOTIATION: \
         case OPT_S_DEBUGBROKE: \
diff --git a/apps/ciphers.c b/apps/ciphers.c
index 4e8ffd1..0bb33a4 100644
--- a/apps/ciphers.c
+++ b/apps/ciphers.c
@@ -26,6 +26,7 @@ typedef enum OPTION_choice {
     OPT_TLS1_3,
     OPT_PSK,
     OPT_SRP,
+    OPT_CIPHERSUITES,
     OPT_V, OPT_UPPER_V, OPT_S
 } OPTION_CHOICE;
 
@@ -57,6 +58,8 @@ const OPTIONS ciphers_options[] = {
     {"srp", OPT_SRP, '-', "include ciphersuites requiring SRP"},
 #endif
     {"convert", OPT_CONVERT, 's', "Convert standard name into OpenSSL name"},
+    {"ciphersuites", OPT_CIPHERSUITES, 's',
+     "Configure the TLSv1.3 ciphersuites to use"},
     {NULL}
 };
 
@@ -91,7 +94,7 @@ int ciphers_main(int argc, char **argv)
     int srp = 0;
 #endif
     const char *p;
-    char *ciphers = NULL, *prog, *convert = NULL;
+    char *ciphers = NULL, *prog, *convert = NULL, *ciphersuites = NULL;
     char buf[512];
     OPTION_CHOICE o;
     int min_version = 0, max_version = 0;
@@ -153,6 +156,9 @@ int ciphers_main(int argc, char **argv)
             srp = 1;
 #endif
             break;
+        case OPT_CIPHERSUITES:
+            ciphersuites = opt_arg();
+            break;
         }
     }
     argv = opt_rest();
@@ -185,6 +191,12 @@ int ciphers_main(int argc, char **argv)
     if (srp)
         SSL_CTX_set_srp_client_pwd_callback(ctx, dummy_srp);
 #endif
+
+    if (ciphersuites != NULL && !SSL_CTX_set_ciphersuites(ctx, ciphersuites)) {
+        BIO_printf(bio_err, "Error setting TLSv1.3 ciphersuites\n");
+        goto err;
+    }
+
     if (ciphers != NULL) {
         if (!SSL_CTX_set_cipher_list(ctx, ciphers)) {
             BIO_printf(bio_err, "Error in cipher list\n");
diff --git a/apps/s_time.c b/apps/s_time.c
index 149107c..0d3543e 100644
--- a/apps/s_time.c
+++ b/apps/s_time.c
@@ -59,9 +59,9 @@ static const size_t fmt_http_get_cmd_size = sizeof(fmt_http_get_cmd) - 2;
 
 typedef enum OPTION_choice {
     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
-    OPT_CONNECT, OPT_CIPHER, OPT_CERT, OPT_NAMEOPT, OPT_KEY, OPT_CAPATH,
-    OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NEW, OPT_REUSE, OPT_BUGS,
-    OPT_VERIFY, OPT_TIME, OPT_SSL3,
+    OPT_CONNECT, OPT_CIPHER, OPT_CIPHERSUITES, OPT_CERT, OPT_NAMEOPT, OPT_KEY,
+    OPT_CAPATH, OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NEW, OPT_REUSE,
+    OPT_BUGS, OPT_VERIFY, OPT_TIME, OPT_SSL3,
     OPT_WWW
 } OPTION_CHOICE;
 
@@ -69,7 +69,9 @@ const OPTIONS s_time_options[] = {
     {"help", OPT_HELP, '-', "Display this summary"},
     {"connect", OPT_CONNECT, 's',
      "Where to connect as post:port (default is " SSL_CONNECT_NAME ")"},
-    {"cipher", OPT_CIPHER, 's', "Cipher to use, see 'openssl ciphers'"},
+    {"cipher", OPT_CIPHER, 's', "TLSv1.2 and below cipher list to be used"},
+    {"ciphersuites", OPT_CIPHERSUITES, 's',
+     "Specify TLSv1.3 ciphersuites to be used"},
     {"cert", OPT_CERT, '<', "Cert file to use, PEM format assumed"},
     {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"},
     {"key", OPT_KEY, '<', "File with key, PEM; default is -cert file"},
@@ -106,7 +108,8 @@ int s_time_main(int argc, char **argv)
     SSL *scon = NULL;
     SSL_CTX *ctx = NULL;
     const SSL_METHOD *meth = NULL;
-    char *CApath = NULL, *CAfile = NULL, *cipher = NULL, *www_path = NULL;
+    char *CApath = NULL, *CAfile = NULL, *cipher = NULL, *ciphersuites = NULL;
+    char *www_path = NULL;
     char *host = SSL_CONNECT_NAME, *certfile = NULL, *keyfile = NULL, *prog;
     double totalTime = 0.0;
     int noCApath = 0, noCAfile = 0;
@@ -170,6 +173,9 @@ int s_time_main(int argc, char **argv)
         case OPT_CIPHER:
             cipher = opt_arg();
             break;
+        case OPT_CIPHERSUITES:
+            ciphersuites = opt_arg();
+            break;
         case OPT_BUGS:
             st_bugs = 1;
             break;
@@ -196,10 +202,6 @@ int s_time_main(int argc, char **argv)
 
     if (cipher == NULL)
         cipher = getenv("SSL_CIPHER");
-    if (cipher == NULL) {
-        BIO_printf(bio_err, "No CIPHER specified\n");
-        goto end;
-    }
 
     if ((ctx = SSL_CTX_new(meth)) == NULL)
         goto end;
@@ -210,7 +212,9 @@ int s_time_main(int argc, char **argv)
 
     if (st_bugs)
         SSL_CTX_set_options(ctx, SSL_OP_ALL);
-    if (!SSL_CTX_set_cipher_list(ctx, cipher))
+    if (cipher != NULL && !SSL_CTX_set_cipher_list(ctx, cipher))
+        goto end;
+    if (ciphersuites != NULL && !SSL_CTX_set_ciphersuites(ctx, ciphersuites))
         goto end;
     if (!set_cert_stuff(ctx, certfile, keyfile))
         goto end;
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index d867007..606f2b1 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -986,6 +986,7 @@ SSL_F_ADD_CLIENT_KEY_SHARE_EXT:438:*
 SSL_F_ADD_KEY_SHARE:512:add_key_share
 SSL_F_BYTES_TO_CIPHER_LIST:519:bytes_to_cipher_list
 SSL_F_CHECK_SUITEB_CIPHER_LIST:331:check_suiteb_cipher_list
+SSL_F_CIPHERSUITE_CB:621:ciphersuite_cb
 SSL_F_CONSTRUCT_CA_NAMES:552:construct_ca_names
 SSL_F_CONSTRUCT_KEY_EXCHANGE_TBS:553:construct_key_exchange_tbs
 SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH:539:create_synthetic_message_hash
diff --git a/doc/man1/ciphers.pod b/doc/man1/ciphers.pod
index 129f766..eed5e64 100644
--- a/doc/man1/ciphers.pod
+++ b/doc/man1/ciphers.pod
@@ -22,6 +22,7 @@ B<openssl> B<ciphers>
 [B<-srp>]
 [B<-stdname>]
 [B<-convert name>]
+[B<-ciphersuites val>]
 [B<cipherlist>]
 
 =head1 DESCRIPTION
@@ -105,10 +106,21 @@ Precede each cipher suite by its standard name.
 
 Convert a standard cipher B<name> to its OpenSSL name.
 
+=item B<-ciphersuites val>
+
+Sets the list of TLSv1.3 ciphersuites. This list will be combined with any
+TLSv1.2 and below ciphersuites that have been configured. The format for this
+list is a simple colon (":") separated list of TLSv1.3 ciphersuite names. By
+default this value is:
+
+"TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
+
 =item B<cipherlist>
 
-A cipher list to convert to a cipher preference list. If it is not included
-then the default cipher list will be used. The format is described below.
+A cipher list of TLSv1.2 and below ciphersuites to convert to a cipher
+preference list. This list will be combined with any TLSv1.3 ciphersuites that
+have been configured. If it is not included then the default cipher list will be
+used. The format is described below.
 
 =back
 
@@ -705,11 +717,11 @@ Note: the CBC modes mentioned in this RFC are not supported.
 
 =head2 TLS v1.3 cipher suites
 
- TLS_AES_128_GCM_SHA256                     TLS13-AES-128-GCM-SHA256
- TLS_AES_256_GCM_SHA384                     TLS13-AES-256-GCM-SHA384
- TLS_CHACHA20_POLY1305_SHA256               TLS13-CHACHA20-POLY1305-SHA256
- TLS_AES_128_CCM_SHA256                     TLS13-AES-128-CCM-SHA256
- TLS_AES_128_CCM_8_SHA256                   TLS13-AES-128-CCM-8-SHA256
+ TLS_AES_128_GCM_SHA256                     TLS_AES_128_GCM_SHA256
+ TLS_AES_256_GCM_SHA384                     TLS_AES_256_GCM_SHA384
+ TLS_CHACHA20_POLY1305_SHA256               TLS_CHACHA20_POLY1305_SHA256
+ TLS_AES_128_CCM_SHA256                     TLS_AES_128_CCM_SHA256
+ TLS_AES_128_CCM_8_SHA256                   TLS_AES_128_CCM_8_SHA256
 
 =head2 Older names used by OpenSSL
 
diff --git a/doc/man1/s_client.pod b/doc/man1/s_client.pod
index f101b33..a06d3a6 100644
--- a/doc/man1/s_client.pod
+++ b/doc/man1/s_client.pod
@@ -99,6 +99,7 @@ B<openssl> B<s_client>
 [B<-sigalgs sigalglist>]
 [B<-curves curvelist>]
 [B<-cipher cipherlist>]
+[B<-ciphersuites val>]
 [B<-serverpref>]
 [B<-starttls protocol>]
 [B<-xmpphost hostname>]
@@ -505,10 +506,20 @@ ultimately selected by the server. For a list of all curves, use:
 
 =item B<-cipher cipherlist>
 
-This allows the cipher list sent by the client to be modified. Although
-the server determines which cipher suite is used it should take the first
-supported cipher in the list sent by the client. See the B<ciphers>
-command for more information.
+This allows the TLSv1.2 and below cipher list sent by the client to be modified.
+This list will be combined with any TLSv1.3 ciphersuites that have been
+configured. Although the server determines which ciphersuite is used it should
+take the first supported cipher in the list sent by the client. See the
+B<ciphers> command for more information.
+
+=item B<-ciphersuites val>
+
+This allows the TLSv1.3 ciphersuites sent by the client to be modified. This
+list will be combined with any TLSv1.2 and below ciphersuites that have been
+configured. Although the server determines which cipher suite is used it should
+take the first supported cipher in the list sent by the client. See the
+B<ciphers> command for more information. The format for this list is a simple
+colon (":") separated list of TLSv1.3 ciphersuite names.
 
 =item B<-starttls protocol>
 
diff --git a/doc/man1/s_server.pod b/doc/man1/s_server.pod
index ad04359..2f0f79a 100644
--- a/doc/man1/s_server.pod
+++ b/doc/man1/s_server.pod
@@ -113,6 +113,7 @@ B<openssl> B<s_server>
 [B<-curves val>]
 [B<-named_curve val>]
 [B<-cipher val>]
+[B<-ciphersuites val>]
 [B<-dhparam infile>]
 [B<-record_padding val>]
 [B<-debug_broken_protocol>]
@@ -533,12 +534,23 @@ For a list of all possible curves, use:
 
 =item B<-cipher val>
 
-This allows the cipher list used by the server to be modified.  When
-the client sends a list of supported ciphers the first client cipher
-also included in the server list is used. Because the client specifies
-the preference order, the order of the server cipherlist irrelevant. See
+This allows the list of TLSv1.2 and below ciphersuites used by the server to be
+modified. This list is combined with any TLSv1.3 ciphersuites that have been
+configured. When the client sends a list of supported ciphers the first client
+cipher also included in the server list is used. Because the client specifies
+the preference order, the order of the server cipherlist is irrelevant. See
 the B<ciphers> command for more information.
 
+=item B<-ciphersuites val>
+
+This allows the list of TLSv1.3 ciphersuites used by the server to be modified.
+This list is combined with any TLSv1.2 and below ciphersuites that have been
+configured. When the client sends a list of supported ciphers the first client
+cipher also included in the server list is used. Because the client specifies
+the preference order, the order of the server cipherlist is irrelevant. See
+the B<ciphers> command for more information. The format for this list is a
+simple colon (":") separated list of TLSv1.3 ciphersuite names.
+
 =item B<-dhparam infile>
 
 The DH parameter file to use. The ephemeral DH cipher suites generate keys
diff --git a/doc/man1/s_time.pod b/doc/man1/s_time.pod
index ecdac17..62a6788 100644
--- a/doc/man1/s_time.pod
+++ b/doc/man1/s_time.pod
@@ -25,6 +25,7 @@ B<openssl> B<s_time>
 [B<-ssl3>]
 [B<-bugs>]
 [B<-cipher cipherlist>]
+[B<-ciphersuites val>]
 
 =head1 DESCRIPTION
 
@@ -128,10 +129,20 @@ option enables various workarounds.
 
 =item B<-cipher cipherlist>
 
-This allows the cipher list sent by the client to be modified. Although
-the server determines which cipher suite is used it should take the first
-supported cipher in the list sent by the client.
-See the L<ciphers(1)> command for more information.
+This allows the TLSv1.2 and below cipher list sent by the client to be modified.
+This list will be combined with any TLSv1.3 ciphersuites that have been
+configured. Although the server determines which cipher suite is used it should
+take the first supported cipher in the list sent by the client. See the
+L<ciphers(1)> command for more information.
+
+=item B<-ciphersuites val>
+
+This allows the TLSv1.3 ciphersuites sent by the client to be modified. This
+list will be combined with any TLSv1.2 and below ciphersuites that have been
+configured. Although the server determines which cipher suite is used it should
+take the first supported cipher in the list sent by the client. See the
+B<ciphers> command for more information. The format for this list is a simple
+colon (":") separated list of TLSv1.3 ciphersuite names.
 
 =item B<-time length>
 
diff --git a/doc/man3/SSL_CONF_cmd.pod b/doc/man3/SSL_CONF_cmd.pod
index b4392f4..e3dc42c 100644
--- a/doc/man3/SSL_CONF_cmd.pod
+++ b/doc/man3/SSL_CONF_cmd.pod
@@ -89,10 +89,18 @@ can be either the B<NIST> name (e.g. B<P-256>) or an OpenSSL OID name
 
 =item B<-cipher>
 
-Sets the cipher suite list to B<value>. Note: syntax checking of B<value> is
-currently not performed unless a B<SSL> or B<SSL_CTX> structure is
+Sets the TLSv1.2 and below ciphersuite list to B<value>. This list will be
+combined with any configured TLSv1.3 ciphersuites. Note: syntax checking
+of B<value> is currently not performed unless a B<SSL> or B<SSL_CTX> structure is
 associated with B<cctx>.
 
+=item B<-ciphersuites>
+
+Sets the available ciphersuites for TLSv1.3 to value. This is a simple colon
+(":") separated list of TLSv1.3 ciphersuite names in order of preference. This
+list will be combined any configured TLSv1.2 and below ciphersuites.
+
+
 =item B<-cert>
 
 Attempts to use the file B<value> as the certificate for the appropriate
@@ -219,9 +227,16 @@ Note: the command prefix (if set) alters the recognised B<cmd> values.
 
 =item B<CipherString>
 
-Sets the cipher suite list to B<value>. Note: syntax checking of B<value> is
-currently not performed unless an B<SSL> or B<SSL_CTX> structure is
-associated with B<cctx>.
+Sets the ciphersuite list for TLSv1.2 and below to B<value>. This list will be
+combined with any configured TLSv1.3 ciphersuites. Note: syntax
+checking of B<value> is currently not performed unless an B<SSL> or B<SSL_CTX>
+structure is associated with B<cctx>.
+
+=item B<Ciphersuites>
+
+Sets the available ciphersuites for TLSv1.3 to B<value>. This is a simple colon
+(":") separated list of TLSv1.3 ciphersuite names in order of preference. This
+list will be combined any configured TLSv1.2 and below ciphersuites.
 
 =item B<Certificate>
 
diff --git a/doc/man3/SSL_CTX_set_cipher_list.pod b/doc/man3/SSL_CTX_set_cipher_list.pod
index 714bb3a..f4b366e 100644
--- a/doc/man3/SSL_CTX_set_cipher_list.pod
+++ b/doc/man3/SSL_CTX_set_cipher_list.pod
@@ -2,7 +2,11 @@
 
 =head1 NAME
 
-SSL_CTX_set_cipher_list, SSL_set_cipher_list - choose list of available SSL_CIPHERs
+SSL_CTX_set_cipher_list,
+SSL_set_cipher_list,
+SSL_CTX_set_ciphersuites,
+SSL_set_ciphersuites
+- choose list of available SSL_CIPHERs
 
 =head1 SYNOPSIS
 
@@ -11,18 +15,49 @@ SSL_CTX_set_cipher_list, SSL_set_cipher_list - choose list of available SSL_CIPH
  int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str);
  int SSL_set_cipher_list(SSL *ssl, const char *str);
 
+ int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str);
+ int SSL_set_ciphersuites(SSL *s, const char *str);
+
 =head1 DESCRIPTION
 
-SSL_CTX_set_cipher_list() sets the list of available ciphers for B<ctx>
-using the control string B<str>. The format of the string is described
+SSL_CTX_set_cipher_list() sets the list of available ciphers (TLSv1.2 and below)
+for B<ctx> using the control string B<str>. The format of the string is described
 in L<ciphers(1)>. The list of ciphers is inherited by all
-B<ssl> objects created from B<ctx>.
+B<ssl> objects created from B<ctx>. This function does not impact TLSv1.3
+ciphersuites. Use SSL_CTX_set_ciphersuites() to configure those.
+
+SSL_set_cipher_list() sets the list of ciphers (TLSv1.2 and below) only for
+B<ssl>.
+
+SSL_CTX_set_ciphersuites() is used to configure the available TLSv1.3
+ciphersuites for B<ctx>. This is a simple colon (":") separated list of TLSv1.3
+ciphersuite names in order of perference. Valid TLSv1.3 ciphersuite names are:
+
+=over 4
+
+=item TLS_AES_128_GCM_SHA256
+
+=item TLS_AES_256_GCM_SHA384
+
+=item TLS_CHACHA20_POLY1305_SHA256
 
-SSL_set_cipher_list() sets the list of ciphers only for B<ssl>.
+=item TLS_AES_128_CCM_SHA256
+
+=item TLS_AES_128_CCM_8_SHA256
+
+=back
+
+An empty list is permissible. The default value for the this setting is:
+
+"TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
+
+SSL_set_ciphersuites() is the same as SSL_CTX_set_ciphersuites() except it
+configures the ciphersuites for B<ssl>.
 
 =head1 NOTES
 
-The control string B<str> should be universally usable and not depend
+The control string B<str> for SSL_CTX_set_cipher_list() and
+SSL_set_cipher_list() should be universally usable and not depend
 on details of the library configuration (ciphers compiled in). Thus no
 syntax checking takes place. Items that are not recognized, because the
 corresponding ciphers are not compiled in or because they are mistyped,
@@ -55,6 +90,9 @@ and the handshake will fail.
 SSL_CTX_set_cipher_list() and SSL_set_cipher_list() return 1 if any cipher
 could be selected and 0 on complete failure.
 
+SSL_CTX_set_ciphersuites() and SSL_set_ciphersuites() return 1 if the requested
+ciphersuite list was configured, and 0 otherwise.
+
 =head1 SEE ALSO
 
 L<ssl(7)>, L<SSL_get_ciphers(3)>,
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index ec29405..0679ada 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -169,8 +169,13 @@ extern "C" {
 /*
  * The following cipher list is used by default. It also is substituted when
  * an application-defined cipher list string starts with 'DEFAULT'.
+ * This applies to ciphersuites for TLSv1.2 and below.
  */
 # define SSL_DEFAULT_CIPHER_LIST "ALL:!COMPLEMENTOFDEFAULT:!eNULL"
+/* This is the default set of TLSv1.3 ciphersuites */
+# define TLS_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384:" \
+                                  "TLS_CHACHA20_POLY1305_SHA256:" \
+                                  "TLS_AES_128_GCM_SHA256"
 /*
  * As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always
  * starts with a reasonable order, and all we have to do for DEFAULT is
@@ -1500,6 +1505,8 @@ void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio);
 __owur BIO *SSL_get_rbio(const SSL *s);
 __owur BIO *SSL_get_wbio(const SSL *s);
 __owur int SSL_set_cipher_list(SSL *s, const char *str);
+__owur int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str);
+__owur int SSL_set_ciphersuites(SSL *s, const char *str);
 void SSL_set_read_ahead(SSL *s, int yes);
 __owur int SSL_get_verify_mode(const SSL *s);
 __owur int SSL_get_verify_depth(const SSL *s);
diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h
index 454877d..77db871 100644
--- a/include/openssl/sslerr.h
+++ b/include/openssl/sslerr.h
@@ -23,6 +23,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_ADD_KEY_SHARE                              512
 # define SSL_F_BYTES_TO_CIPHER_LIST                       519
 # define SSL_F_CHECK_SUITEB_CIPHER_LIST                   331
+# define SSL_F_CIPHERSUITE_CB                             621
 # define SSL_F_CONSTRUCT_CA_NAMES                         552
 # define SSL_F_CONSTRUCT_KEY_EXCHANGE_TBS                 553
 # define SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH              539
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 0d5b9f8..b9f0918 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -1131,18 +1131,6 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
 # define TLS1_TXT_RSA_PSK_WITH_ARIA_128_GCM_SHA256         "RSA-PSK-ARIA128-GCM-SHA256"
 # define TLS1_TXT_RSA_PSK_WITH_ARIA_256_GCM_SHA384         "RSA-PSK-ARIA256-GCM-SHA384"
 
-
-/* TLSv1.3 ciphersuites */
-/*
- * TODO(TLS1.3): Review the naming scheme for TLSv1.3 ciphers and also the
- * cipherstring selection process for these ciphers
- */
-# define TLS1_3_TXT_AES_128_GCM_SHA256                     "TLS13-AES-128-GCM-SHA256"
-# define TLS1_3_TXT_AES_256_GCM_SHA384                     "TLS13-AES-256-GCM-SHA384"
-# define TLS1_3_TXT_CHACHA20_POLY1305_SHA256               "TLS13-CHACHA20-POLY1305-SHA256"
-# define TLS1_3_TXT_AES_128_CCM_SHA256                     "TLS13-AES-128-CCM-SHA256"
-# define TLS1_3_TXT_AES_128_CCM_8_SHA256                   "TLS13-AES-128-CCM-8-SHA256"
-
 # define TLS_CT_RSA_SIGN                 1
 # define TLS_CT_DSS_SIGN                 2
 # define TLS_CT_RSA_FIXED_DH             3
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 8f0d3e1..f230b5f 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -18,6 +18,7 @@
 #include <openssl/rand.h>
 #include "internal/cryptlib.h"
 
+#define TLS13_NUM_CIPHERS       OSSL_NELEM(tls13_ciphers)
 #define SSL3_NUM_CIPHERS        OSSL_NELEM(ssl3_ciphers)
 #define SSL3_NUM_SCSVS          OSSL_NELEM(ssl3_scsvs)
 
@@ -29,6 +30,90 @@ const unsigned char tls12downgrade[] = {
     0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01
 };
 
+/* The list of available TLSv1.3 ciphers */
+static SSL_CIPHER tls13_ciphers[] = {
+    {
+        1,
+        TLS1_3_RFC_AES_128_GCM_SHA256,
+        TLS1_3_RFC_AES_128_GCM_SHA256,
+        TLS1_3_CK_AES_128_GCM_SHA256,
+        0, 0,
+        SSL_AES128GCM,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA256,
+        128,
+        128,
+    }, {
+        1,
+        TLS1_3_RFC_AES_256_GCM_SHA384,
+        TLS1_3_RFC_AES_256_GCM_SHA384,
+        TLS1_3_CK_AES_256_GCM_SHA384,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_AES256GCM,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        0, 0,
+        SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA384,
+        256,
+        256,
+    },
+#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+    {
+        1,
+        TLS1_3_RFC_CHACHA20_POLY1305_SHA256,
+        TLS1_3_RFC_CHACHA20_POLY1305_SHA256,
+        TLS1_3_CK_CHACHA20_POLY1305_SHA256,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_CHACHA20POLY1305,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        0, 0,
+        SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA256,
+        256,
+        256,
+    },
+#endif
+    {
+        1,
+        TLS1_3_RFC_AES_128_CCM_SHA256,
+        TLS1_3_RFC_AES_128_CCM_SHA256,
+        TLS1_3_CK_AES_128_CCM_SHA256,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_AES128CCM,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        0, 0,
+        SSL_NOT_DEFAULT | SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA256,
+        128,
+        128,
+    }, {
+        1,
+        TLS1_3_RFC_AES_128_CCM_8_SHA256,
+        TLS1_3_RFC_AES_128_CCM_8_SHA256,
+        TLS1_3_CK_AES_128_CCM_8_SHA256,
+        SSL_kANY,
+        SSL_aANY,
+        SSL_AES128CCM8,
+        SSL_AEAD,
+        TLS1_3_VERSION, TLS1_3_VERSION,
+        0, 0,
+        SSL_NOT_DEFAULT | SSL_HIGH,
+        SSL_HANDSHAKE_MAC_SHA256,
+        128,
+        128,
+    }
+};
+
 /*
  * The list of available ciphers, mostly organized into the following
  * groups:
@@ -860,88 +945,6 @@ static SSL_CIPHER ssl3_ciphers[] = {
      },
     {
      1,
-     TLS1_3_TXT_AES_128_GCM_SHA256,
-     TLS1_3_RFC_AES_128_GCM_SHA256,
-     TLS1_3_CK_AES_128_GCM_SHA256,
-     0, 0,
-     SSL_AES128GCM,
-     SSL_AEAD,
-     TLS1_3_VERSION, TLS1_3_VERSION,
-     SSL_kANY,
-     SSL_aANY,
-     SSL_HIGH,
-     SSL_HANDSHAKE_MAC_SHA256,
-     128,
-     128,
-     },
-    {
-     1,
-     TLS1_3_TXT_AES_256_GCM_SHA384,
-     TLS1_3_RFC_AES_256_GCM_SHA384,
-     TLS1_3_CK_AES_256_GCM_SHA384,
-     SSL_kANY,
-     SSL_aANY,
-     SSL_AES256GCM,
-     SSL_AEAD,
-     TLS1_3_VERSION, TLS1_3_VERSION,
-     0, 0,
-     SSL_HIGH,
-     SSL_HANDSHAKE_MAC_SHA384,
-     256,
-     256,
-     },
-#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
-    {
-     1,
-     TLS1_3_TXT_CHACHA20_POLY1305_SHA256,
-     TLS1_3_RFC_CHACHA20_POLY1305_SHA256,
-     TLS1_3_CK_CHACHA20_POLY1305_SHA256,
-     SSL_kANY,
-     SSL_aANY,
-     SSL_CHACHA20POLY1305,
-     SSL_AEAD,
-     TLS1_3_VERSION, TLS1_3_VERSION,
-     0, 0,
-     SSL_HIGH,
-     SSL_HANDSHAKE_MAC_SHA256,
-     256,
-     256,
-     },
-#endif
-    {
-     1,
-     TLS1_3_TXT_AES_128_CCM_SHA256,
-     TLS1_3_RFC_AES_128_CCM_SHA256,
-     TLS1_3_CK_AES_128_CCM_SHA256,
-     SSL_kANY,
-     SSL_aANY,
-     SSL_AES128CCM,
-     SSL_AEAD,
-     TLS1_3_VERSION, TLS1_3_VERSION,
-     0, 0,
-     SSL_NOT_DEFAULT | SSL_HIGH,
-     SSL_HANDSHAKE_MAC_SHA256,
-     128,
-     128,
-     },
-    {
-     1,
-     TLS1_3_TXT_AES_128_CCM_8_SHA256,
-     TLS1_3_RFC_AES_128_CCM_8_SHA256,
-     TLS1_3_CK_AES_128_CCM_8_SHA256,
-     SSL_kANY,
-     SSL_aANY,
-     SSL_AES128CCM8,
-     SSL_AEAD,
-     TLS1_3_VERSION, TLS1_3_VERSION,
-     0, 0,
-     SSL_NOT_DEFAULT | SSL_HIGH,
-     SSL_HANDSHAKE_MAC_SHA256,
-     128,
-     128,
-     },
-    {
-     1,
      TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA,
      TLS1_RFC_ECDHE_ECDSA_WITH_NULL_SHA,
      TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA,
@@ -3207,6 +3210,8 @@ static int cipher_compare(const void *a, const void *b)
 
 void ssl_sort_cipher_list(void)
 {
+    qsort(tls13_ciphers, TLS13_NUM_CIPHERS, sizeof(tls13_ciphers[0]),
+          cipher_compare);
     qsort(ssl3_ciphers, SSL3_NUM_CIPHERS, sizeof(ssl3_ciphers[0]),
           cipher_compare);
     qsort(ssl3_scsvs, SSL3_NUM_SCSVS, sizeof(ssl3_scsvs[0]), cipher_compare);
@@ -4027,6 +4032,9 @@ const SSL_CIPHER *ssl3_get_cipher_by_id(uint32_t id)
     const SSL_CIPHER *cp;
 
     c.id = id;
+    cp = OBJ_bsearch_ssl_cipher_id(&c, tls13_ciphers, TLS13_NUM_CIPHERS);
+    if (cp != NULL)
+        return cp;
     cp = OBJ_bsearch_ssl_cipher_id(&c, ssl3_ciphers, SSL3_NUM_CIPHERS);
     if (cp != NULL)
         return cp;
@@ -4035,17 +4043,19 @@ const SSL_CIPHER *ssl3_get_cipher_by_id(uint32_t id)
 
 const SSL_CIPHER *ssl3_get_cipher_by_std_name(const char *stdname)
 {
-    SSL_CIPHER *c = NULL;
-    SSL_CIPHER *tbl = ssl3_ciphers;
-    size_t i;
+    SSL_CIPHER *c = NULL, *tbl;
+    SSL_CIPHER *alltabs[] = {tls13_ciphers, ssl3_ciphers};
+    size_t i, j, tblsize[] = {TLS13_NUM_CIPHERS, SSL3_NUM_CIPHERS};
 
     /* this is not efficient, necessary to optimize this? */
-    for (i = 0; i < SSL3_NUM_CIPHERS; i++, tbl++) {
-        if (tbl->stdname == NULL)
-            continue;
-        if (strcmp(stdname, tbl->stdname) == 0) {
-            c = tbl;
-            break;
+    for (j = 0; j < OSSL_NELEM(alltabs); j++) {
+        for (i = 0, tbl = alltabs[j]; i < tblsize[j]; i++, tbl++) {
+            if (tbl->stdname == NULL)
+                continue;
+            if (strcmp(stdname, tbl->stdname) == 0) {
+                c = tbl;
+                break;
+            }
         }
     }
     if (c == NULL) {
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index d31aeb7..49e16fc 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -1274,12 +1274,14 @@ static int check_suiteb_cipher_list(const SSL_METHOD *meth, CERT *c,
 }
 #endif
 
-STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, STACK_OF(SSL_CIPHER)
-                                             **cipher_list, STACK_OF(SSL_CIPHER)
-                                             **cipher_list_by_id,
-                                             const char *rule_str, CERT *c)
+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,
+                                             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;
+    int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases, i;
     uint32_t disabled_mkey, disabled_auth, disabled_enc, disabled_mac;
     STACK_OF(SSL_CIPHER) *cipherstack, *tmp_cipher_list;
     const char *rule_p;
@@ -1469,6 +1471,15 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, STACK
         return NULL;
     }
 
+    /* Add TLSv1.3 ciphers first - we always prefer those if possible */
+    for (i = 0; i < sk_SSL_CIPHER_num(tls13_ciphersuites); i++) {
+        if (!sk_SSL_CIPHER_push(cipherstack,
+                                sk_SSL_CIPHER_value(tls13_ciphersuites, i))) {
+            sk_SSL_CIPHER_free(cipherstack);
+            return NULL;
+        }
+    }
+
     /*
      * The cipher selection for the list is done. The ciphers are added
      * to the resulting precedence to the STACK_OF(SSL_CIPHER).
diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c
index 2c50d19..30e43d9 100644
--- a/ssl/ssl_conf.c
+++ b/ssl/ssl_conf.c
@@ -256,6 +256,7 @@ static int cmd_ECDHParameters(SSL_CONF_CTX *cctx, const char *value)
 static int cmd_CipherString(SSL_CONF_CTX *cctx, const char *value)
 {
     int rv = 1;
+
     if (cctx->ctx)
         rv = SSL_CTX_set_cipher_list(cctx->ctx, value);
     if (cctx->ssl)
@@ -263,6 +264,17 @@ static int cmd_CipherString(SSL_CONF_CTX *cctx, const char *value)
     return rv > 0;
 }
 
+static int cmd_Ciphersuites(SSL_CONF_CTX *cctx, const char *value)
+{
+    int rv = 1;
+
+    if (cctx->ctx)
+        rv = SSL_CTX_set_ciphersuites(cctx->ctx, value);
+    if (cctx->ssl)
+        rv = SSL_set_ciphersuites(cctx->ssl, value);
+    return rv > 0;
+}
+
 static int cmd_Protocol(SSL_CONF_CTX *cctx, const char *value)
 {
     static const ssl_flag_tbl ssl_protocol_list[] = {
@@ -606,6 +618,7 @@ static const ssl_conf_cmd_tbl ssl_conf_cmds[] = {
     SSL_CONF_CMD_STRING(ECDHParameters, "named_curve", SSL_CONF_FLAG_SERVER),
 #endif
     SSL_CONF_CMD_STRING(CipherString, "cipher", 0),
+    SSL_CONF_CMD_STRING(Ciphersuites, "ciphersuites", 0),
     SSL_CONF_CMD_STRING(Protocol, NULL, 0),
     SSL_CONF_CMD_STRING(MinProtocol, "min_protocol", 0),
     SSL_CONF_CMD_STRING(MaxProtocol, "max_protocol", 0),
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index e367a36..64580bb 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -20,6 +20,7 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
      "bytes_to_cipher_list"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_CHECK_SUITEB_CIPHER_LIST, 0),
      "check_suiteb_cipher_list"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_CIPHERSUITE_CB, 0), "ciphersuite_cb"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_CONSTRUCT_CA_NAMES, 0), "construct_ca_names"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_CONSTRUCT_KEY_EXCHANGE_TBS, 0),
      "construct_key_exchange_tbs"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 0814fb3..d5c5918 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -653,7 +653,9 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth)
 
     ctx->method = meth;
 
-    sk = ssl_create_cipher_list(ctx->method, &(ctx->cipher_list),
+    sk = ssl_create_cipher_list(ctx->method,
+                                ctx->tls13_ciphersuites,
+                                &(ctx->cipher_list),
                                 &(ctx->cipher_list_by_id),
                                 SSL_DEFAULT_CIPHER_LIST, ctx->cert);
     if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0)) {
@@ -712,6 +714,11 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->max_cert_list = ctx->max_cert_list;
     s->max_early_data = ctx->max_early_data;
 
+    /* Shallow copy of the ciphersuites stack */
+    s->tls13_ciphersuites = sk_SSL_CIPHER_dup(ctx->tls13_ciphersuites);
+    if (s->tls13_ciphersuites == NULL)
+        goto err;
+
     /*
      * Earlier library versions used to copy the pointer to the CERT, not
      * its contents; only when setting new parameters for the per-SSL
@@ -1156,6 +1163,7 @@ void SSL_free(SSL *s)
     /* add extra stuff */
     sk_SSL_CIPHER_free(s->cipher_list);
     sk_SSL_CIPHER_free(s->cipher_list_by_id);
+    sk_SSL_CIPHER_free(s->tls13_ciphersuites);
 
     /* Make the next call work :-) */
     if (s->session != NULL) {
@@ -2520,8 +2528,9 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str)
 {
     STACK_OF(SSL_CIPHER) *sk;
 
-    sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list,
-                                &ctx->cipher_list_by_id, str, ctx->cert);
+    sk = ssl_create_cipher_list(ctx->method, ctx->tls13_ciphersuites,
+                                &ctx->cipher_list, &ctx->cipher_list_by_id, str,
+                                ctx->cert);
     /*
      * ssl_create_cipher_list may return an empty stack if it was unable to
      * find a cipher matching the given rule string (for example if the rule
@@ -2543,8 +2552,9 @@ int SSL_set_cipher_list(SSL *s, const char *str)
 {
     STACK_OF(SSL_CIPHER) *sk;
 
-    sk = ssl_create_cipher_list(s->ctx->method, &s->cipher_list,
-                                &s->cipher_list_by_id, str, s->cert);
+    sk = ssl_create_cipher_list(s->ctx->method, s->tls13_ciphersuites,
+                                &s->cipher_list, &s->cipher_list_by_id, str,
+                                s->cert);
     /* see comment in SSL_CTX_set_cipher_list */
     if (sk == NULL)
         return 0;
@@ -2555,6 +2565,99 @@ int SSL_set_cipher_list(SSL *s, const char *str)
     return 1;
 }
 
+static int ciphersuite_cb(const char *elem, int len, void *arg)
+{
+    STACK_OF(SSL_CIPHER) *ciphersuites = (STACK_OF(SSL_CIPHER) *)arg;
+    const SSL_CIPHER *cipher;
+    /* Arbitrary sized temp buffer for the cipher name. Should be big enough */
+    char name[80];
+
+    if (len > (int)(sizeof(name) - 1)) {
+        SSLerr(SSL_F_CIPHERSUITE_CB, SSL_R_NO_CIPHER_MATCH);
+        return 0;
+    }
+
+    memcpy(name, elem, len);
+    name[len] = '\0';
+
+    cipher = ssl3_get_cipher_by_std_name(name);
+    if (cipher == NULL) {
+        SSLerr(SSL_F_CIPHERSUITE_CB, SSL_R_NO_CIPHER_MATCH);
+        return 0;
+    }
+
+    if (!sk_SSL_CIPHER_push(ciphersuites, cipher)) {
+        SSLerr(SSL_F_CIPHERSUITE_CB, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int set_ciphersuites(STACK_OF(SSL_CIPHER) **currciphers, const char *str)
+{
+    STACK_OF(SSL_CIPHER) *newciphers = sk_SSL_CIPHER_new_null();
+
+    if (newciphers == NULL)
+        return 0;
+
+    /* Parse the list. We explicitly allow an empty list */
+    if (*str != '\0'
+            && !CONF_parse_list(str, ':', 1, ciphersuite_cb, newciphers)) {
+        sk_SSL_CIPHER_free(newciphers);
+        return 0;
+    }
+    sk_SSL_CIPHER_free(*currciphers);
+    *currciphers = newciphers;
+
+    return 1;
+}
+
+static int update_cipher_list(STACK_OF(SSL_CIPHER) *cipher_list,
+                              STACK_OF(SSL_CIPHER) *tls13_ciphersuites)
+{
+    int i;
+
+    /*
+     * Delete any existing TLSv1.3 ciphersuites. These are always first in the
+     * list.
+     */
+    while (sk_SSL_CIPHER_num(cipher_list) > 0
+           && sk_SSL_CIPHER_value(cipher_list, 0)->min_tls == TLS1_3_VERSION)
+        sk_SSL_CIPHER_delete(cipher_list, 0);
+
+    /* Insert the new TLSv1.3 ciphersuites */
+    for (i = 0; i < sk_SSL_CIPHER_num(tls13_ciphersuites); i++)
+        sk_SSL_CIPHER_insert(cipher_list,
+                             sk_SSL_CIPHER_value(tls13_ciphersuites, i), i);
+
+    return 1;
+}
+
+int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str)
+{
+    int ret = set_ciphersuites(&(ctx->tls13_ciphersuites), 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->tls13_ciphersuites);
+    }
+
+    return ret;
+}
+
+int SSL_set_ciphersuites(SSL *s, const char *str)
+{
+    int ret = set_ciphersuites(&(s->tls13_ciphersuites), 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->tls13_ciphersuites);
+    }
+
+    return ret;
+}
+
 char *SSL_get_shared_ciphers(const SSL *s, char *buf, int len)
 {
     char *p;
@@ -2915,7 +3018,12 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
     if (ret->ctlog_store == NULL)
         goto err;
 #endif
+
+    if (!SSL_CTX_set_ciphersuites(ret, TLS_DEFAULT_CIPHERSUITES))
+        goto err;
+
     if (!ssl_create_cipher_list(ret->method,
+                                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) {
@@ -3075,6 +3183,7 @@ void SSL_CTX_free(SSL_CTX *a)
 #endif
     sk_SSL_CIPHER_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);
     sk_X509_NAME_pop_free(a->ca_names, X509_NAME_free);
     sk_X509_pop_free(a->extra_certs, X509_free);
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 246605c..4b8482a 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -740,6 +740,8 @@ struct ssl_ctx_st {
     STACK_OF(SSL_CIPHER) *cipher_list;
     /* same as above but sorted for lookup */
     STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+    /* TLSv1.3 specific ciphersuites */
+    STACK_OF(SSL_CIPHER) *tls13_ciphersuites;
     struct x509_store_st /* X509_STORE */ *cert_store;
     LHASH_OF(SSL_SESSION) *sessions;
     /*
@@ -1108,6 +1110,8 @@ struct ssl_st {
     /* crypto */
     STACK_OF(SSL_CIPHER) *cipher_list;
     STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+    /* TLSv1.3 specific ciphersuites */
+    STACK_OF(SSL_CIPHER) *tls13_ciphersuites;
     /*
      * These are the ones being used, the ones in SSL_SESSION are the ones to
      * be 'copied' into these ones
@@ -2198,10 +2202,10 @@ __owur int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b);
 DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id);
 __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 *meth,
-                                                    STACK_OF(SSL_CIPHER) **pref,
-                                                    STACK_OF(SSL_CIPHER)
-                                                    **sorted,
+__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,
+                                                    STACK_OF(SSL_CIPHER) **cipher_list_by_id,
                                                     const char *rule_str,
                                                     CERT *c);
 __owur int ssl_cache_cipherlist(SSL *s, PACKET *cipher_suites, int sslv2format);
diff --git a/test/cipherlist_test.c b/test/cipherlist_test.c
index 50e3027..b224983 100644
--- a/test/cipherlist_test.c
+++ b/test/cipherlist_test.c
@@ -63,6 +63,13 @@ static CIPHERLIST_TEST_FIXTURE *set_up(const char *const test_case_name)
  * are currently broken and should be considered mission impossible in libssl.
  */
 static const uint32_t default_ciphers_in_order[] = {
+#ifndef OPENSSL_NO_TLS1_3
+    TLS1_3_CK_AES_256_GCM_SHA384,
+# if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+    TLS1_3_CK_CHACHA20_POLY1305_SHA256,
+# endif
+    TLS1_3_CK_AES_128_GCM_SHA256,
+#endif
 #ifndef OPENSSL_NO_TLS1_2
 # ifndef OPENSSL_NO_EC
     TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
@@ -127,13 +134,6 @@ static const uint32_t default_ciphers_in_order[] = {
     TLS1_CK_RSA_WITH_AES_256_GCM_SHA384,
     TLS1_CK_RSA_WITH_AES_128_GCM_SHA256,
 #endif
-#ifndef OPENSSL_NO_TLS1_3
-    TLS1_3_CK_AES_256_GCM_SHA384,
-# if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
-    TLS1_3_CK_CHACHA20_POLY1305_SHA256,
-# endif
-    TLS1_3_CK_AES_128_GCM_SHA256,
-#endif
 #ifndef OPENSSL_NO_TLS1_2
     TLS1_CK_RSA_WITH_AES_256_SHA256,
     TLS1_CK_RSA_WITH_AES_128_SHA256,
diff --git a/test/clienthellotest.c b/test/clienthellotest.c
index 5cff519..5eded83 100644
--- a/test/clienthellotest.c
+++ b/test/clienthellotest.c
@@ -97,8 +97,7 @@ static int test_client_hello(int currtest)
          * ClientHello is already going to be quite long. To avoid getting one
          * that is too long for this test we use a restricted ciphersuite list
          */
-        if (!TEST_true(SSL_CTX_set_cipher_list(ctx,
-                                               "TLS13-AES-128-GCM-SHA256")))
+        if (!TEST_true(SSL_CTX_set_cipher_list(ctx, "")))
             goto end;
          /* Fall through */
     case TEST_ADD_PADDING:
@@ -121,7 +120,9 @@ static int test_client_hello(int currtest)
          * not need padding.
          */
         } else if (!TEST_true(SSL_CTX_set_cipher_list(ctx,
-                              "AES128-SHA:TLS13-AES-128-GCM-SHA256"))) {
+                              "AES128-SHA"))
+                   || !TEST_true(SSL_CTX_set_ciphersuites(ctx,
+                                 "TLS_AES_128_GCM_SHA256"))) {
             goto end;
         }
         break;
diff --git a/test/fatalerrtest.c b/test/fatalerrtest.c
index 2335735..85b11c8 100644
--- a/test/fatalerrtest.c
+++ b/test/fatalerrtest.c
@@ -38,6 +38,10 @@ static int test_fatalerr(void)
      */
     if (!TEST_true(SSL_CTX_set_cipher_list(sctx, "AES128-SHA"))
             || !TEST_true(SSL_CTX_set_cipher_list(cctx, "AES256-SHA"))
+            || !TEST_true(SSL_CTX_set_ciphersuites(sctx,
+                                                   "TLS_AES_128_GCM_SHA256"))
+            || !TEST_true(SSL_CTX_set_ciphersuites(cctx,
+                                                   "TLS_AES_256_GCM_SHA384"))
             || !TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, NULL,
                           NULL)))
         goto err;
diff --git a/test/recipes/70-test_sslsigalgs.t b/test/recipes/70-test_sslsigalgs.t
index c1d8272..95af8a1 100644
--- a/test/recipes/70-test_sslsigalgs.t
+++ b/test/recipes/70-test_sslsigalgs.t
@@ -116,7 +116,7 @@ SKIP: {
     #        should succeed
     $proxy->clear();
     $proxy->serverflags("-no_tls1_3");
-    $proxy->ciphers("ECDHE-RSA-AES128-SHA:TLS13-AES-128-GCM-SHA256");
+    $proxy->ciphers("ECDHE-RSA-AES128-SHA");
     $proxy->filter(undef);
     $proxy->start();
     ok(TLSProxy::Message->success, "TLSv1.3 client TLSv1.2 server");
@@ -131,7 +131,7 @@ SKIP: {
     $proxy->clear();
     $testtype = NO_SIG_ALGS_EXT;
     $proxy->clientflags("-no_tls1_3");
-    $proxy->ciphers("ECDHE-RSA-AES128-SHA:TLS13-AES-128-GCM-SHA256");
+    $proxy->ciphers("ECDHE-RSA-AES128-SHA");
     $proxy->start();
     ok(TLSProxy::Message->success, "No TLSv1.2 sigalgs");
 
@@ -139,7 +139,7 @@ SKIP: {
     $proxy->clear();
     $testtype = EMPTY_SIG_ALGS_EXT;
     $proxy->clientflags("-no_tls1_3");
-    $proxy->ciphers("ECDHE-RSA-AES128-SHA:TLS13-AES-128-GCM-SHA256");
+    $proxy->ciphers("ECDHE-RSA-AES128-SHA");
     $proxy->start();
     ok(TLSProxy::Message->fail, "Empty TLSv1.2 sigalgs");
 
@@ -147,7 +147,7 @@ SKIP: {
     $proxy->clear();
     $testtype = NO_KNOWN_SIG_ALGS;
     $proxy->clientflags("-no_tls1_3");
-    $proxy->ciphers("ECDHE-RSA-AES128-SHA:TLS13-AES-128-GCM-SHA256");
+    $proxy->ciphers("ECDHE-RSA-AES128-SHA");
     $proxy->start();
     ok(TLSProxy::Message->fail, "No known TLSv1.3 sigalgs");
 
@@ -156,7 +156,7 @@ SKIP: {
     $proxy->clear();
     $testtype = NO_PSS_SIG_ALGS;
     $proxy->clientflags("-no_tls1_3");
-    $proxy->ciphers("ECDHE-RSA-AES128-SHA:TLS13-AES-128-GCM-SHA256");
+    $proxy->ciphers("ECDHE-RSA-AES128-SHA");
     $proxy->start();
     ok(TLSProxy::Message->success, "No PSS TLSv1.2 sigalgs");
 
@@ -164,7 +164,7 @@ SKIP: {
     $proxy->clear();
     $testtype = PSS_ONLY_SIG_ALGS;
     $proxy->serverflags("-no_tls1_3");
-    $proxy->ciphers("ECDHE-RSA-AES128-SHA:TLS13-AES-128-GCM-SHA256");
+    $proxy->ciphers("ECDHE-RSA-AES128-SHA");
     $proxy->start();
     ok(TLSProxy::Message->success, "PSS only sigalgs in TLSv1.2");
 
@@ -175,7 +175,7 @@ SKIP: {
     $proxy->clear();
     $testtype = PSS_ONLY_SIG_ALGS;
     $proxy->clientflags("-no_tls1_3 -sigalgs RSA+SHA256");
-    $proxy->ciphers("ECDHE-RSA-AES128-SHA:TLS13-AES-128-GCM-SHA256");
+    $proxy->ciphers("ECDHE-RSA-AES128-SHA");
     $proxy->start();
     ok(TLSProxy::Message->fail, "Sigalg we did not send in TLSv1.2");
 
@@ -183,7 +183,7 @@ SKIP: {
     #         matches the certificate should fail in TLSv1.2
     $proxy->clear();
     $proxy->clientflags("-no_tls1_3 -sigalgs ECDSA+SHA256");
-    $proxy->ciphers("ECDHE-RSA-AES128-SHA:TLS13-AES-128-GCM-SHA256");
+    $proxy->ciphers("ECDHE-RSA-AES128-SHA");
     $proxy->filter(undef);
     $proxy->start();
     ok(TLSProxy::Message->fail, "No matching TLSv1.2 sigalgs");
@@ -197,7 +197,7 @@ SKIP: {
                                                "server-ecdsa-cert.pem") .
                         " -key " . srctop_file("test", "certs",
                                                "server-ecdsa-key.pem")),
-    $proxy->ciphers("ECDHE-ECDSA-AES128-SHA:TLS13-AES-128-GCM-SHA256");
+    $proxy->ciphers("ECDHE-ECDSA-AES128-SHA");
     $proxy->start();
     ok(TLSProxy::Message->success, "No TLSv1.2 sigalgs, ECDSA");
 }
diff --git a/test/recipes/70-test_tls13hrr.t b/test/recipes/70-test_tls13hrr.t
index 56b7faf..e0b47ed 100644
--- a/test/recipes/70-test_tls13hrr.t
+++ b/test/recipes/70-test_tls13hrr.t
@@ -53,7 +53,7 @@ ok(TLSProxy::Message->fail(), "Server ciphersuite changes");
 #        we end up selecting a different ciphersuite between HRR and the SH
 $proxy->clear();
 $proxy->serverflags("-curves P-256");
-$proxy->ciphers("TLS13-AES-128-GCM-SHA256:TLS13-AES-256-GCM-SHA384");
+$proxy->ciphersuitess("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384");
 $testtype = CHANGE_CH1_CIPHERSUITE;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "Client ciphersuite changes");
@@ -85,8 +85,7 @@ sub hrr_filter
 
     my $ch1 = ${$proxy->message_list}[0];
 
-    # The server prefers TLS13-AES-256-GCM-SHA384 so it will pick that next
-    # time around
+    # The server will always pick TLS_AES_256_GCM_SHA384
     my @ciphersuites = (TLSProxy::Message::CIPHER_TLS13_AES_128_GCM_SHA256);
     $ch1->ciphersuite_len(2 * scalar @ciphersuites);
     $ch1->ciphersuites(\@ciphersuites);
diff --git a/test/recipes/70-test_tls13psk.t b/test/recipes/70-test_tls13psk.t
index bd2508d..fa30dd1 100644
--- a/test/recipes/70-test_tls13psk.t
+++ b/test/recipes/70-test_tls13psk.t
@@ -82,10 +82,10 @@ $proxy->clear();
 $proxy->clientflags("-sess_in ".$session);
 $proxy->filter(\&modify_psk_filter);
 $proxy->serverflags("-curves P-256");
-$proxy->cipherc("TLS13-AES-128-GCM-SHA256:TLS13-AES-256-GCM-SHA384");
-$proxy->ciphers("TLS13-AES-256-GCM-SHA384");
+$proxy->ciphersuitesc("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384");
+$proxy->ciphersuitess("TLS_AES_256_GCM_SHA384");
 #We force an early failure because TLS Proxy doesn't actually support
-#TLS13-AES-256-GCM-SHA384. That doesn't matter for this test though.
+#TLS_AES_256_GCM_SHA384. That doesn't matter for this test though.
 $testtype = ILLEGAL_EXT_SECOND_CH;
 $proxy->start();
 #Check if the PSK is present in the second ClientHello
diff --git a/test/recipes/80-test_ssl_old.t b/test/recipes/80-test_ssl_old.t
index f89779c..377bf09 100644
--- a/test/recipes/80-test_ssl_old.t
+++ b/test/recipes/80-test_ssl_old.t
@@ -432,9 +432,12 @@ sub testssl {
             if $protocolciphersuitecount + scalar(keys %ciphersuites) == 0;
 
         # The count of protocols is because in addition to the ciphersuites
-        # we got above, we're running a weak DH test for each protocol
-        plan tests => scalar(@protocols) + $protocolciphersuitecount
-            + scalar(keys %ciphersuites);
+        # we got above, we're running a weak DH test for each protocol (except
+        # TLSv1.3)
+        my $testcount = scalar(@protocols) + $protocolciphersuitecount
+                        + scalar(keys %ciphersuites);
+        $testcount-- unless $no_tls1_3;
+        plan tests => $testcount;
 
         foreach my $protocol (@protocols) {
             ok($ciphersstatus{$protocol}, "Getting ciphers for $protocol");
@@ -445,21 +448,27 @@ sub testssl {
             # ssltest_old doesn't know -tls1_3, but that's fine, since that's
             # the default choice if TLSv1.3 enabled
             my $flag = $protocol eq "-tls1_3" ? "" : $protocol;
+            my $ciphersuites = "";
             foreach my $cipher (@{$ciphersuites{$protocol}}) {
                 if ($protocol eq "-ssl3" && $cipher =~ /ECDH/ ) {
                     note "*****SKIPPING $protocol $cipher";
                     ok(1);
                 } else {
+                    if ($protocol eq "-tls1_3") {
+                        $ciphersuites = $cipher;
+                        $cipher = "";
+                    }
                     ok(run(test([@ssltest, @exkeys, "-cipher", $cipher,
-                                 $flag || ()])),
-                    "Testing $cipher");
+                                 "-ciphersuites", $ciphersuites, $flag || ()])),
+                       "Testing $cipher");
                 }
             }
+            next if $protocol eq "-tls1_3";
             is(run(test([@ssltest,
                          "-s_cipher", "EDH",
                          "-c_cipher", 'EDH:@SECLEVEL=1',
                          "-dhe512",
-                         $protocol eq "SSLv3" ? ("-ssl3") : ()])), 0,
+                         $protocol])), 0,
                "testing connection with weak DH, expecting failure");
         }
     };
diff --git a/test/ssl-tests/02-protocol-version.conf b/test/ssl-tests/02-protocol-version.conf
index d0a64cd..4b7d7df 100644
--- a/test/ssl-tests/02-protocol-version.conf
+++ b/test/ssl-tests/02-protocol-version.conf
@@ -18787,6 +18787,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [676-ciphersuite-sanity-check-client-client]
 CipherString = AES128-SHA
+Ciphersuites = 
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -18806,6 +18807,7 @@ client = 677-ciphersuite-sanity-check-server-client
 [677-ciphersuite-sanity-check-server-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = AES128-SHA
+Ciphersuites = 
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [677-ciphersuite-sanity-check-server-client]
diff --git a/test/ssl-tests/protocol_version.pm b/test/ssl-tests/protocol_version.pm
index edc0dd2..2cdc5db 100644
--- a/test/ssl-tests/protocol_version.pm
+++ b/test/ssl-tests/protocol_version.pm
@@ -137,6 +137,7 @@ sub generate_version_tests {
         "client" => {
             #Offering only <=TLSv1.2 ciphersuites with TLSv1.3 should fail
             "CipherString" => "AES128-SHA",
+            "Ciphersuites" => "",
         },
         "server" => {
             "MaxProtocol" => "TLSv1.2"
@@ -154,6 +155,7 @@ sub generate_version_tests {
         "server" => {
             #Allowing only <=TLSv1.2 ciphersuites with TLSv1.3 should fail
             "CipherString" => "AES128-SHA",
+            "Ciphersuites" => "",
         },
         "test" => {
             "ExpectedResult" => "ServerFail",
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 32f60e5..2c122be 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -2381,8 +2381,8 @@ static int test_ciphersuite_change(void)
     if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
                                        TLS_client_method(), &sctx,
                                        &cctx, cert, privkey))
-            || !TEST_true(SSL_CTX_set_cipher_list(cctx,
-                                                  "TLS13-AES-128-GCM-SHA256"))
+            || !TEST_true(SSL_CTX_set_ciphersuites(cctx,
+                                                   "TLS_AES_128_GCM_SHA256"))
             || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
                                           &clientssl, NULL, NULL))
             || !TEST_true(create_ssl_connection(serverssl, clientssl,
@@ -2400,8 +2400,8 @@ static int test_ciphersuite_change(void)
 
 # if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
     /* Check we can resume a session with a different SHA-256 ciphersuite */
-    if (!TEST_true(SSL_CTX_set_cipher_list(cctx,
-                                           "TLS13-CHACHA20-POLY1305-SHA256"))
+    if (!TEST_true(SSL_CTX_set_ciphersuites(cctx,
+                                            "TLS_CHACHA20_POLY1305_SHA256"))
             || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
                                              NULL, NULL))
             || !TEST_true(SSL_set_session(clientssl, clntsess))
@@ -2423,7 +2423,7 @@ static int test_ciphersuite_change(void)
      * Check attempting to resume a SHA-256 session with no SHA-256 ciphersuites
      * succeeds but does not resume.
      */
-    if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "TLS13-AES-256-GCM-SHA384"))
+    if (!TEST_true(SSL_CTX_set_ciphersuites(cctx, "TLS_AES_256_GCM_SHA384"))
             || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
                                              NULL, NULL))
             || !TEST_true(SSL_set_session(clientssl, clntsess))
@@ -2441,7 +2441,7 @@ static int test_ciphersuite_change(void)
     serverssl = clientssl = NULL;
 
     /* Create a session based on SHA384 */
-    if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "TLS13-AES-256-GCM-SHA384"))
+    if (!TEST_true(SSL_CTX_set_ciphersuites(cctx, "TLS_AES_256_GCM_SHA384"))
             || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
                                           &clientssl, NULL, NULL))
             || !TEST_true(create_ssl_connection(serverssl, clientssl,
@@ -2455,10 +2455,10 @@ static int test_ciphersuite_change(void)
     SSL_free(clientssl);
     serverssl = clientssl = NULL;
 
-    if (!TEST_true(SSL_CTX_set_cipher_list(cctx,
-                   "TLS13-AES-128-GCM-SHA256:TLS13-AES-256-GCM-SHA384"))
-            || !TEST_true(SSL_CTX_set_cipher_list(sctx,
-                                                  "TLS13-AES-256-GCM-SHA384"))
+    if (!TEST_true(SSL_CTX_set_ciphersuites(cctx,
+                   "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384"))
+            || !TEST_true(SSL_CTX_set_ciphersuites(sctx,
+                                                   "TLS_AES_256_GCM_SHA384"))
             || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
                                              NULL, NULL))
             || !TEST_true(SSL_set_session(clientssl, clntsess))
@@ -2520,7 +2520,7 @@ static int test_tls13_psk(int idx)
      * We use a ciphersuite with SHA256 to ease testing old style PSK callbacks
      * which will always default to SHA256
      */
-    if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "TLS13-AES-128-GCM-SHA256")))
+    if (!TEST_true(SSL_CTX_set_ciphersuites(cctx, "TLS_AES_128_GCM_SHA256")))
         goto end;
 
     /*
diff --git a/test/sslcorrupttest.c b/test/sslcorrupttest.c
index a0bca38..1923100 100644
--- a/test/sslcorrupttest.c
+++ b/test/sslcorrupttest.c
@@ -202,19 +202,17 @@ static int test_ssl_corrupt(int testidx)
         goto end;
 
     if (!TEST_ptr(ciphers = SSL_CTX_get_ciphers(cctx))
+            || !TEST_true(SSL_CTX_set_ciphersuites(cctx, ""))
             || !TEST_int_eq(sk_SSL_CIPHER_num(ciphers), 1)
             || !TEST_ptr(currcipher = sk_SSL_CIPHER_value(ciphers, 0)))
         goto end;
 
     /*
-     * If we haven't got a TLSv1.3 cipher, then we mustn't attempt to use
-     * TLSv1.3. Version negotiation happens before cipher selection, so we will
-     * get a "no shared cipher" error.
+     * No ciphers we are using are TLSv1.3 compatible so we should not attempt
+     * to negotiate TLSv1.3
      */
-    if (strcmp(SSL_CIPHER_get_version(currcipher), "TLSv1.3") != 0) {
-        if (!TEST_true(SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION)))
-            goto end;
-    }
+    if (!TEST_true(SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION)))
+        goto end;
 
     if (!TEST_ptr(c_to_s_fbio = BIO_new(bio_f_tls_corrupt_filter())))
         goto end;
diff --git a/test/ssltest_old.c b/test/ssltest_old.c
index 349d30a..7d31d36 100644
--- a/test/ssltest_old.c
+++ b/test/ssltest_old.c
@@ -612,6 +612,7 @@ static int custom_ext_3_srv_add_cb(SSL *s, unsigned int ext_type,
 }
 
 static char *cipher = NULL;
+static char *ciphersuites = NULL;
 static int verbose = 0;
 static int debug = 0;
 
@@ -671,7 +672,8 @@ static void sv_usage(void)
     fprintf(stderr, " -c_cert arg   - Client certificate file\n");
     fprintf(stderr,
             " -c_key arg    - Client key file (default: same as -c_cert)\n");
-    fprintf(stderr, " -cipher arg   - The cipher list\n");
+    fprintf(stderr, " -cipher arg   - The TLSv1.2 and below cipher list\n");
+    fprintf(stderr, " -ciphersuites arg   - The TLSv1.3 ciphersuites\n");
     fprintf(stderr, " -bio_pair     - Use BIO pairs\n");
     fprintf(stderr, " -ipv4         - Use IPv4 connection on localhost\n");
     fprintf(stderr, " -ipv6         - Use IPv6 connection on localhost\n");
@@ -918,7 +920,6 @@ int main(int argc, char *argv[])
 
     verbose = 0;
     debug = 0;
-    cipher = 0;
 
     bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
 
@@ -1046,6 +1047,10 @@ int main(int argc, char *argv[])
             if (--argc < 1)
                 goto bad;
             cipher = *(++argv);
+        } else if (strcmp(*argv, "-ciphersuites") == 0) {
+            if (--argc < 1)
+                goto bad;
+            ciphersuites = *(++argv);
         } else if (strcmp(*argv, "-CApath") == 0) {
             if (--argc < 1)
                 goto bad;
@@ -1377,6 +1382,14 @@ int main(int argc, char *argv[])
             goto end;
         }
     }
+    if (ciphersuites != NULL) {
+        if (!SSL_CTX_set_ciphersuites(c_ctx, ciphersuites)
+            || !SSL_CTX_set_ciphersuites(s_ctx, ciphersuites)
+            || !SSL_CTX_set_ciphersuites(s_ctx2, ciphersuites)) {
+            ERR_print_errors(bio_err);
+            goto end;
+        }
+    }
 
 #ifndef OPENSSL_NO_CT
     if (ct_validation &&
diff --git a/util/libssl.num b/util/libssl.num
index db844e3..344d684 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -484,3 +484,5 @@ SSL_SESSION_set1_ticket_appdata         484	1_1_1	EXIST::FUNCTION:
 SSL_CTX_set_session_ticket_cb           485	1_1_1	EXIST::FUNCTION:
 SSL_CTX_set_stateless_cookie_generate_cb 486	1_1_1	EXIST::FUNCTION:
 SSL_CTX_set_stateless_cookie_verify_cb  487	1_1_1	EXIST::FUNCTION:
+SSL_CTX_set_ciphersuites                488	1_1_1	EXIST::FUNCTION:
+SSL_set_ciphersuites                    489	1_1_1	EXIST::FUNCTION:
diff --git a/util/perl/TLSProxy/Proxy.pm b/util/perl/TLSProxy/Proxy.pm
index 0b722c1..db7b19c 100644
--- a/util/perl/TLSProxy/Proxy.pm
+++ b/util/perl/TLSProxy/Proxy.pm
@@ -58,7 +58,9 @@ sub new
         cert => $cert,
         debug => $debug,
         cipherc => "",
-        ciphers => "AES128-SHA:TLS13-AES-128-GCM-SHA256",
+        ciphersuitesc => "",
+        ciphers => "AES128-SHA",
+        ciphersuitess => "TLS_AES_128_GCM_SHA256",
         flight => 0,
         record_list => [],
         message_list => [],
@@ -135,6 +137,7 @@ sub clearClient
     my $self = shift;
 
     $self->{cipherc} = "";
+    $self->{ciphersuitec} = "";
     $self->{flight} = 0;
     $self->{record_list} = [];
     $self->{message_list} = [];
@@ -153,7 +156,8 @@ sub clear
     my $self = shift;
 
     $self->clearClient;
-    $self->{ciphers} = "AES128-SHA:TLS13-AES-128-GCM-SHA256";
+    $self->{ciphers} = "AES128-SHA";
+    $self->{ciphersuitess} = "TLS_AES_128_GCM_SHA256";
     $self->{serverflags} = "";
     $self->{serverconnects} = 1;
     $self->{serverpid} = 0;
@@ -198,6 +202,9 @@ sub start
         if ($self->ciphers ne "") {
             $execcmd .= " -cipher ".$self->ciphers;
         }
+        if ($self->ciphersuitess ne "") {
+            $execcmd .= " -ciphersuites ".$self->ciphersuitess;
+        }
         if ($self->serverflags ne "") {
             $execcmd .= " ".$self->serverflags;
         }
@@ -234,6 +241,9 @@ sub clientstart
             if ($self->cipherc ne "") {
                 $execcmd .= " -cipher ".$self->cipherc;
             }
+            if ($self->ciphersuitesc ne "") {
+                $execcmd .= " -ciphersuites ".$self->ciphersuitesc;
+            }
             if ($self->clientflags ne "") {
                 $execcmd .= " ".$self->clientflags;
             }
@@ -487,6 +497,14 @@ sub cipherc
     }
     return $self->{cipherc};
 }
+sub ciphersuitesc
+{
+    my $self = shift;
+    if (@_) {
+        $self->{ciphersuitesc} = shift;
+    }
+    return $self->{ciphersuitesc};
+}
 sub ciphers
 {
     my $self = shift;
@@ -495,6 +513,14 @@ sub ciphers
     }
     return $self->{ciphers};
 }
+sub ciphersuitess
+{
+    my $self = shift;
+    if (@_) {
+        $self->{ciphersuitess} = shift;
+    }
+    return $self->{ciphersuitess};
+}
 sub serverflags
 {
     my $self = shift;


More information about the openssl-commits mailing list