[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Thu Mar 16 14:26:05 UTC 2017


The branch master has been updated
       via  635b7d3f2a3a4c1caaf772dc9a6c1cdcb958f6fe (commit)
       via  c35cb287cbda087cc203be86d74d35ea1b5eeac6 (commit)
       via  807551ac0dfe90c7953381df445205833ee7a1af (commit)
       via  69b2d39332e04d0745faed119eaad5e6a9033082 (commit)
       via  cf3e221bd90085035d869d3a233a03970d036638 (commit)
       via  11c67eeaf4dd0376d84a90590e307d5d2e12f025 (commit)
       via  9e0ac6a2f1237ab72f0f26a032199864c7b71f2e (commit)
       via  6594189fa16e845df5565ca4c180220783a752d4 (commit)
       via  ef6c191bceb7f09918cfd39e780759c32afb2396 (commit)
       via  bc993d30fcff70667618d83f5b58d99e119f4c23 (commit)
       via  3e0458fb12a9e663518cf99bad4d807adc8a0a28 (commit)
       via  e984b535d95f354e9df5dfe95d588db0d6dc2413 (commit)
      from  7baabf45c424c135ecfafc6b3bb7ea1d225fbfda (commit)


- Log -----------------------------------------------------------------
commit 635b7d3f2a3a4c1caaf772dc9a6c1cdcb958f6fe
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Mar 16 14:06:00 2017 +0000

    Updates following review feedback
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit c35cb287cbda087cc203be86d74d35ea1b5eeac6
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 15 20:35:23 2017 +0000

    Add some HRR tests
    
    Check that we handle changes of ciphersuite between HRR and ServerHello
    correctly.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit 807551ac0dfe90c7953381df445205833ee7a1af
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 15 18:44:05 2017 +0000

    Add some more PSK tests
    
    Test that if the server selects a ciphersuite with a different hash from
    the PSK in the original ClientHello, the second ClientHello does not
    contain the PSK.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit 69b2d39332e04d0745faed119eaad5e6a9033082
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 15 18:41:50 2017 +0000

    Fix ciphersuite handling during an HRR
    
    Choose a new ciphersuite for the HRR. Don't just use the one from the
    session.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit cf3e221bd90085035d869d3a233a03970d036638
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Mar 13 16:09:47 2017 +0000

    Ensure after an HRR any PSKs have the right hash
    
    Don't include a PSK that does not have the right hash for the selected
    ciphersuite following an HRR.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit 11c67eeaf4dd0376d84a90590e307d5d2e12f025
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Mar 13 15:21:15 2017 +0000

    HelloRetryRequest updates for draft-19
    
    Draft-19 changes the HRR transcript hash so that the initial ClientHello
    is replaced in the transcript with a special synthetic message_hash message
    that just contains a hash of ClientHello1 as its message body.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit 9e0ac6a2f1237ab72f0f26a032199864c7b71f2e
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Mar 9 22:58:05 2017 +0000

    Check ClientHello boundary as per draft-19
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit 6594189fa16e845df5565ca4c180220783a752d4
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Mar 9 15:31:55 2017 +0000

    Merge early_data_info extension into early_data
    
    As per draft-19
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit ef6c191bceb7f09918cfd39e780759c32afb2396
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Mar 9 15:03:07 2017 +0000

    Update end of early data processing for draft-19
    
    The end of early data is now indicated by a new handshake message rather
    than an alert.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit bc993d30fcff70667618d83f5b58d99e119f4c23
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 8 14:29:14 2017 +0000

    Update the TLSv1.3 secrets test vectors for draft-19
    
    These are self-generated test vectors which gives us very little
    confidence that we've got the implementation right. However until
    we can get vectors from somewhere else (or ideally official vectors)
    this is all we've got. At least it will tell us if we accidentally
    break something at some point in the future.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit 3e0458fb12a9e663518cf99bad4d807adc8a0a28
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 8 13:57:17 2017 +0000

    Update secret generation for draft-19
    
    TLSv1.3 draft 19 introduces a new pre HKDF-extract Derive-Secret stage.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

commit e984b535d95f354e9df5dfe95d588db0d6dc2413
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Mar 8 11:48:43 2017 +0000

    Update the TLSv1.3 version indicator for draft-19
    
    This change will mean we will lose interoperability with draft-18
    implementations.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2895)

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

Summary of changes:
 include/openssl/ssl.h              |  11 ++-
 include/openssl/ssl3.h             |   6 +-
 include/openssl/tls1.h             |   7 +-
 ssl/record/rec_layer_s3.c          |  41 ++-------
 ssl/record/ssl3_record_tls13.c     |   3 +-
 ssl/ssl_err.c                      |   9 ++
 ssl/ssl_lib.c                      |  62 +------------
 ssl/ssl_locl.h                     |   5 +-
 ssl/statem/extensions.c            |   9 +-
 ssl/statem/extensions_clnt.c       |  42 +++++----
 ssl/statem/extensions_srvr.c       |  33 +++----
 ssl/statem/statem.c                |  22 ++++-
 ssl/statem/statem.h                |   1 -
 ssl/statem/statem_clnt.c           | 181 ++++++++++++++++++++++++++++---------
 ssl/statem/statem_lib.c            |  42 ++++++++-
 ssl/statem/statem_locl.h           |  10 +-
 ssl/statem/statem_srvr.c           | 144 ++++++++++++++++++++++-------
 ssl/t1_trce.c                      |  34 +++++--
 ssl/tls13_enc.c                    |  26 +++++-
 test/recipes/70-test_tls13hrr.t    |  94 +++++++++++++++++++
 test/recipes/70-test_tls13psk.t    |  74 +++++++++++++--
 test/sslapitest.c                  |   9 --
 test/tls13secretstest.c            |  69 +++++++-------
 util/TLSProxy/HelloRetryRequest.pm |  15 +++
 util/TLSProxy/Message.pm           |   4 +-
 util/TLSProxy/Record.pm            |  16 ++--
 26 files changed, 671 insertions(+), 298 deletions(-)
 create mode 100644 test/recipes/70-test_tls13hrr.t

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 488ce4f..8003959 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -901,7 +901,9 @@ typedef enum {
     TLS_ST_SR_KEY_UPDATE,
     TLS_ST_CR_KEY_UPDATE,
     TLS_ST_EARLY_DATA,
-    TLS_ST_PENDING_EARLY_DATA_END
+    TLS_ST_PENDING_EARLY_DATA_END,
+    TLS_ST_CW_END_OF_EARLY_DATA,
+    TLS_ST_SR_END_OF_EARLY_DATA
 } OSSL_HANDSHAKE_STATE;
 
 /*
@@ -1027,7 +1029,6 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 # define SSL_AD_INTERNAL_ERROR           TLS1_AD_INTERNAL_ERROR
 # define SSL_AD_USER_CANCELLED           TLS1_AD_USER_CANCELLED
 # define SSL_AD_NO_RENEGOTIATION         TLS1_AD_NO_RENEGOTIATION
-# define SSL_AD_END_OF_EARLY_DATA        TLS13_AD_END_OF_EARLY_DATA
 # define SSL_AD_MISSING_EXTENSION        TLS13_AD_MISSING_EXTENSION
 # define SSL_AD_CERTIFICATE_REQUIRED     TLS13_AD_CERTIFICATE_REQUIRED
 # define SSL_AD_UNSUPPORTED_EXTENSION    TLS1_AD_UNSUPPORTED_EXTENSION
@@ -2134,6 +2135,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_CREATE_SYNTHETIC_MESSAGE_HASH              539
 # define SSL_F_CT_MOVE_SCTS                               345
 # define SSL_F_CT_STRICT                                  349
 # define SSL_F_D2I_SSL_SESSION                            103
@@ -2174,6 +2176,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION         418
 # define SSL_F_PROCESS_KEY_SHARE_EXT                      439
 # define SSL_F_READ_STATE_MACHINE                         352
+# define SSL_F_SET_CLIENT_CIPHERSUITE                     540
 # define SSL_F_SSL3_CHANGE_CIPHER_STATE                   129
 # define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM              130
 # define SSL_F_SSL3_CTRL                                  213
@@ -2373,6 +2376,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP                482
 # define SSL_F_TLS_CONSTRUCT_CTOS_VERIFY                  358
 # define SSL_F_TLS_CONSTRUCT_ENCRYPTED_EXTENSIONS         443
+# define SSL_F_TLS_CONSTRUCT_END_OF_EARLY_DATA            536
 # define SSL_F_TLS_CONSTRUCT_EXTENSIONS                   447
 # define SSL_F_TLS_CONSTRUCT_FINISHED                     359
 # define SSL_F_TLS_CONSTRUCT_HELLO_REQUEST                373
@@ -2411,6 +2415,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_PARSE_CTOS_RENEGOTIATE                 464
 # define SSL_F_TLS_PARSE_CTOS_USE_SRTP                    465
 # define SSL_F_TLS_PARSE_STOC_COOKIE                      534
+# define SSL_F_TLS_PARSE_STOC_EARLY_DATA                  538
 # define SSL_F_TLS_PARSE_STOC_EARLY_DATA_INFO             528
 # define SSL_F_TLS_PARSE_STOC_KEY_SHARE                   445
 # define SSL_F_TLS_PARSE_STOC_PSK                         502
@@ -2434,6 +2439,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_PROCESS_CLIENT_HELLO                   381
 # define SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE            382
 # define SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS           444
+# define SSL_F_TLS_PROCESS_END_OF_EARLY_DATA              537
 # define SSL_F_TLS_PROCESS_FINISHED                       364
 # define SSL_F_TLS_PROCESS_HELLO_REQ                      507
 # define SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST            511
@@ -2460,6 +2466,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE       143
 # define SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE     158
 # define SSL_R_BAD_CHANGE_CIPHER_SPEC                     103
+# define SSL_R_BAD_CIPHER                                 186
 # define SSL_R_BAD_DATA                                   390
 # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK              106
 # define SSL_R_BAD_DECOMPRESSION                          107
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 604a704..13de6b7 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -280,6 +280,7 @@ extern "C" {
 # define SSL3_MT_CLIENT_HELLO                    1
 # define SSL3_MT_SERVER_HELLO                    2
 # define SSL3_MT_NEWSESSION_TICKET               4
+# define SSL3_MT_END_OF_EARLY_DATA               5
 # define SSL3_MT_HELLO_RETRY_REQUEST             6
 # define SSL3_MT_ENCRYPTED_EXTENSIONS            8
 # define SSL3_MT_CERTIFICATE                     11
@@ -292,9 +293,10 @@ extern "C" {
 # define SSL3_MT_CERTIFICATE_STATUS              22
 # define SSL3_MT_KEY_UPDATE                      24
 # ifndef OPENSSL_NO_NEXTPROTONEG
-#  define SSL3_MT_NEXT_PROTO                      67
+#  define SSL3_MT_NEXT_PROTO                     67
 # endif
-# define DTLS1_MT_HELLO_VERIFY_REQUEST    3
+# define SSL3_MT_MESSAGE_HASH                    254
+# define DTLS1_MT_HELLO_VERIFY_REQUEST           3
 
 /* Dummy message type for handling CCS like a normal handshake message */
 # define SSL3_MT_CHANGE_CIPHER_SPEC              0x0101
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index cf06f72..f2af3ab 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -68,9 +68,9 @@ extern "C" {
 # define TLS1_3_VERSION                  0x0304
 # define TLS_MAX_VERSION                 TLS1_3_VERSION
 
-/* TODO(TLS1.3) REMOVE ME: Version indicator for draft -18 */
-# define TLS1_3_VERSION_DRAFT            0x7f12
-# define TLS1_3_VERSION_DRAFT_TXT        "TLS 1.3 (draft 18)"
+/* TODO(TLS1.3) REMOVE ME: Version indicator for draft -19 */
+# define TLS1_3_VERSION_DRAFT            0x7f13
+# define TLS1_3_VERSION_DRAFT_TXT        "TLS 1.3 (draft 19)"
 
 /* Special value for method supporting multiple versions */
 # define TLS_ANY_VERSION                 0x10000
@@ -184,7 +184,6 @@ extern "C" {
 # define TLSEXT_TYPE_supported_versions          43
 # define TLSEXT_TYPE_cookie                      44
 # define TLSEXT_TYPE_psk_kex_modes               45
-# define TLSEXT_TYPE_early_data_info             46
 
 /* Temporary extension type */
 # define TLSEXT_TYPE_renegotiate                 0xff01
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index a14d372..e8e9329 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -904,7 +904,8 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
         SSL3_RECORD_set_length(thiswr, len);
     }
 
-    if (s->early_data_state == SSL_EARLY_DATA_WRITING) {
+    if (s->early_data_state == SSL_EARLY_DATA_WRITING
+            || s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
         /*
          * We haven't actually negotiated the version yet, but we're trying to
          * send early data - so we need to use the the tls13enc function.
@@ -1367,17 +1368,16 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
                 n = SSL3_RECORD_get_length(rr); /* available bytes */
 
             /* now move 'n' bytes: */
-            while (n-- > 0) {
-                dest[(*dest_len)++] =
-                    SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)];
-                SSL3_RECORD_add_off(rr, 1);
-                SSL3_RECORD_add_length(rr, -1);
-            }
-
-            if (*dest_len < dest_maxlen) {
+            memcpy(dest + *dest_len,
+                   SSL3_RECORD_get_data(rr) + SSL3_RECORD_get_off(rr), n);
+            SSL3_RECORD_add_off(rr, n);
+            SSL3_RECORD_add_length(rr, -n);
+            *dest_len += n;
+            if (SSL3_RECORD_get_length(rr) == 0)
                 SSL3_RECORD_set_read(rr);
+
+            if (*dest_len < dest_maxlen)
                 goto start;     /* fragment was too small */
-            }
         }
     }
 
@@ -1454,14 +1454,6 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
                 al = SSL_AD_HANDSHAKE_FAILURE;
                 SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_NO_RENEGOTIATION);
                 goto f_err;
-            } else if (alert_descr == SSL_AD_END_OF_EARLY_DATA) {
-                if (!ssl_end_of_early_data_seen(s)) {
-                    al = SSL_AD_UNEXPECTED_MESSAGE;
-                    SSLerr(SSL_F_SSL3_READ_BYTES,
-                           SSL_R_UNEXPECTED_END_OF_EARLY_DATA);
-                    goto f_err;
-                }
-                return 0;
             }
         } else if (alert_level == SSL3_AL_FATAL) {
             char tmp[16];
@@ -1504,19 +1496,6 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
      */
     if ((s->rlayer.handshake_fragment_len >= 4)
             && !ossl_statem_get_in_handshake(s)) {
-        /*
-         * To get here we must be trying to read app data but found handshake
-         * data. But if we're trying to read app data, and we're not in init
-         * (which is tested for at the top of this function) then init must be
-         * finished
-         */
-        assert(SSL_is_init_finished(s));
-        if (!SSL_is_init_finished(s)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-
         /* We found handshake data, so we're going back into init */
         ossl_statem_set_in_init(s, 1);
 
diff --git a/ssl/record/ssl3_record_tls13.c b/ssl/record/ssl3_record_tls13.c
index 87041df..c6ea511 100644
--- a/ssl/record/ssl3_record_tls13.c
+++ b/ssl/record/ssl3_record_tls13.c
@@ -56,7 +56,8 @@ int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int send)
 
     ivlen = EVP_CIPHER_CTX_iv_length(ctx);
 
-    if (s->early_data_state == SSL_EARLY_DATA_WRITING) {
+    if (s->early_data_state == SSL_EARLY_DATA_WRITING
+            || s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
         alg_enc = s->session->cipher->algorithm_enc;
     } else {
         /*
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 23987e6..f7ee171 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -23,6 +23,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_ADD_KEY_SHARE), "add_key_share"},
     {ERR_FUNC(SSL_F_BYTES_TO_CIPHER_LIST), "bytes_to_cipher_list"},
     {ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "check_suiteb_cipher_list"},
+    {ERR_FUNC(SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH),
+     "create_synthetic_message_hash"},
     {ERR_FUNC(SSL_F_CT_MOVE_SCTS), "ct_move_scts"},
     {ERR_FUNC(SSL_F_CT_STRICT), "ct_strict"},
     {ERR_FUNC(SSL_F_D2I_SSL_SESSION), "d2i_SSL_SESSION"},
@@ -74,6 +76,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "ossl_statem_server_read_transition"},
     {ERR_FUNC(SSL_F_PROCESS_KEY_SHARE_EXT), "process_key_share_ext"},
     {ERR_FUNC(SSL_F_READ_STATE_MACHINE), "read_state_machine"},
+    {ERR_FUNC(SSL_F_SET_CLIENT_CIPHERSUITE), "set_client_ciphersuite"},
     {ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE), "ssl3_change_cipher_state"},
     {ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM),
      "ssl3_check_cert_and_algorithm"},
@@ -343,6 +346,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_VERIFY), "TLS_CONSTRUCT_CTOS_VERIFY"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_ENCRYPTED_EXTENSIONS),
      "tls_construct_encrypted_extensions"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_END_OF_EARLY_DATA),
+     "tls_construct_end_of_early_data"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_EXTENSIONS), "tls_construct_extensions"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_FINISHED), "tls_construct_finished"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST),
@@ -403,6 +408,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "tls_parse_ctos_renegotiate"},
     {ERR_FUNC(SSL_F_TLS_PARSE_CTOS_USE_SRTP), "tls_parse_ctos_use_srtp"},
     {ERR_FUNC(SSL_F_TLS_PARSE_STOC_COOKIE), "tls_parse_stoc_cookie"},
+    {ERR_FUNC(SSL_F_TLS_PARSE_STOC_EARLY_DATA), "tls_parse_stoc_early_data"},
     {ERR_FUNC(SSL_F_TLS_PARSE_STOC_EARLY_DATA_INFO),
      "tls_parse_stoc_early_data_info"},
     {ERR_FUNC(SSL_F_TLS_PARSE_STOC_KEY_SHARE), "tls_parse_stoc_key_share"},
@@ -438,6 +444,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "tls_process_client_key_exchange"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS),
      "tls_process_encrypted_extensions"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA),
+     "tls_process_end_of_early_data"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_FINISHED), "tls_process_finished"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_HELLO_REQ), "tls_process_hello_req"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST),
@@ -476,6 +484,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE),
      "at least (D)TLS 1.2 needed in Suite B mode"},
     {ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC), "bad change cipher spec"},
+    {ERR_REASON(SSL_R_BAD_CIPHER), "bad cipher"},
     {ERR_REASON(SSL_R_BAD_DATA), "bad data"},
     {ERR_REASON(SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),
      "bad data returned by callback"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 581941e..482c810 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -105,8 +105,6 @@ static const struct {
     },
 };
 
-static int ssl_write_early_finish(SSL *s);
-
 static int dane_ctx_enable(struct dane_ctx_st *dctx)
 {
     const EVP_MD **mdevp;
@@ -1641,9 +1639,9 @@ int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes)
             s->early_data_state = SSL_EARLY_DATA_READING;
             ret = SSL_read_ex(s, buf, num, readbytes);
             /*
-             * Record layer will call ssl_end_of_early_data_seen() if we see
-             * that alert - which updates the early_data_state to
-             * SSL_EARLY_DATA_FINISHED_READING
+             * State machine will update early_data_state to
+             * SSL_EARLY_DATA_FINISHED_READING if we get an EndOfEarlyData
+             * message
              */
             if (ret > 0 || (ret <= 0 && s->early_data_state
                                         != SSL_EARLY_DATA_FINISHED_READING)) {
@@ -1663,18 +1661,6 @@ int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes)
     }
 }
 
-int ssl_end_of_early_data_seen(SSL *s)
-{
-    if (s->early_data_state == SSL_EARLY_DATA_READING
-            || s->early_data_state == SSL_EARLY_DATA_READ_RETRY) {
-        s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
-        ossl_statem_finish_early_data(s);
-        return 1;
-    }
-
-    return 0;
-}
-
 int SSL_get_early_data_status(const SSL *s)
 {
     return s->ext.early_data;
@@ -1753,14 +1739,7 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
         return -1;
     }
 
-    if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
-        /*
-         * We're still writing early data. We need to stop that so we can write
-         * normal data
-         */
-        if (!ssl_write_early_finish(s))
-            return 0;
-    } else if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
+    if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
                 || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY
                 || s->early_data_state == SSL_EARLY_DATA_READ_RETRY) {
         SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
@@ -1863,32 +1842,6 @@ int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written)
     }
 }
 
-static int ssl_write_early_finish(SSL *s)
-{
-    int ret;
-
-    if (s->early_data_state != SSL_EARLY_DATA_WRITE_RETRY) {
-        SSLerr(SSL_F_SSL_WRITE_EARLY_FINISH, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
-        return 0;
-    }
-
-    s->early_data_state = SSL_EARLY_DATA_WRITING;
-    ret = ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_END_OF_EARLY_DATA);
-    if (ret <= 0) {
-        s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
-        return 0;
-    }
-    s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
-    /*
-     * We set the enc_write_ctx back to NULL because we may end up writing
-     * in cleartext again if we get a HelloRetryRequest from the server.
-     */
-    EVP_CIPHER_CTX_free(s->enc_write_ctx);
-    s->enc_write_ctx = NULL;
-    ossl_statem_set_in_init(s, 1);
-    return 1;
-}
-
 int SSL_shutdown(SSL *s)
 {
     /*
@@ -3252,13 +3205,6 @@ int SSL_do_handshake(SSL *s)
         return -1;
     }
 
-    if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
-        int edfin;
-
-        edfin = ssl_write_early_finish(s);
-        if (edfin <= 0)
-            return edfin;
-    }
     ossl_statem_check_finish_init(s, -1);
 
     s->method->ssl_renegotiate_check(s, 0);
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index f4860ea..9913548 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -350,7 +350,8 @@
                           && (s)->method->version != TLS_ANY_VERSION)
 
 # define SSL_TREAT_AS_TLS13(s) \
-    (SSL_IS_TLS13(s) || (s)->early_data_state == SSL_EARLY_DATA_WRITING)
+    (SSL_IS_TLS13(s) || (s)->early_data_state == SSL_EARLY_DATA_WRITING \
+     || (s)->early_data_state == SSL_EARLY_DATA_WRITE_RETRY)
 
 # define SSL_IS_FIRST_HANDSHAKE(S) ((s)->s3->tmp.finish_md_len == 0)
 
@@ -1790,7 +1791,6 @@ typedef enum tlsext_index_en {
     TLSEXT_IDX_renegotiate,
     TLSEXT_IDX_server_name,
     TLSEXT_IDX_srp,
-    TLSEXT_IDX_early_data_info,
     TLSEXT_IDX_ec_point_formats,
     TLSEXT_IDX_supported_groups,
     TLSEXT_IDX_session_ticket,
@@ -2030,7 +2030,6 @@ static ossl_inline int ssl_has_cert(const SSL *s, int idx)
 
 # ifndef OPENSSL_UNIT_TEST
 
-int ssl_end_of_early_data_seen(SSL *s);
 __owur int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes);
 __owur int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written);
 void ssl_clear_cipher_ctx(SSL *s);
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index 0ab1f04..f11f5e0 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -131,12 +131,6 @@ static const EXTENSION_DEFINITION ext_defs[] = {
 #else
     INVALID_EXTENSION,
 #endif
-    {
-        TLSEXT_TYPE_early_data_info,
-        EXT_TLS1_3_NEW_SESSION_TICKET,
-        NULL, NULL, tls_parse_stoc_early_data_info,
-        tls_construct_stoc_early_data_info, NULL, NULL
-    },
 #ifndef OPENSSL_NO_EC
     {
         TLSEXT_TYPE_ec_point_formats,
@@ -287,7 +281,8 @@ static const EXTENSION_DEFINITION ext_defs[] = {
     },
     {
         TLSEXT_TYPE_early_data,
-        EXT_CLIENT_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS,
+        EXT_CLIENT_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+        | EXT_TLS1_3_NEW_SESSION_TICKET,
         NULL, tls_parse_ctos_early_data, tls_parse_stoc_early_data,
         tls_construct_stoc_early_data, tls_construct_ctos_early_data,
         final_early_data
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index c6cd0ce..84bfb3c 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -769,6 +769,14 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
         return 1;
     }
 
+    if (s->hello_retry_request && md != ssl_handshake_md(s)) {
+        /*
+         * Selected ciphersuite hash does not match the hash for the session so
+         * we can't use it.
+         */
+        return 1;
+    }
+
     /*
      * Technically the C standard just says time() returns a time_t and says
      * nothing about the encoding of that type. In practice most implementations
@@ -931,24 +939,6 @@ int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
     return 1;
 }
 
-int tls_parse_stoc_early_data_info(SSL *s, PACKET *pkt, unsigned int context,
-                                   X509 *x, size_t chainidx, int *al)
-{
-    unsigned long max_early_data;
-
-    if (!PACKET_get_net_4(pkt, &max_early_data)
-            || PACKET_remaining(pkt) != 0) {
-        SSLerr(SSL_F_TLS_PARSE_STOC_EARLY_DATA_INFO,
-               SSL_R_INVALID_MAX_EARLY_DATA);
-        *al = SSL_AD_DECODE_ERROR;
-        return 0;
-    }
-
-    s->session->ext.max_early_data = max_early_data;
-
-    return 1;
-}
-
 #ifndef OPENSSL_NO_EC
 int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
                                  X509 *x, size_t chainidx, int *al)
@@ -1382,6 +1372,22 @@ int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
 int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
                               X509 *x, size_t chainidx, int *al)
 {
+    if (context == EXT_TLS1_3_NEW_SESSION_TICKET) {
+        unsigned long max_early_data;
+
+        if (!PACKET_get_net_4(pkt, &max_early_data)
+                || PACKET_remaining(pkt) != 0) {
+            SSLerr(SSL_F_TLS_PARSE_STOC_EARLY_DATA,
+                   SSL_R_INVALID_MAX_EARLY_DATA);
+            *al = SSL_AD_DECODE_ERROR;
+            return 0;
+        }
+
+        s->session->ext.max_early_data = max_early_data;
+
+        return 1;
+    }
+
     if (PACKET_remaining(pkt) != 0) {
         *al = SSL_AD_DECODE_ERROR;
         return 0;
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index ab3ad46..076a635 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -841,24 +841,6 @@ int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, unsigned int context,
     return 1;
 }
 
-int tls_construct_stoc_early_data_info(SSL *s, WPACKET *pkt,
-                                       unsigned int context, X509 *x,
-                                       size_t chainidx, int *al)
-{
-    if (s->max_early_data == 0)
-        return 1;
-
-    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data_info)
-            || !WPACKET_start_sub_packet_u16(pkt)
-            || !WPACKET_put_bytes_u32(pkt, s->max_early_data)
-            || !WPACKET_close(pkt)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA_INFO, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    return 1;
-}
-
 #ifndef OPENSSL_NO_EC
 int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
                                      X509 *x, size_t chainidx, int *al)
@@ -1151,6 +1133,21 @@ int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, unsigned int context,
 int tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, unsigned int context,
                                   X509 *x, size_t chainidx, int *al)
 {
+    if (context == EXT_TLS1_3_NEW_SESSION_TICKET) {
+        if (s->max_early_data == 0)
+            return 1;
+
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
+                || !WPACKET_start_sub_packet_u16(pkt)
+                || !WPACKET_put_bytes_u32(pkt, s->max_early_data)
+                || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+
+        return 1;
+    }
+
     if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED)
         return 1;
 
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
index 11cbe55..92a0e8f 100644
--- a/ssl/statem/statem.c
+++ b/ssl/statem/statem.c
@@ -180,13 +180,29 @@ void ossl_statem_check_finish_init(SSL *s, int send)
 {
     if (send == -1) {
         if (s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END
-                || s->statem.hand_state == TLS_ST_EARLY_DATA)
+                || s->statem.hand_state == TLS_ST_EARLY_DATA) {
             ossl_statem_set_in_init(s, 1);
+            if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
+                /*
+                 * SSL_connect() or SSL_do_handshake() has been called directly.
+                 * We don't allow any more writing of early data.
+                 */
+                s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+            }
+        }
     } else if (!s->server) {
-        if ((send && s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END
+        if ((send && (s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END
+                      || s->statem.hand_state == TLS_ST_EARLY_DATA)
                   && s->early_data_state != SSL_EARLY_DATA_WRITING)
-                || (!send && s->statem.hand_state == TLS_ST_EARLY_DATA))
+                || (!send && s->statem.hand_state == TLS_ST_EARLY_DATA)) {
             ossl_statem_set_in_init(s, 1);
+            /*
+             * SSL_write() has been called directly. We don't allow any more
+             * writing of early data.
+             */
+            if (send && s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY)
+                s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+        }
     } else {
         if (s->early_data_state == SSL_EARLY_DATA_FINISHED_READING
                 && s->statem.hand_state == TLS_ST_EARLY_DATA)
diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h
index 56009b0..7012115 100644
--- a/ssl/statem/statem.h
+++ b/ssl/statem/statem.h
@@ -130,4 +130,3 @@ __owur int ossl_statem_app_data_allowed(SSL *s);
 void ossl_statem_set_sctp_read_sock(SSL *s, int read_sock);
 __owur int ossl_statem_in_sctp_read_sock(SSL *s);
 #endif
-int ossl_statem_finish_early_data(SSL *s);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 9f4a719..d153afe 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -435,7 +435,8 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
         return WRITE_TRAN_CONTINUE;
 
     case TLS_ST_CR_FINISHED:
-        if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY)
+        if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY
+                || s->early_data_state == SSL_EARLY_DATA_FINISHED_WRITING)
             st->hand_state = TLS_ST_PENDING_EARLY_DATA_END;
         else
             st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
@@ -443,6 +444,13 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
         return WRITE_TRAN_CONTINUE;
 
     case TLS_ST_PENDING_EARLY_DATA_END:
+        if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+            st->hand_state = TLS_ST_CW_END_OF_EARLY_DATA;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Fall through */
+
+    case TLS_ST_CW_END_OF_EARLY_DATA:
         st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
                                                     : TLS_ST_CW_FINISHED;
         return WRITE_TRAN_CONTINUE;
@@ -666,8 +674,18 @@ WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst)
         }
         break;
 
-    case TLS_ST_EARLY_DATA:
     case TLS_ST_PENDING_EARLY_DATA_END:
+        /*
+         * If we've been called by SSL_do_handshake()/SSL_write(), or we did not
+         * attempt to write early data before calling SSL_read() then we press
+         * on with the handshake. Otherwise we pause here.
+         */
+        if (s->early_data_state == SSL_EARLY_DATA_FINISHED_WRITING
+                || s->early_data_state == SSL_EARLY_DATA_NONE)
+            return WORK_FINISHED_CONTINUE;
+        /* Fall through */
+
+    case TLS_ST_EARLY_DATA:
     case TLS_ST_OK:
         return tls_finish_handshake(s, wst, 1);
     }
@@ -712,6 +730,15 @@ WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst)
         }
         break;
 
+    case TLS_ST_CW_END_OF_EARLY_DATA:
+        /*
+         * We set the enc_write_ctx back to NULL because we may end up writing
+         * in cleartext again if we get a HelloRetryRequest from the server.
+         */
+        EVP_CIPHER_CTX_free(s->enc_write_ctx);
+        s->enc_write_ctx = NULL;
+        break;
+
     case TLS_ST_CW_KEY_EXCH:
         if (tls_client_key_exchange_post_work(s) == 0)
             return WORK_ERROR;
@@ -813,6 +840,16 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt,
         *mt = SSL3_MT_CLIENT_HELLO;
         break;
 
+    case TLS_ST_CW_END_OF_EARLY_DATA:
+        *confunc = tls_construct_end_of_early_data;
+        *mt = SSL3_MT_END_OF_EARLY_DATA;
+        break;
+
+    case TLS_ST_PENDING_EARLY_DATA_END:
+        *confunc = NULL;
+        *mt = SSL3_MT_DUMMY;
+        break;
+
     case TLS_ST_CW_CERT:
         *confunc = tls_construct_client_certificate;
         *mt = SSL3_MT_CERTIFICATE;
@@ -1206,14 +1243,65 @@ MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
     return MSG_PROCESS_ERROR;
 }
 
-MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
+static int set_client_ciphersuite(SSL *s, const unsigned char *cipherchars)
 {
     STACK_OF(SSL_CIPHER) *sk;
     const SSL_CIPHER *c;
+    int i;
+
+    c = ssl_get_cipher_by_char(s, cipherchars, 0);
+    if (c == NULL) {
+        /* unknown cipher */
+        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_UNKNOWN_CIPHER_RETURNED);
+        return 0;
+    }
+    /*
+     * If it is a disabled cipher we either didn't send it in client hello,
+     * or it's not allowed for the selected protocol. So we return an error.
+     */
+    if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) {
+        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED);
+        return 0;
+    }
+
+    sk = ssl_get_ciphers_by_id(s);
+    i = sk_SSL_CIPHER_find(sk, c);
+    if (i < 0) {
+        /* we did not say we would use this cipher */
+        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED);
+        return 0;
+    }
+
+    if (SSL_IS_TLS13(s) && s->s3->tmp.new_cipher != NULL
+            && s->s3->tmp.new_cipher->id != c->id) {
+        /* ServerHello selected a different ciphersuite to that in the HRR */
+        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED);
+        return 0;
+    }
+
+    /*
+     * Depending on the session caching (internal/external), the cipher
+     * and/or cipher_id values may not be set. Make sure that cipher_id is
+     * set and use it for comparison.
+     */
+    if (s->session->cipher != NULL)
+        s->session->cipher_id = s->session->cipher->id;
+    if (s->hit && (s->session->cipher_id != c->id)) {
+        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE,
+               SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+        return 0;
+    }
+    s->s3->tmp.new_cipher = c;
+
+    return 1;
+}
+
+MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
+{
     PACKET session_id, extpkt;
     size_t session_id_len;
     const unsigned char *cipherchars;
-    int i, al = SSL_AD_INTERNAL_ERROR;
+    int al = SSL_AD_INTERNAL_ERROR;
     unsigned int compression;
     unsigned int sversion;
     unsigned int context;
@@ -1400,54 +1488,18 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
                SSL_R_SSL_SESSION_VERSION_MISMATCH);
         goto f_err;
     }
-
-    c = ssl_get_cipher_by_char(s, cipherchars, 0);
-    if (c == NULL) {
-        /* unknown cipher */
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED);
-        goto f_err;
-    }
     /*
      * Now that we know the version, update the check to see if it's an allowed
      * version.
      */
     s->s3->tmp.min_ver = s->version;
     s->s3->tmp.max_ver = s->version;
-    /*
-     * If it is a disabled cipher we either didn't send it in client hello,
-     * or it's not allowed for the selected protocol. So we return an error.
-     */
-    if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
-        goto f_err;
-    }
 
-    sk = ssl_get_ciphers_by_id(s);
-    i = sk_SSL_CIPHER_find(sk, c);
-    if (i < 0) {
-        /* we did not say we would use this cipher */
+    if (!set_client_ciphersuite(s, cipherchars)) {
         al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
         goto f_err;
     }
 
-    /*
-     * Depending on the session caching (internal/external), the cipher
-     * and/or cipher_id values may not be set. Make sure that cipher_id is
-     * set and use it for comparison.
-     */
-    if (s->session->cipher)
-        s->session->cipher_id = s->session->cipher->id;
-    if (s->hit && (s->session->cipher_id != c->id)) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-               SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
-        goto f_err;
-    }
-    s->s3->tmp.new_cipher = c;
-
 #ifdef OPENSSL_NO_COMP
     if (compression != 0) {
         al = SSL_AD_ILLEGAL_PARAMETER;
@@ -1543,6 +1595,7 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
 {
     unsigned int sversion;
     int errorcode;
+    const unsigned char *cipherchars;
     RAW_EXTENSION *extensions = NULL;
     int al;
     PACKET extpkt;
@@ -1563,6 +1616,17 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
+    if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
+        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_LENGTH_MISMATCH);
+        al = SSL_AD_DECODE_ERROR;
+        goto f_err;
+    }
+
+    if (!set_client_ciphersuite(s, cipherchars)) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        goto f_err;
+    }
+
     if (!PACKET_as_length_prefixed_2(pkt, &extpkt)) {
         al = SSL_AD_DECODE_ERROR;
         SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_BAD_LENGTH);
@@ -1577,6 +1641,28 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
 
     OPENSSL_free(extensions);
 
+    /*
+     * Re-initialise the Transcript Hash. We're going to prepopulate it with
+     * a synthetic message_hash in place of ClientHello1.
+     */
+    if (!create_synthetic_message_hash(s)) {
+        al = SSL_AD_INTERNAL_ERROR;
+        goto f_err;
+    }
+
+    /*
+     * Add this message to the Transcript Hash. Normally this is done
+     * automatically prior to the message processing stage. However due to the
+     * need to create the synthetic message hash, we defer that step until now
+     * for HRR messages.
+     */
+    if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+                                s->init_num + SSL3_HM_HEADER_LENGTH)) {
+        al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, ERR_R_INTERNAL_ERROR);
+        goto f_err;
+    }
+
     return MSG_PROCESS_FINISHED_READING;
  f_err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
@@ -3543,3 +3629,16 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, WPACKET *pkt)
 
     return 1;
 }
+
+int tls_construct_end_of_early_data(SSL *s, WPACKET *pkt)
+{
+    if (s->early_data_state != SSL_EARLY_DATA_WRITE_RETRY
+            && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_END_OF_EARLY_DATA,
+               ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return 0;
+    }
+
+    s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+    return 1;
+}
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 36c96e5..5164cc0 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -986,7 +986,6 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs)
             s->d1->next_handshake_write_seq = 0;
             dtls1_clear_received_buffer(s);
         }
-        s->early_data_state = SSL_EARLY_DATA_NONE;
     }
 
     /*
@@ -1150,8 +1149,13 @@ int tls_get_message_body(SSL *s, size_t *len)
             s->msg_callback(0, SSL2_VERSION, 0, s->init_buf->data,
                             (size_t)s->init_num, s, s->msg_callback_arg);
     } else {
-        if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
-                             s->init_num + SSL3_HM_HEADER_LENGTH)) {
+        /*
+         * We defer feeding in the HRR until later. We'll do it as part of
+         * processing the message
+         */
+        if (s->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST
+                && !ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+                                    s->init_num + SSL3_HM_HEADER_LENGTH)) {
             SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_EVP_LIB);
             ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
             *len = 0;
@@ -1871,3 +1875,35 @@ int check_in_list(SSL *s, unsigned int group_id, const unsigned char *groups,
     return i < num_groups;
 }
 #endif
+
+/* Replace ClientHello1 in the transcript hash with a synthetic message */
+int create_synthetic_message_hash(SSL *s)
+{
+    unsigned char hashval[EVP_MAX_MD_SIZE];
+    size_t hashlen = 0;
+    unsigned char msghdr[SSL3_HM_HEADER_LENGTH];
+
+    memset(msghdr, 0, sizeof(msghdr));
+
+    /* Get the hash of the initial ClientHello */
+    if (!ssl3_digest_cached_records(s, 0)
+            || !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) {
+        SSLerr(SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* Reinitialise the transcript hash */
+    if (!ssl3_init_finished_mac(s))
+        return 0;
+
+    /* Inject the synthetic message_hash message */
+    msghdr[0] = SSL3_MT_MESSAGE_HASH;
+    msghdr[SSL3_HM_HEADER_LENGTH - 1] = hashlen;
+    if (!ssl3_finish_mac(s, msghdr, SSL3_HM_HEADER_LENGTH)
+            || !ssl3_finish_mac(s, hashval, hashlen)) {
+        SSLerr(SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index 68160c9..1c78a4d 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -18,6 +18,7 @@
 
 /* The spec allows for a longer length than this, but we limit it */
 #define HELLO_VERIFY_REQUEST_MAX_LENGTH 258
+#define END_OF_EARLY_DATA_MAX_LENGTH    0
 #define SERVER_HELLO_MAX_LENGTH         20000
 #define HELLO_RETRY_REQUEST_MAX_LENGTH  20000
 #define ENCRYPTED_EXTENSIONS_MAX_LENGTH 20000
@@ -78,7 +79,7 @@ typedef int (*confunc_f) (SSL *s, WPACKET *pkt);
 
 int check_in_list(SSL *s, unsigned int group_id, const unsigned char *groups,
                   size_t num_groups, int checkallow);
-
+int create_synthetic_message_hash(SSL *s);
 /*
  * TLS/DTLS client state machine functions
  */
@@ -147,6 +148,7 @@ __owur int tls_construct_next_proto(SSL *s, WPACKET *pkt);
 #endif
 __owur MSG_PROCESS_RETURN tls_process_hello_req(SSL *s, PACKET *pkt);
 __owur MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt);
+__owur int tls_construct_end_of_early_data(SSL *s, WPACKET *pkt);
 
 /* some server-only functions */
 __owur MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt);
@@ -165,6 +167,7 @@ __owur MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt);
 __owur MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt);
 #endif
 __owur int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt);
+MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt);
 
 
 /* Extension processing */
@@ -235,9 +238,6 @@ int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
                                    X509 *x, size_t chainidx, int *al);
 int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, unsigned int context,
                                    X509 *x, size_t chainidx, int *al);
-int tls_construct_stoc_early_data_info(SSL *s, WPACKET *pkt,
-                                       unsigned int context, X509 *x,
-                                       size_t chainidx, int *al);
 int tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, unsigned int context,
                                   X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_EC
@@ -342,8 +342,6 @@ int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
                                X509 *x, size_t chainidx, int *al);
 int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, unsigned int context,
                                X509 *x, size_t chainidx, int *al);
-int tls_parse_stoc_early_data_info(SSL *s, PACKET *pkt, unsigned int context,
-                              X509 *x, size_t chainidx, int *al);
 int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
                               X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_EC
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 2e381fd..78f977f 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -94,6 +94,16 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
         break;
 
     case TLS_ST_EARLY_DATA:
+        if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+            if (mt == SSL3_MT_END_OF_EARLY_DATA) {
+                st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA;
+                return 1;
+            }
+            break;
+        }
+        /* Fall through */
+
+    case TLS_ST_SR_END_OF_EARLY_DATA:
     case TLS_ST_SW_FINISHED:
         if (s->s3->tmp.cert_request) {
             if (mt == SSL3_MT_CERTIFICATE) {
@@ -144,9 +154,6 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
     }
 
     /* No valid transition found */
-    ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
-    SSLerr(SSL_F_OSSL_STATEM_SERVER13_READ_TRANSITION,
-           SSL_R_UNEXPECTED_MESSAGE);
     return 0;
 }
 
@@ -1009,6 +1016,9 @@ size_t ossl_statem_server_max_message_size(SSL *s)
     case TLS_ST_SR_CLNT_HELLO:
         return CLIENT_HELLO_MAX_LENGTH;
 
+    case TLS_ST_SR_END_OF_EARLY_DATA:
+        return END_OF_EARLY_DATA_MAX_LENGTH;
+
     case TLS_ST_SR_CERT:
         return s->max_cert_list;
 
@@ -1049,6 +1059,9 @@ MSG_PROCESS_RETURN ossl_statem_server_process_message(SSL *s, PACKET *pkt)
     case TLS_ST_SR_CLNT_HELLO:
         return tls_process_client_hello(s, pkt);
 
+    case TLS_ST_SR_END_OF_EARLY_DATA:
+        return tls_process_end_of_early_data(s, pkt);
+
     case TLS_ST_SR_CERT:
         return tls_process_client_certificate(s, pkt);
 
@@ -1115,15 +1128,6 @@ WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst)
     return WORK_FINISHED_CONTINUE;
 }
 
-int ossl_statem_finish_early_data(SSL *s)
-{
-    if (!s->method->ssl3_enc->change_cipher_state(s,
-                SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ))
-        return 0;
-
-    return 1;
-}
-
 #ifndef OPENSSL_NO_SRP
 static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
 {
@@ -1530,6 +1534,14 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
         goto err;
     }
 
+    /* TLSv1.3 specifies that a ClientHello must end on a record boundary */
+    if (SSL_IS_TLS13(s) && RECORD_LAYER_processed_read_pending(&s->rlayer)) {
+        *al = SSL_AD_UNEXPECTED_MESSAGE;
+        SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
+               SSL_R_NOT_ON_RECORD_BOUNDARY);
+        goto err;
+    }
+
     if (SSL_IS_DTLS(s)) {
         /* Empty cookie was already handled above by returning early. */
         if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
@@ -1837,12 +1849,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
      * Given s->session->ciphers and SSL_get_ciphers, we must pick a cipher
      */
 
-    if (!s->hit) {
-#ifdef OPENSSL_NO_COMP
-        s->session->compress_meth = 0;
-#else
-        s->session->compress_meth = (comp == NULL) ? 0 : comp->id;
-#endif
+    if (!s->hit || s->hello_retry_request) {
         sk_SSL_CIPHER_free(s->session->ciphers);
         s->session->ciphers = ciphers;
         if (ciphers == NULL) {
@@ -1851,6 +1858,14 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
             goto err;
         }
         ciphers = NULL;
+    }
+
+    if (!s->hit) {
+#ifdef OPENSSL_NO_COMP
+        s->session->compress_meth = 0;
+#else
+        s->session->compress_meth = (comp == NULL) ? 0 : comp->id;
+#endif
         if (!tls1_set_server_sigalgs(s)) {
             SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
             goto err;
@@ -1939,7 +1954,7 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
         wst = WORK_MORE_B;
     }
     if (wst == WORK_MORE_B) {
-        if (!s->hit) {
+        if (!s->hit || s->hello_retry_request) {
             /* Let cert callback update server certificates if required */
             if (s->cert->cert_cb) {
                 int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
@@ -1963,18 +1978,30 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
                        SSL_R_NO_SHARED_CIPHER);
                 goto f_err;
             }
-            s->s3->tmp.new_cipher = cipher;
-            if (!tls_choose_sigalg(s, &al))
+            if (SSL_IS_TLS13(s) && s->s3->tmp.new_cipher != NULL
+                    && s->s3->tmp.new_cipher->id != cipher->id) {
+                /*
+                 * A previous HRR picked a different ciphersuite to the one we
+                 * just selected. Something must have changed.
+                 */
+                al = SSL_AD_ILLEGAL_PARAMETER;
+                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_BAD_CIPHER);
                 goto f_err;
-            /* check whether we should disable session resumption */
-            if (s->not_resumable_session_cb != NULL)
-                s->session->not_resumable =
-                    s->not_resumable_session_cb(s, ((cipher->algorithm_mkey
-                                                    & (SSL_kDHE | SSL_kECDHE))
-                                                   != 0));
-            if (s->session->not_resumable)
-                /* do not send a session ticket */
-                s->ext.ticket_expected = 0;
+            }
+            s->s3->tmp.new_cipher = cipher;
+            if (!s->hit) {
+                if (!tls_choose_sigalg(s, &al))
+                    goto f_err;
+                /* check whether we should disable session resumption */
+                if (s->not_resumable_session_cb != NULL)
+                    s->session->not_resumable =
+                        s->not_resumable_session_cb(s, ((cipher->algorithm_mkey
+                                                        & (SSL_kDHE | SSL_kECDHE))
+                                                       != 0));
+                if (s->session->not_resumable)
+                    /* do not send a session ticket */
+                    s->ext.ticket_expected = 0;
+            }
         } else {
             /* Session-id reuse */
             s->s3->tmp.new_cipher = s->session->cipher;
@@ -3650,17 +3677,18 @@ static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt)
 static int tls_construct_hello_retry_request(SSL *s, WPACKET *pkt)
 {
     int al = SSL_AD_INTERNAL_ERROR;
+    size_t len = 0;
 
     /*
      * TODO(TLS1.3): Remove the DRAFT version before release
      * (should be s->version)
      */
     if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)
+            || !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt, &len)
             || !tls_construct_extensions(s, pkt, EXT_TLS1_3_HELLO_RETRY_REQUEST,
                                          NULL, 0, &al)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_HELLO_RETRY_REQUEST, ERR_R_INTERNAL_ERROR);
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        return 0;
+        goto err;
     }
 
     /* Ditch the session. We'll create a new one next time around */
@@ -3668,5 +3696,57 @@ static int tls_construct_hello_retry_request(SSL *s, WPACKET *pkt)
     s->session = NULL;
     s->hit = 0;
 
+    /*
+     * Re-initialise the Transcript Hash. We're going to prepopulate it with
+     * a synthetic message_hash in place of ClientHello1.
+     */
+    if (!create_synthetic_message_hash(s))
+        goto err;
+
     return 1;
+ err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    return 0;
+}
+
+MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt)
+{
+    int al = SSL_AD_INTERNAL_ERROR;
+
+    if (PACKET_remaining(pkt) != 0) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA, SSL_R_LENGTH_MISMATCH);
+        ossl_statem_set_error(s);
+        return MSG_PROCESS_ERROR;
+    }
+
+    if (s->early_data_state != SSL_EARLY_DATA_READING
+            && s->early_data_state != SSL_EARLY_DATA_READ_RETRY) {
+        SSLerr(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /*
+     * EndOfEarlyData signals a key change so the end of the message must be on
+     * a record boundary.
+     */
+    if (RECORD_LAYER_processed_read_pending(&s->rlayer)) {
+        al = SSL_AD_UNEXPECTED_MESSAGE;
+        SSLerr(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA,
+               SSL_R_NOT_ON_RECORD_BOUNDARY);
+        goto err;
+    }
+
+    s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+    if (!s->method->ssl3_enc->change_cipher_state(s,
+                SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ)) {
+        SSLerr(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    return MSG_PROCESS_CONTINUE_READING;
+ err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    ossl_statem_set_error(s);
+    return MSG_PROCESS_ERROR;
 }
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index 5cfaacd..0632066 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -476,7 +476,6 @@ static ssl_trace_tbl ssl_exts_tbl[] = {
     {TLSEXT_TYPE_padding, "padding"},
     {TLSEXT_TYPE_encrypt_then_mac, "encrypt_then_mac"},
     {TLSEXT_TYPE_extended_master_secret, "extended_master_secret"},
-    {TLSEXT_TYPE_early_data_info, "ticket_early_data_info"},
     {TLSEXT_TYPE_early_data, "early_data"}
 };
 
@@ -833,7 +832,9 @@ static int ssl_print_extension(BIO *bio, int indent, int server,
         return ssl_trace_list(bio, indent + 2, ext + 1, xlen, 1,
                               ssl_psk_kex_modes_tbl);
 
-    case TLSEXT_TYPE_early_data_info:
+    case TLSEXT_TYPE_early_data:
+        if (mt != SSL3_MT_NEWSESSION_TICKET)
+            break;
         if (extlen != 4)
             return 0;
         max_early_data = (ext[0] << 24) | (ext[1] << 16) | (ext[2] << 8)
@@ -991,6 +992,29 @@ static int ssl_print_server_hello(BIO *bio, int indent,
     return 1;
 }
 
+static int ssl_print_hello_retry_request(BIO *bio, int indent,
+                                         const unsigned char *msg,
+                                         size_t msglen)
+{
+    unsigned int cs;
+
+    if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen, NULL))
+        return 0;
+
+    cs = (msg[0] << 8) | msg[1];
+    BIO_indent(bio, indent, 80);
+    BIO_printf(bio, "cipher_suite {0x%02X, 0x%02X} %s\n",
+               msg[0], msg[1], ssl_trace_str(cs, ssl_ciphers_tbl));
+    msg += 2;
+    msglen -= 2;
+
+    if (!ssl_print_extensions(bio, indent, 1, SSL3_MT_HELLO_RETRY_REQUEST, &msg,
+                              &msglen))
+        return 0;
+
+    return 1;
+}
+
 static int ssl_get_keyex(const char **pname, SSL *ssl)
 {
     unsigned long alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey;
@@ -1421,11 +1445,7 @@ static int ssl_print_handshake(BIO *bio, SSL *ssl, int server,
         break;
 
     case SSL3_MT_HELLO_RETRY_REQUEST:
-        if (!ssl_print_version(bio, indent + 2, "server_version", &msg, &msglen,
-                               NULL)
-                || !ssl_print_extensions(bio, indent + 2, 1,
-                                         SSL3_MT_HELLO_RETRY_REQUEST, &msg,
-                                         &msglen))
+        if (!ssl_print_hello_retry_request(bio, indent + 2, msg, msglen))
             return 0;
         break;
 
diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
index 9fdd61e..9103362 100644
--- a/ssl/tls13_enc.c
+++ b/ssl/tls13_enc.c
@@ -124,6 +124,8 @@ int tls13_generate_secret(SSL *s, const EVP_MD *md,
     size_t mdlen, prevsecretlen;
     int ret;
     EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+    const char *derived_secret_label = "derived secret";
+    unsigned char preextractsec[EVP_MAX_MD_SIZE];
 
     if (pctx == NULL)
         return 0;
@@ -138,6 +140,26 @@ int tls13_generate_secret(SSL *s, const EVP_MD *md,
         prevsecret = default_zeros;
         prevsecretlen = 0;
     } else {
+        EVP_MD_CTX *mctx = EVP_MD_CTX_new();
+        unsigned char hash[EVP_MAX_MD_SIZE];
+
+        /* The pre-extract derive step uses a hash of no messages */
+        if (mctx == NULL
+                || EVP_DigestInit_ex(mctx, md, NULL) <= 0
+                || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
+            EVP_MD_CTX_free(mctx);
+            return 0;
+        }
+        EVP_MD_CTX_free(mctx);
+
+        /* Generate the pre-extract secret */
+        if (!tls13_hkdf_expand(s, md, prevsecret,
+                               (unsigned char *)derived_secret_label,
+                               sizeof(derived_secret_label) - 1, hash,
+                               preextractsec, mdlen))
+            return 0;
+
+        prevsecret = preextractsec;
         prevsecretlen = mdlen;
     }
 
@@ -152,6 +174,8 @@ int tls13_generate_secret(SSL *s, const EVP_MD *md,
                <= 0;
 
     EVP_PKEY_CTX_free(pctx);
+    if (prevsecret == preextractsec)
+        OPENSSL_cleanse(preextractsec, mdlen);
     return ret == 0;
 }
 
@@ -576,7 +600,7 @@ int tls13_update_key(SSL *s, int send)
 
 int tls13_alert_code(int code)
 {
-    if (code == SSL_AD_MISSING_EXTENSION || code == SSL_AD_END_OF_EARLY_DATA)
+    if (code == SSL_AD_MISSING_EXTENSION)
         return code;
 
     return tls1_alert_code(code);
diff --git a/test/recipes/70-test_tls13hrr.t b/test/recipes/70-test_tls13hrr.t
new file mode 100644
index 0000000..8130119
--- /dev/null
+++ b/test/recipes/70-test_tls13hrr.t
@@ -0,0 +1,94 @@
+#! /usr/bin/env perl
+# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
+use OpenSSL::Test::Utils;
+use TLSProxy::Proxy;
+
+my $test_name = "test_tls13hrr";
+setup($test_name);
+
+plan skip_all => "TLSProxy isn't usable on $^O"
+    if $^O =~ /^(VMS|MSWin32)$/;
+
+plan skip_all => "$test_name needs the dynamic engine feature enabled"
+    if disabled("engine") || disabled("dynamic-engine");
+
+plan skip_all => "$test_name needs the sock feature enabled"
+    if disabled("sock");
+
+plan skip_all => "$test_name needs TLS1.3 enabled"
+    if disabled("tls1_3");
+
+$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
+
+my $proxy = TLSProxy::Proxy->new(
+    undef,
+    cmdstr(app(["openssl"]), display => 1),
+    srctop_file("apps", "server.pem"),
+    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
+);
+
+use constant {
+    CHANGE_HRR_CIPHERSUITE => 0,
+    CHANGE_CH1_CIPHERSUITE => 1
+};
+
+#Test 1: A client should fail if the server changes the ciphersuite between the
+#        HRR and the SH
+$proxy->filter(\&hrr_filter);
+$proxy->serverflags("-curves P-256");
+my $testtype = CHANGE_HRR_CIPHERSUITE;
+$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
+plan tests => 2;
+ok(TLSProxy::Message->fail(), "Server ciphersuite changes");
+
+#Test 2: It is an error if the client changes the offered ciphersuites so that
+#        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");
+$testtype = CHANGE_CH1_CIPHERSUITE;
+$proxy->start();
+ok(TLSProxy::Message->fail(), "Client ciphersuite changes");
+
+sub hrr_filter
+{
+    my $proxy = shift;
+
+    if ($testtype == CHANGE_HRR_CIPHERSUITE) {
+        # We're only interested in the HRR
+        if ($proxy->flight != 1) {
+            return;
+        }
+
+        my $hrr = ${$proxy->message_list}[1];
+
+        # We will normally only ever select CIPHER_TLS13_AES_128_GCM_SHA256
+        # because that's what Proxy tells s_server to do. Setting as below means
+        # the ciphersuite will change will we get the ServerHello
+        $hrr->ciphersuite(TLSProxy::Message::CIPHER_TLS13_AES_256_GCM_SHA384);
+        $hrr->repack();
+        return;
+    }
+
+    # CHANGE_CH1_CIPHERSUITE
+    if ($proxy->flight != 0) {
+        return;
+    }
+
+    my $ch1 = ${$proxy->message_list}[0];
+
+    # The server prefers TLS13-AES-256-GCM-SHA384 so it will pick that next
+    # time around
+    my @ciphersuites = (TLSProxy::Message::CIPHER_TLS13_AES_128_GCM_SHA256);
+    $ch1->ciphersuite_len(2 * scalar @ciphersuites);
+    $ch1->ciphersuites(\@ciphersuites);
+    $ch1->repack();
+}
diff --git a/test/recipes/70-test_tls13psk.t b/test/recipes/70-test_tls13psk.t
index 2607d51..48d1dde 100644
--- a/test/recipes/70-test_tls13psk.t
+++ b/test/recipes/70-test_tls13psk.t
@@ -37,6 +37,11 @@ my $proxy = TLSProxy::Proxy->new(
     (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
 );
 
+use constant {
+    PSK_LAST_FIRST_CH => 0,
+    ILLEGAL_EXT_SECOND_CH => 1
+};
+
 #Most PSK tests are done in test_ssl_new. This just checks sending a PSK
 #extension when it isn't in the last place in a ClientHello
 
@@ -45,29 +50,82 @@ my $proxy = TLSProxy::Proxy->new(
 $proxy->clientflags("-sess_out ".$session);
 $proxy->sessionfile($session);
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 2;
+plan tests => 4;
 ok(TLSProxy::Message->success(), "Initial connection");
 
 #Test 2: Attempt a resume with PSK not in last place. Should fail
 $proxy->clear();
 $proxy->clientflags("-sess_in ".$session);
 $proxy->filter(\&modify_psk_filter);
+my $testtype = PSK_LAST_FIRST_CH;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "PSK not last");
 
+#Test 3: Attempt a resume after an HRR where PSK hash matches selected
+#        ciperhsuite. Should see PSK on second ClientHello
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+$proxy->serverflags("-curves P-256");
+$proxy->filter(undef);
+$proxy->start();
+#Check if the PSK is present in the second ClientHello
+my $ch2 = ${$proxy->message_list}[2];
+my $ch2seen = defined $ch2 && $ch2->mt() == TLSProxy::Message::MT_CLIENT_HELLO;
+my $pskseen = $ch2seen
+              && defined ${$ch2->{extension_data}}{TLSProxy::Message::EXT_PSK};
+ok($pskseen, "PSK hash matches");
+
+#Test 4: Attempt a resume after an HRR where PSK hash does not match selected
+#        ciphersuite. Should not see PSK on second ClientHello
+$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");
+#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.
+$testtype = ILLEGAL_EXT_SECOND_CH;
+$proxy->start();
+#Check if the PSK is present in the second ClientHello
+$ch2 = ${$proxy->message_list}[2];
+$ch2seen = defined $ch2 && $ch2->mt() == TLSProxy::Message::MT_CLIENT_HELLO;
+$pskseen = $ch2seen
+           && defined ${$ch2->extension_data}{TLSProxy::Message::EXT_PSK};
+ok($ch2seen && !$pskseen, "PSK hash does not match");
+
+
 unlink $session;
 
 sub modify_psk_filter
 {
     my $proxy = shift;
+    my $flight;
+    my $message;
+
+    if ($testtype == PSK_LAST_FIRST_CH) {
+        $flight = 0;
+    } else {
+        $flight = 2;
+    }
+
+    # Only look at the first or second ClientHello
+    return if $proxy->flight != $flight;
+
+    if ($testtype == PSK_LAST_FIRST_CH) {
+        $message = ${$proxy->message_list}[0];
+    } else {
+        $message = ${$proxy->message_list}[2];
+    }
 
-    # We're only interested in the initial ClientHello
-    return if ($proxy->flight != 0);
+    return if (!defined $message
+               || $message->mt != TLSProxy::Message::MT_CLIENT_HELLO);
 
-    foreach my $message (@{$proxy->message_list}) {
-        if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO) {
-            $message->set_extension(TLSProxy::Message::EXT_FORCE_LAST, "");
-            $message->repack();
-        }
+    if ($testtype == PSK_LAST_FIRST_CH) {
+        $message->set_extension(TLSProxy::Message::EXT_FORCE_LAST, "");
+    } else {
+        #Deliberately break the connection
+        $message->set_extension(TLSProxy::Message::EXT_SUPPORTED_GROUPS, "");
     }
+    $message->repack();
 }
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 1b96527..85fcabc 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -1764,15 +1764,6 @@ static int test_early_data_read_write(void)
         goto end;
     }
 
-    /*
-     * We expect SSL_accept() to initially block as it handles the end of early
-     * data alert
-     */
-    if (SSL_accept(serverssl) > 0) {
-        printf("Unexpected success completing server handshake\n");
-        goto end;
-    }
-
     if (SSL_accept(serverssl) <= 0) {
         printf("Unable to complete server handshake\n");
         goto end;
diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c
index 55424b1..240fa2d 100644
--- a/test/tls13secretstest.c
+++ b/test/tls13secretstest.c
@@ -17,13 +17,15 @@
 #define IVLEN   12
 #define KEYLEN  16
 
-/* The following are unofficial test vectors generated from a locally modified
- * version of picotls.
+/* The following are self-generated test vectors. This gives us very little
+ * confidence that we've got the implementation right, but at least tells us
+ * if we accidentally  break something in the future. Until we can get some
+ * other source of test vectors this is all we've got.
  * TODO(TLS1.3): As and when official vectors become available we should use
  * those, e.g. see
  * https://www.ietf.org/id/draft-thomson-tls-tls13-vectors-00.txt, however at
  * the time of writing these are not suitable because they are based on
- * draft -16, which works slightly differently to the draft -18 vectors below.
+ * draft -16, which works differently to the draft -19 vectors below.
  */
 
 static unsigned char hs_start_hash[] = {
@@ -51,84 +53,83 @@ static unsigned char ecdhe_secret[] = {
 };
 
 static unsigned char handshake_secret[] = {
-0xdf, 0xc9, 0x41, 0xd8, 0x26, 0x93, 0x2a, 0x59, 0x11, 0xb3, 0xb7, 0xd0, 0x38,
-0xcb, 0x65, 0x6f, 0xda, 0xaf, 0x77, 0x07, 0x1e, 0x40, 0x9a, 0x9b, 0xa6, 0xca,
-0x74, 0xda, 0x17, 0xb4, 0xe0, 0x04,
+0xed, 0x80, 0x0a, 0x28, 0x28, 0xf6, 0x3b, 0x45, 0x6b, 0x26, 0xf6, 0x5c, 0x5e,
+0x2e, 0x30, 0x57, 0xc8, 0x02, 0xe2, 0x03, 0x5c, 0xf6, 0xf2, 0xd7, 0x1b, 0x95,
+0x45, 0x5f, 0xb0, 0x76, 0x23, 0x4e
 };
 
 static const char *client_hts_label = "client handshake traffic secret";
 
 static unsigned char client_hts[] = {
-0x4b, 0x38, 0x48, 0xf1, 0x5d, 0xb1, 0x5e, 0x88, 0xcf, 0x3e, 0x3b, 0xff, 0xa6,
-0xba, 0x02, 0xc1, 0xc5, 0xd1, 0xe5, 0xb1, 0xc3, 0xf3, 0x10, 0xdf, 0xe5, 0xc9,
-0x69, 0x5a, 0x4a, 0xc6, 0x06, 0x38,
+0x39, 0x58, 0x9d, 0x3f, 0xaf, 0x5f, 0xc0, 0xc2, 0xa3, 0x56, 0x94, 0x4f, 0x0a,
+0x08, 0x63, 0x84, 0xbc, 0xec, 0xcf, 0x2c, 0x25, 0x2f, 0xce, 0xfe, 0x0c, 0x57,
+0xb3, 0xca, 0x21, 0xc4, 0x37, 0x73
 };
 
 static unsigned char client_hts_key[] = {
-0xe5, 0x7b, 0x8c, 0x38, 0x6d, 0x6f, 0x09, 0x14, 0xe2, 0xe5, 0x4e, 0x36, 0x23,
-0x91, 0x2a, 0xd4
+0x6d, 0x91, 0x24, 0xf2, 0xd8, 0xd7, 0x65, 0x90, 0x86, 0x4d, 0x04, 0xbc, 0x94,
+0x26, 0xcb, 0x2f
 };
 
 static unsigned char client_hts_iv[] = {
-0x4d, 0x2e, 0x61, 0x0c, 0x4d, 0x3a, 0x8e, 0x5f, 0x15, 0x41, 0x1e, 0xfd
+0x16, 0x9b, 0x9f, 0x47, 0x16, 0x8a, 0xb5, 0x4d, 0xf5, 0x28, 0x1e, 0xe2
 };
 
 static const char *server_hts_label = "server handshake traffic secret";
 
 static unsigned char server_hts[] = {
-0x74, 0x1f, 0xb3, 0xb8, 0x41, 0x24, 0xc4, 0x7e, 0x1b, 0x2e, 0xa9, 0x4f, 0x0c,
-0x42, 0xc9, 0x06, 0xb7, 0x7c, 0x84, 0x92, 0x05, 0xed, 0x5f, 0x19, 0xda, 0xbb,
-0xbb, 0xce, 0xc7, 0x29, 0x06, 0x7e,
+0x3a, 0xb5, 0x28, 0x21, 0x7d, 0xb3, 0xbc, 0x5a, 0xf4, 0x8b, 0xc2, 0x3a, 0x1b,
+0x1e, 0x6f, 0x2b, 0x8e, 0xb0, 0xac, 0x26, 0xe9, 0x6d, 0xee, 0xa7, 0x3e, 0xfd,
+0x0a, 0x9f, 0xc0, 0x28, 0x62, 0x70
 };
 
 static unsigned char server_hts_key[] = {
-0x72, 0x61, 0x1c, 0xc8, 0x0d, 0x65, 0x9c, 0x89, 0xf8, 0x94, 0x9e, 0x32, 0x67,
-0xe1, 0x6c, 0x2d
-
+0x6d, 0x92, 0xe8, 0x71, 0x97, 0xf4, 0x12, 0xf5, 0x8f, 0x9c, 0xab, 0xf9, 0x55,
+0xe9, 0x74, 0x7e
 };
 
 static unsigned char server_hts_iv[] = {
-0x43, 0xfe, 0x11, 0x29, 0x0f, 0xe8, 0xfe, 0x84, 0x9c, 0x9b, 0x21, 0xef,
+0x85, 0x45, 0xc8, 0x3e, 0x94, 0x68, 0x4f, 0xd9, 0xe4, 0xd8, 0x42, 0x64
 };
 
 static unsigned char master_secret[] = {
-0xfe, 0x8d, 0xfb, 0xd0, 0x14, 0x94, 0x4e, 0x22, 0x65, 0x16, 0x7d, 0xc4, 0x20,
-0x01, 0x5b, 0x10, 0x64, 0x74, 0xb7, 0x22, 0x9a, 0x95, 0xd1, 0x48, 0x0c, 0xb9,
-0xac, 0xd1, 0xa0, 0x28, 0xb7, 0x67
+0x3d, 0x10, 0x81, 0xb3, 0x9d, 0x60, 0x3a, 0x9f, 0x3a, 0x1b, 0x7c, 0xec, 0x0d,
+0xfc, 0x92, 0xe5, 0xca, 0xcc, 0x6c, 0xd6, 0xec, 0xd1, 0x58, 0xcd, 0xd9, 0x93,
+0xf1, 0xfc, 0xe3, 0x10, 0x8e, 0x84
 };
 
 static const char *client_ats_label = "client application traffic secret";
 
 static unsigned char client_ats[] = {
-0x56, 0x9e, 0x9c, 0x17, 0xe3, 0x52, 0x1f, 0xdd, 0x09, 0xf4, 0xb8, 0x4f, 0x6c,
-0xd6, 0x6d, 0xa8, 0x23, 0xde, 0xeb, 0x81, 0xbb, 0xb1, 0xde, 0x61, 0xe2, 0x82,
-0x56, 0x27, 0xf7, 0x00, 0x63, 0x81,
+0xe6, 0xb3, 0xbd, 0x9b, 0x6b, 0xd5, 0xbf, 0x4c, 0xba, 0x8f, 0xbf, 0xc1, 0x15,
+0xb2, 0x06, 0x34, 0x83, 0xfa, 0xad, 0x72, 0xb3, 0xb8, 0x08, 0xa7, 0xa8, 0xd1,
+0x6e, 0xc5, 0x37, 0x1f, 0x4d, 0x9c
 };
 
 static unsigned char client_ats_key[] = {
-0xcb, 0xfa, 0xae, 0x71, 0x8d, 0xfb, 0x52, 0xba, 0x7b, 0x87, 0xde, 0x8b, 0x6d,
-0xac, 0x92, 0x60
+0x87, 0xe6, 0xee, 0xdc, 0x4d, 0x9b, 0x0c, 0xa4, 0x65, 0xff, 0xe4, 0xb9, 0xeb,
+0x2b, 0x26, 0xf9
 };
 
 static unsigned char client_ats_iv[] = {
-0x74, 0x86, 0x88, 0xe9, 0x7f, 0x72, 0xfb, 0xf3, 0x33, 0x1e, 0xfb, 0x55
+0xf0, 0x15, 0xc6, 0xbc, 0x95, 0x89, 0xc8, 0x94, 0x03, 0x4d, 0x6c, 0x70
 };
 
 static const char *server_ats_label = "server application traffic secret";
 
 static unsigned char server_ats[] = {
-0xd1, 0xbf, 0xdc, 0x8b, 0x84, 0xf4, 0x16, 0xb7, 0xc6, 0x90, 0xd9, 0xc9, 0x2c,
-0x23, 0x11, 0xb3, 0x05, 0xad, 0x75, 0xfc, 0xe6, 0x29, 0x90, 0x2b, 0xe1, 0x03,
-0xdd, 0x0c, 0x12, 0x51, 0xea, 0xd2,
+0x27, 0x72, 0x45, 0xe1, 0x1c, 0xcd, 0x40, 0x67, 0xdf, 0xa7, 0xf5, 0xd2, 0xa2,
+0xda, 0xe8, 0x87, 0x61, 0x52, 0xc3, 0x0d, 0x7f, 0x62, 0x22, 0x03, 0xd4, 0x97,
+0xfa, 0xaf, 0x31, 0xab, 0xaa, 0xba
 };
 
 static unsigned char server_ats_key[] = {
-0x35, 0xc2, 0xd1, 0x54, 0xa8, 0x43, 0x03, 0xc6, 0x55, 0xa0, 0x2e, 0x5e, 0x1f,
-0x82, 0x31, 0x62
+0xd2, 0xa3, 0x23, 0x54, 0x66, 0x92, 0x33, 0xa2, 0x49, 0x19, 0x74, 0xc2, 0x1a,
+0x0e, 0x19, 0x01
 };
 
 static unsigned char server_ats_iv[] = {
-0xe5, 0x77, 0xd9, 0x8a, 0xb3, 0x2e, 0xec, 0x79, 0xb1, 0x63, 0x68, 0xc2
+0x70, 0x28, 0x1e, 0x0d, 0xf7, 0xd4, 0x16, 0x97, 0xd3, 0xc3, 0xc4, 0x51
 };
 
 /* Mocked out implementations of various functions */
diff --git a/util/TLSProxy/HelloRetryRequest.pm b/util/TLSProxy/HelloRetryRequest.pm
index a15c054..c4125b7 100644
--- a/util/TLSProxy/HelloRetryRequest.pm
+++ b/util/TLSProxy/HelloRetryRequest.pm
@@ -47,6 +47,9 @@ sub parse
         $server_version = TLSProxy::Record::VERS_TLS_1_3;
     }
 
+    my $ciphersuite = unpack('n', substr($self->data, $ptr));
+    $ptr += 2;
+
     my $extensions_len = unpack('n', substr($self->data, $ptr));
     if (!defined $extensions_len) {
         $extensions_len = 0;
@@ -75,8 +78,11 @@ sub parse
     }
 
     $self->server_version($server_version);
+    $self->ciphersuite($ciphersuite);
     $self->extension_data(\%extensions);
 
+    print "    Server Version:".$server_version."\n";
+    print "    Ciphersuite:".$ciphersuite."\n";
     print "    Extensions Len:".$extensions_len."\n";
 }
 
@@ -100,6 +106,7 @@ sub set_message_contents
     }
 
     $data = pack('n', $self->server_version);
+    $data .= pack('n', $self->ciphersuite);
     $data .= pack('n', length($extensions));
     $data .= $extensions;
     $self->data($data);
@@ -114,6 +121,14 @@ sub server_version
     }
     return $self->{server_version};
 }
+sub ciphersuite
+{
+    my $self = shift;
+    if (@_) {
+      $self->{ciphersuite} = shift;
+    }
+    return $self->{ciphersuite};
+}
 sub extension_data
 {
     my $self = shift;
diff --git a/util/TLSProxy/Message.pm b/util/TLSProxy/Message.pm
index 39123fa..3c19845 100644
--- a/util/TLSProxy/Message.pm
+++ b/util/TLSProxy/Message.pm
@@ -92,7 +92,9 @@ use constant {
 
 use constant {
     CIPHER_DHE_RSA_AES_128_SHA => 0x0033,
-    CIPHER_ADH_AES_128_SHA => 0x0034
+    CIPHER_ADH_AES_128_SHA => 0x0034,
+    CIPHER_TLS13_AES_128_GCM_SHA256 => 0x1301,
+    CIPHER_TLS13_AES_256_GCM_SHA384 => 0x1302
 };
 
 my $payload = "";
diff --git a/util/TLSProxy/Record.pm b/util/TLSProxy/Record.pm
index 202c1ec..358c1ce 100644
--- a/util/TLSProxy/Record.pm
+++ b/util/TLSProxy/Record.pm
@@ -35,14 +35,14 @@ my %record_type = (
 );
 
 use constant {
-    VERS_TLS_1_4 => 773,
-    VERS_TLS_1_3_DRAFT => 32530,
-    VERS_TLS_1_3 => 772,
-    VERS_TLS_1_2 => 771,
-    VERS_TLS_1_1 => 770,
-    VERS_TLS_1_0 => 769,
-    VERS_SSL_3_0 => 768,
-    VERS_SSL_LT_3_0 => 767
+    VERS_TLS_1_4 => 0x0305,
+    VERS_TLS_1_3_DRAFT => 0x7f13,
+    VERS_TLS_1_3 => 0x0304,
+    VERS_TLS_1_2 => 0x0303,
+    VERS_TLS_1_1 => 0x0302,
+    VERS_TLS_1_0 => 0x0301,
+    VERS_SSL_3_0 => 0x0300,
+    VERS_SSL_LT_3_0 => 0x02ff
 };
 
 my %tls_version = (


More information about the openssl-commits mailing list