[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Tue Feb 14 13:18:12 UTC 2017


The branch master has been updated
       via  429ff318d613047cf94accdc17e8d7c0dc144657 (commit)
       via  319a33d0060b77d9446894b8a386718abcaee1a4 (commit)
       via  0dd7ba24e835fc66afc4997b376bc2a5e1f03992 (commit)
       via  2248dbebeeedd77f08d67e3dcd9031f6c1f0894f (commit)
       via  b0bfd1408506b399081186aa2a15cd60ed001595 (commit)
       via  d542790b0767535bce903d9f6ad314357484d67f (commit)
       via  0adb6417403f4be801b8da28cb83efb60f79f66c (commit)
       via  f6cec2d8badb6e9b01e8f477f98fdeecc32e46a5 (commit)
       via  38f5c30b311f0e736081e0b64b22e917b651536a (commit)
       via  87d70b63a53e7268512c7890cb55192669342534 (commit)
       via  aff9929b43cba794e5b99a9be5c8ca47873154d1 (commit)
       via  3847d426e3a530786b82fecfdbc9793b44b88cd3 (commit)
       via  7d061fced39d72bd664d04e254c1e3ba6cf99fbc (commit)
       via  611383586e68921ba4640134c491a4d2b57933d9 (commit)
      from  e0670973d5c0b837eb5a9f1670e47107f466fbc7 (commit)


- Log -----------------------------------------------------------------
commit 429ff318d613047cf94accdc17e8d7c0dc144657
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Feb 8 17:27:09 2017 +0000

    Remove a double call to ssl3_send_alert()
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit 319a33d0060b77d9446894b8a386718abcaee1a4
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Feb 8 17:16:25 2017 +0000

    Fix a bogus uninit variable warning
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit 0dd7ba24e835fc66afc4997b376bc2a5e1f03992
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Feb 6 16:52:38 2017 +0000

    Add a bytestogroup macro
    
    For converting the 2 byte group id into an unsigned int.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit 2248dbebeeedd77f08d67e3dcd9031f6c1f0894f
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Feb 6 16:47:29 2017 +0000

    Various style fixes following review feedback
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit b0bfd1408506b399081186aa2a15cd60ed001595
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Feb 2 16:28:45 2017 +0000

    Update the tls13messages test to add some HRR scenarios
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit d542790b0767535bce903d9f6ad314357484d67f
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Feb 2 16:06:50 2017 +0000

    Update the kex modes tests to check various HRR scenarios
    
    Make sure we get an HRR in the right circumstances based on kex mode.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit 0adb6417403f4be801b8da28cb83efb60f79f66c
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Feb 2 16:06:28 2017 +0000

    Update TLSProxy to know about HelloRetryRequest messages
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit f6cec2d8badb6e9b01e8f477f98fdeecc32e46a5
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Feb 2 14:54:24 2017 +0000

    Update test counting in checkhandshake.pm
    
    Previously counting the number of tests in checkhandshake.pm took an
    initial guess and then modified it based on various known special
    cases. That is becoming increasingly untenable, so this changes it to
    properly calculate the number of tests we expect to run.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit 38f5c30b311f0e736081e0b64b22e917b651536a
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Feb 2 13:12:08 2017 +0000

    Update the key_share tests for HelloRetryRequest
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit 87d70b63a53e7268512c7890cb55192669342534
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Feb 2 11:16:25 2017 +0000

    Add trace support for HelloRetryRequest
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit aff9929b43cba794e5b99a9be5c8ca47873154d1
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Feb 1 17:10:45 2017 +0000

    Implement support for resumption with a HelloRetryRequest
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit 3847d426e3a530786b82fecfdbc9793b44b88cd3
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Feb 1 13:31:27 2017 +0000

    Add client side support for parsing Hello Retry Request
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit 7d061fced39d72bd664d04e254c1e3ba6cf99fbc
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jan 30 16:16:28 2017 +0000

    Add server side support for creating the Hello Retry Request message
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

commit 611383586e68921ba4640134c491a4d2b57933d9
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jan 31 17:00:12 2017 +0000

    Make the context available to the extensions parse and construction funcs
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/2341)

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

Summary of changes:
 include/openssl/ssl.h                              |   8 +-
 include/openssl/ssl3.h                             |   1 +
 ssl/ssl_err.c                                      |   6 +
 ssl/ssl_locl.h                                     |   6 +
 ssl/statem/extensions.c                            | 155 ++++++++++--
 ssl/statem/extensions_clnt.c                       | 277 +++++++++++++--------
 ssl/statem/extensions_srvr.c                       | 164 ++++++------
 ssl/statem/statem_clnt.c                           |  87 ++++++-
 ssl/statem/statem_lib.c                            |  67 ++++-
 ssl/statem/statem_locl.h                           | 229 +++++++++--------
 ssl/statem/statem_srvr.c                           |  80 ++++--
 ssl/t1_trce.c                                      |  48 +++-
 test/recipes/70-test_key_share.t                   |  74 +++---
 test/recipes/70-test_tls13kexmodes.t               |  90 ++++++-
 test/recipes/70-test_tls13messages.t               |  57 ++++-
 test/testlib/checkhandshake.pm                     |  85 +++++--
 ...EncryptedExtensions.pm => HelloRetryRequest.pm} |  30 ++-
 util/TLSProxy/Message.pm                           |  11 +
 util/TLSProxy/Proxy.pm                             |   1 +
 19 files changed, 1056 insertions(+), 420 deletions(-)
 copy util/TLSProxy/{EncryptedExtensions.pm => HelloRetryRequest.pm} (76%)

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index aa3bcc6..96a5558 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -880,7 +880,9 @@ typedef enum {
     TLS_ST_CR_ENCRYPTED_EXTENSIONS,
     TLS_ST_CR_CERT_VRFY,
     TLS_ST_SW_CERT_VRFY,
-    TLS_ST_CR_HELLO_REQ
+    TLS_ST_CR_HELLO_REQ,
+    TLS_ST_SW_HELLO_RETRY_REQUEST,
+    TLS_ST_CR_HELLO_RETRY_REQUEST
 } OSSL_HANDSHAKE_STATE;
 
 /*
@@ -2072,6 +2074,7 @@ int ERR_load_SSL_strings(void);
 
 /* Function codes. */
 # define SSL_F_ADD_CLIENT_KEY_SHARE_EXT                   438
+# define SSL_F_ADD_KEY_SHARE                              512
 # define SSL_F_CHECK_SUITEB_CIPHER_LIST                   331
 # define SSL_F_CT_MOVE_SCTS                               345
 # define SSL_F_CT_STRICT                                  349
@@ -2300,6 +2303,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_CONSTRUCT_EXTENSIONS                   447
 # define SSL_F_TLS_CONSTRUCT_FINISHED                     359
 # define SSL_F_TLS_CONSTRUCT_HELLO_REQUEST                373
+# define SSL_F_TLS_CONSTRUCT_HELLO_RETRY_REQUEST          510
 # define SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET           428
 # define SSL_F_TLS_CONSTRUCT_NEXT_PROTO                   426
 # define SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE           490
@@ -2353,6 +2357,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS           444
 # define SSL_F_TLS_PROCESS_FINISHED                       364
 # define SSL_F_TLS_PROCESS_HELLO_REQ                      507
+# define SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST            511
 # define SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT          442
 # define SSL_F_TLS_PROCESS_KEY_EXCHANGE                   365
 # define SSL_F_TLS_PROCESS_NEW_SESSION_TICKET             366
@@ -2502,6 +2507,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_NO_RENEGOTIATION                           339
 # define SSL_R_NO_REQUIRED_DIGEST                         324
 # define SSL_R_NO_SHARED_CIPHER                           193
+# define SSL_R_NO_SHARED_GROUPS                           410
 # define SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS             376
 # define SSL_R_NO_SRTP_PROFILES                           359
 # define SSL_R_NO_SUITABLE_KEY_SHARE                      101
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 8d146be..d76236a 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -274,6 +274,7 @@ extern "C" {
 # define SSL3_MT_CLIENT_HELLO                    1
 # define SSL3_MT_SERVER_HELLO                    2
 # define SSL3_MT_NEWSESSION_TICKET               4
+# define SSL3_MT_HELLO_RETRY_REQUEST             6
 # define SSL3_MT_ENCRYPTED_EXTENSIONS            8
 # define SSL3_MT_CERTIFICATE                     11
 # define SSL3_MT_SERVER_KEY_EXCHANGE             12
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index a6d3412..ea5a763 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -20,6 +20,7 @@
 
 static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_ADD_CLIENT_KEY_SHARE_EXT), "add_client_key_share_ext"},
+    {ERR_FUNC(SSL_F_ADD_KEY_SHARE), "add_key_share"},
     {ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "check_suiteb_cipher_list"},
     {ERR_FUNC(SSL_F_CT_MOVE_SCTS), "ct_move_scts"},
     {ERR_FUNC(SSL_F_CT_STRICT), "ct_strict"},
@@ -329,6 +330,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_FINISHED), "tls_construct_finished"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST),
      "tls_construct_hello_request"},
+    {ERR_FUNC(SSL_F_TLS_CONSTRUCT_HELLO_RETRY_REQUEST),
+     "tls_construct_hello_retry_request"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET),
      "tls_construct_new_session_ticket"},
     {ERR_FUNC(SSL_F_TLS_CONSTRUCT_NEXT_PROTO), "tls_construct_next_proto"},
@@ -410,6 +413,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "tls_process_encrypted_extensions"},
     {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),
+     "tls_process_hello_retry_request"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT),
      "tls_process_initial_server_flight"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_KEY_EXCHANGE), "tls_process_key_exchange"},
@@ -603,6 +608,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_NO_RENEGOTIATION), "no renegotiation"},
     {ERR_REASON(SSL_R_NO_REQUIRED_DIGEST), "no required digest"},
     {ERR_REASON(SSL_R_NO_SHARED_CIPHER), "no shared cipher"},
+    {ERR_REASON(SSL_R_NO_SHARED_GROUPS), "no shared groups"},
     {ERR_REASON(SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS),
      "no shared signature algorithms"},
     {ERR_REASON(SSL_R_NO_SRTP_PROFILES), "no srtp profiles"},
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 2a23007..df6be64 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1005,6 +1005,9 @@ struct ssl_st {
     unsigned char cert_verify_hash[EVP_MAX_MD_SIZE];
     size_t cert_verify_hash_len;
 
+    /* Flag to indicate whether we should send a HelloRetryRequest or not */
+    int hello_retry_request;
+
     /*
      * the session_id_context is used to ensure sessions are only reused in
      * the appropriate context
@@ -2191,6 +2194,9 @@ SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
 # define TLS_CURVE_PRIME         0x0
 # define TLS_CURVE_CHAR2         0x1
 # define TLS_CURVE_CUSTOM        0x2
+
+#define bytestogroup(bytes) ((unsigned int)(bytes[0] << 8 | bytes[1]))
+
 __owur int tls1_ec_curve_id2nid(int curve_id, unsigned int *pflags);
 __owur int tls1_ec_nid2curve_id(int nid);
 __owur int tls1_check_curve(SSL *s, const unsigned char *p, size_t len);
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index 5368e85..50fd3bb 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -57,15 +57,17 @@ typedef struct extensions_definition_st {
      */
     int (*init)(SSL *s, unsigned int context);
     /* Parse extension sent from client to server */
-    int (*parse_ctos)(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+    int (*parse_ctos)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                      size_t chainidx, int *al);
     /* Parse extension send from server to client */
-    int (*parse_stoc)(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+    int (*parse_stoc)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                      size_t chainidx, int *al);
     /* Construct extension sent from server to client */
-    int (*construct_stoc)(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                          int *al);
+    int (*construct_stoc)(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                          size_t chainidx, int *al);
     /* Construct extension sent from client to server */
-    int (*construct_ctos)(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                          int *al);
+    int (*construct_ctos)(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                          size_t chainidx, int *al);
     /*
      * Finalise extension after parsing. Always called where an extensions was
      * initialised even if the extension was not present. |sent| is set to 1 if
@@ -470,7 +472,8 @@ int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
                         RAW_EXTENSION *exts, X509 *x, size_t chainidx, int *al)
 {
     RAW_EXTENSION *currext = &exts[idx];
-    int (*parser)(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al) = NULL;
+    int (*parser)(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                  size_t chainidx, int *al) = NULL;
 
     /* Skip if the extension is not present */
     if (!currext->present)
@@ -499,7 +502,7 @@ int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
         parser = s->server ? extdef->parse_ctos : extdef->parse_stoc;
 
         if (parser != NULL)
-            return parser(s, &currext->data, x, chainidx, al);
+            return parser(s, &currext->data, context, x, chainidx, al);
 
         /*
          * If the parser is NULL we fall through to the custom extension
@@ -633,8 +636,8 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
     }
 
     for (i = 0, thisexd = ext_defs; i < OSSL_NELEM(ext_defs); i++, thisexd++) {
-        int (*construct)(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                         int *al);
+        int (*construct)(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                         size_t chainidx, int *al);
 
         /* Skip if not relevant for our context */
         if ((thisexd->context & context) == 0)
@@ -661,7 +664,7 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
                 || construct == NULL)
             continue;
 
-        if (!construct(s, pkt, x, chainidx, &tmpal))
+        if (!construct(s, pkt, context, x, chainidx, &tmpal))
             goto err;
     }
 
@@ -965,22 +968,102 @@ static int final_key_share(SSL *s, unsigned int context, int sent, int *al)
 
     /*
      * If
+     *     we are a client
+     *     AND
      *     we have no key_share
      *     AND
      *     (we are not resuming
      *      OR the kex_mode doesn't allow non key_share resumes)
      * THEN
-     *     fail
+     *     fail;
      */
-    if (((s->server && s->s3->peer_tmp == NULL) || (!s->server && !sent))
+    if (!s->server
+            && !sent
             && (!s->hit
                 || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0)) {
-        /* No suitable share */
-        /* TODO(TLS1.3): Send a HelloRetryRequest */
+        /* Nothing left we can do - just fail */
         *al = SSL_AD_HANDSHAKE_FAILURE;
         SSLerr(SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
         return 0;
     }
+    /*
+     * If
+     *     we are a server
+     *     AND
+     *     we have no key_share
+     * THEN
+     *     If
+     *         we didn't already send a HelloRetryRequest
+     *         AND
+     *         the client sent a key_share extension
+     *         AND
+     *         (we are not resuming
+     *          OR the kex_mode allows key_share resumes)
+     *         AND
+     *         a shared group exists
+     *     THEN
+     *         send a HelloRetryRequest
+     *     ELSE If
+     *         we are not resuming
+     *         OR
+     *         the kex_mode doesn't allow non key_share resumes
+     *     THEN
+     *         fail;
+     */
+    if (s->server && s->s3->peer_tmp == NULL) {
+        /* No suitable share */
+        if (s->hello_retry_request == 0 && sent
+                && (!s->hit
+                    || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE)
+                       != 0)) {
+            const unsigned char *pcurves, *pcurvestmp, *clntcurves;
+            size_t num_curves, clnt_num_curves, i;
+            unsigned int group_id = 0;
+
+            /* Check if a shared group exists */
+
+            /* Get the clients list of supported groups. */
+            if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_FINAL_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+
+            /* Get our list of available groups */
+            if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_FINAL_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+
+            /* Find the first group we allow that is also in client's list */
+            for (i = 0, pcurvestmp = pcurves; i < num_curves;
+                 i++, pcurvestmp += 2) {
+                group_id = bytestogroup(pcurvestmp);
+
+                if (check_in_list(s, group_id, clntcurves, clnt_num_curves, 1))
+                    break;
+            }
+
+            if (i < num_curves) {
+                /* A shared group exists so send a HelloRetryRequest */
+                s->s3->group_id = group_id;
+                s->hello_retry_request = 1;
+                return 1;
+            }
+        }
+        if (!s->hit
+                || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0) {
+            /* Nothing left we can do - just fail */
+            *al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
+            return 0;
+        }
+    }
+
+    /* We have a key_share so don't send any more HelloRetryRequest messages */
+    if (s->server)
+        s->hello_retry_request = 0;
 
     /*
      * For a client side resumption with no key_share we need to generate
@@ -1050,13 +1133,45 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
         goto err;
     }
 
+    if (EVP_DigestInit_ex(mctx, md, NULL) <= 0) {
+        SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
     /*
-     * Get a hash of the ClientHello up to the start of the binders.
-     * TODO(TLS1.3): This will need to be tweaked when we implement
-     * HelloRetryRequest to include the digest of the previous messages here.
+     * Get a hash of the ClientHello up to the start of the binders. If we are
+     * following a HelloRetryRequest then this includes the hash of the first
+     * ClientHello and the HelloRetryRequest itself.
      */
-    if (EVP_DigestInit_ex(mctx, md, NULL) <= 0
-            || EVP_DigestUpdate(mctx, msgstart, binderoffset) <= 0
+    if (s->hello_retry_request) {
+        size_t hdatalen;
+        void *hdata;
+
+        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+        if (hdatalen <= 0) {
+            SSLerr(SSL_F_TLS_PSK_DO_BINDER, SSL_R_BAD_HANDSHAKE_LENGTH);
+            goto err;
+        }
+
+        /*
+         * For servers the handshake buffer data will include the second
+         * ClientHello - which we don't want - so we need to take that bit off.
+         */
+        if (s->server) {
+            if (hdatalen < s->init_num + SSL3_HM_HEADER_LENGTH) {
+                SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            hdatalen -= s->init_num + SSL3_HM_HEADER_LENGTH;
+        }
+
+        if (EVP_DigestUpdate(mctx, hdata, hdatalen) <= 0) {
+            SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    if (EVP_DigestUpdate(mctx, msgstart, binderoffset) <= 0
             || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) {
         SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
         goto err;
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 68b52e1..ea37919 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -12,8 +12,8 @@
 #include "../ssl_locl.h"
 #include "statem_locl.h"
 
-int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, X509 *x,
-                                   size_t chainidx, int *al)
+int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx, int *al)
 {
     /* Add RI if renegotiating */
     if (!s->renegotiate)
@@ -31,8 +31,8 @@ int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, X509 *x,
     return 1;
 }
 
-int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, X509 *x,
-                                   size_t chainidx, int *al)
+int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx, int *al)
 {
     if (s->ext.hostname == NULL)
         return 1;
@@ -56,8 +56,8 @@ int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, X509 *x,
 }
 
 #ifndef OPENSSL_NO_SRP
-int tls_construct_ctos_srp(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al)
+int tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al)
 {
     /* Add SRP username if there is one */
     if (s->srp_ctx.login == NULL)
@@ -108,8 +108,8 @@ static int use_ecc(SSL *s)
     return i < end;
 }
 
-int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, X509 *x,
-                                     size_t chainidx, int *al)
+int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx, int *al)
 {
     const unsigned char *pformats;
     size_t num_formats;
@@ -132,7 +132,8 @@ int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, X509 *x,
     return 1;
 }
 
-int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
                                         size_t chainidx, int *al)
 {
     const unsigned char *pcurves = NULL, *pcurvestmp;
@@ -163,7 +164,7 @@ int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt, X509 *x,
     }
     /* Copy curve ID if supported */
     for (i = 0; i < num_curves; i++, pcurvestmp += 2) {
-        if (tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) {
+        if (tls_curve_allowed(s, pcurvestmp, SSL_SECOP_CURVE_SUPPORTED)) {
             if (!WPACKET_put_bytes_u8(pkt, pcurvestmp[0])
                 || !WPACKET_put_bytes_u8(pkt, pcurvestmp[1])) {
                     SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
@@ -182,7 +183,8 @@ int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt, X509 *x,
 }
 #endif
 
-int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
                                       size_t chainidx, int *al)
 {
     size_t ticklen;
@@ -223,8 +225,8 @@ int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt, X509 *x,
     return 1;
 }
 
-int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                int *al)
+int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx, int *al)
 {
     size_t salglen;
     const uint16_t *salg;
@@ -249,7 +251,8 @@ int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 }
 
 #ifndef OPENSSL_NO_OCSP
-int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
                                       size_t chainidx, int *al)
 {
     int i;
@@ -316,8 +319,8 @@ int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt, X509 *x,
 #endif
 
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al)
+int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al)
 {
     if (s->ctx->ext.npn_select_cb == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
         return 1;
@@ -336,8 +339,8 @@ int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 }
 #endif
 
-int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                            int *al)
+int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al)
 {
     s->s3->alpn_sent = 0;
 
@@ -360,8 +363,8 @@ int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 
 
 #ifndef OPENSSL_NO_SRTP
-int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                int *al)
+int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx, int *al)
 {
     STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = SSL_get_srtp_profiles(s);
     int i, end;
@@ -400,8 +403,8 @@ int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 }
 #endif
 
-int tls_construct_ctos_etm(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al)
+int tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al)
 {
     if (s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
         return 1;
@@ -416,8 +419,8 @@ int tls_construct_ctos_etm(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 }
 
 #ifndef OPENSSL_NO_CT
-int tls_construct_ctos_sct(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al)
+int tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al)
 {
     if (s->ct_validation_callback == NULL)
         return 1;
@@ -436,8 +439,8 @@ int tls_construct_ctos_sct(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 }
 #endif
 
-int tls_construct_ctos_ems(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al)
+int tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al)
 {
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
             || !WPACKET_put_bytes_u16(pkt, 0)) {
@@ -448,7 +451,8 @@ int tls_construct_ctos_ems(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
     return 1;
 }
 
-int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
                                           size_t chainidx, int *al)
 {
     int currv, min_version, max_version, reason;
@@ -499,8 +503,8 @@ int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, X509 *x,
  * Construct a psk_kex_modes extension. We only have two modes we know about
  * at this stage, so we send both.
  */
-int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, X509 *x,
-                                     size_t chainidx, int *al)
+int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     /*
@@ -524,12 +528,57 @@ int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, X509 *x,
     return 1;
 }
 
-int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al)
+#ifndef OPENSSL_NO_TLS1_3
+static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
+{
+    unsigned char *encoded_point;
+    EVP_PKEY *key_share_key;
+    size_t encodedlen;
+
+    key_share_key = ssl_generate_pkey_curve(curve_id);
+    if (key_share_key == NULL) {
+        SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EVP_LIB);
+        return 0;
+    }
+
+    /* Encode the public key. */
+    encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
+                                                &encoded_point);
+    if (encodedlen == 0) {
+        SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EC_LIB);
+        EVP_PKEY_free(key_share_key);
+        return 0;
+    }
+
+    /* Create KeyShareEntry */
+    if (!WPACKET_put_bytes_u16(pkt, curve_id)
+            || !WPACKET_sub_memcpy_u16(pkt, encoded_point, encodedlen)) {
+        SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        EVP_PKEY_free(key_share_key);
+        OPENSSL_free(encoded_point);
+        return 0;
+    }
+
+    /*
+     * TODO(TLS1.3): When changing to send more than one key_share we're
+     * going to need to be able to save more than one EVP_PKEY. For now
+     * we reuse the existing tmp.pkey
+     */
+    s->s3->tmp.pkey = key_share_key;
+    s->s3->group_id = curve_id;
+    OPENSSL_free(encoded_point);
+
+    return 1;
+}
+#endif
+
+int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
-    size_t i, sharessent = 0, num_curves = 0;
+    size_t i, num_curves = 0;
     const unsigned char *pcurves = NULL;
+    unsigned int curve_id = 0;
 
     /* key_share extension */
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
@@ -547,62 +596,37 @@ int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
         return 0;
     }
 
+    if (s->s3->tmp.pkey != NULL) {
+        /* Shouldn't happen! */
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
     /*
      * TODO(TLS1.3): Make the number of key_shares sent configurable. For
      * now, just send one
      */
-    for (i = 0; i < num_curves && sharessent < 1; i++, pcurves += 2) {
-        unsigned char *encodedPoint = NULL;
-        unsigned int curve_id = 0;
-        EVP_PKEY *key_share_key = NULL;
-        size_t encodedlen;
-
-        if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
-            continue;
-
-        if (s->s3->tmp.pkey != NULL) {
-            /* Shouldn't happen! */
-            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-            return 0;
-        }
+    if (s->s3->group_id != 0) {
+        curve_id = s->s3->group_id;
+    } else {
+        for (i = 0; i < num_curves; i++, pcurves += 2) {
 
-        /* Generate a key for this key_share */
-        curve_id = (pcurves[0] << 8) | pcurves[1];
-        key_share_key = ssl_generate_pkey_curve(curve_id);
-        if (key_share_key == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EVP_LIB);
-            return 0;
-        }
+            if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
+                continue;
 
-        /* Encode the public key. */
-        encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
-                                                    &encodedPoint);
-        if (encodedlen == 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EC_LIB);
-            EVP_PKEY_free(key_share_key);
-            return 0;
-        }
-
-        /* Create KeyShareEntry */
-        if (!WPACKET_put_bytes_u16(pkt, curve_id)
-                || !WPACKET_sub_memcpy_u16(pkt, encodedPoint, encodedlen)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
-            EVP_PKEY_free(key_share_key);
-            OPENSSL_free(encodedPoint);
-            return 0;
+            curve_id = bytestogroup(pcurves);
+            break;
         }
+    }
 
-        /*
-         * TODO(TLS1.3): When changing to send more than one key_share we're
-         * going to need to be able to save more than one EVP_PKEY. For now
-         * we reuse the existing tmp.pkey
-         */
-        s->s3->group_id = curve_id;
-        s->s3->tmp.pkey = key_share_key;
-        sharessent++;
-        OPENSSL_free(encodedPoint);
+    if (curve_id == 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
+        return 0;
     }
 
+    if (!add_key_share(s, pkt, curve_id))
+        return 0;
+
     if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
         return 0;
@@ -615,8 +639,8 @@ int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 #define F5_WORKAROUND_MIN_MSG_LEN   0xff
 #define F5_WORKAROUND_MAX_MSG_LEN   0x200
 
-int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                               int *al)
+int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx, int *al)
 {
     unsigned char *padbytes;
     size_t hlen;
@@ -662,8 +686,8 @@ int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 /*
  * Construct the pre_shared_key extension
  */
-int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al)
+int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     uint32_t now, agesec, agems;
@@ -774,8 +798,8 @@ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 /*
  * Parse the server's renegotiation binding and abort if it's not right
  */
-int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                               int *al)
+int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx, int *al)
 {
     size_t expected_len = s->s3->previous_client_finished_len
         + s->s3->previous_server_finished_len;
@@ -832,8 +856,8 @@ int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
     return 1;
 }
 
-int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, 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)
 {
     if (s->ext.hostname == NULL || PACKET_remaining(pkt) > 0) {
         *al = SSL_AD_UNRECOGNIZED_NAME;
@@ -856,8 +880,8 @@ int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 }
 
 #ifndef OPENSSL_NO_EC
-int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al)
+int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al)
 {
     unsigned int ecpointformats_len;
     PACKET ecptformatlist;
@@ -891,8 +915,8 @@ int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 }
 #endif
 
-int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                  int *al)
+int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     if (s->ext.session_ticket_cb != NULL &&
         !s->ext.session_ticket_cb(s, PACKET_data(pkt),
@@ -913,8 +937,8 @@ int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 }
 
 #ifndef OPENSSL_NO_OCSP
-int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                  int *al)
+int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     /*
      * MUST only be sent if we've requested a status
@@ -944,7 +968,8 @@ int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 
 
 #ifndef OPENSSL_NO_CT
-int tls_parse_stoc_sct(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
     /*
      * Only take it if we asked for it - i.e if there is no CT validation
@@ -997,7 +1022,8 @@ static int ssl_next_proto_validate(PACKET *pkt)
     return 1;
 }
 
-int tls_parse_stoc_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_stoc_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
     unsigned char *selected;
     unsigned char selected_len;
@@ -1047,7 +1073,8 @@ int tls_parse_stoc_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
 }
 #endif
 
-int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx, int *al)
 {
     size_t len;
 
@@ -1084,8 +1111,8 @@ int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
 }
 
 #ifndef OPENSSL_NO_SRTP
-int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                            int *al)
+int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al)
 {
     unsigned int id, ct, mki;
     int i;
@@ -1138,7 +1165,8 @@ int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 }
 #endif
 
-int tls_parse_stoc_etm(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_stoc_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
     /* Ignore if inappropriate ciphersuite */
     if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
@@ -1149,7 +1177,8 @@ int tls_parse_stoc_etm(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
     return 1;
 }
 
-int tls_parse_stoc_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
     s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
     if (!s->hit)
@@ -1158,8 +1187,8 @@ int tls_parse_stoc_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
     return 1;
 }
 
-int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                             int *al)
+int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                             size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     unsigned int group_id;
@@ -1179,6 +1208,49 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
         return 0;
     }
 
+    if ((context & EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0) {
+        unsigned const char *pcurves = NULL;
+        size_t i, num_curves;
+
+        if (PACKET_remaining(pkt) != 0) {
+            *al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_LENGTH_MISMATCH);
+            return 0;
+        }
+
+        /*
+         * It is an error if the HelloRetryRequest wants a key_share that we
+         * already sent in the first ClientHello
+         */
+        if (group_id == s->s3->group_id) {
+            *al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
+            return 0;
+        }
+
+        /* Validate the selected group is one we support */
+        pcurves = s->ext.supportedgroups;
+        if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
+            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        for (i = 0; i < num_curves; i++, pcurves += 2) {
+            if (group_id == bytestogroup(pcurves))
+                break;
+        }
+        if (i >= num_curves
+                || !tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) {
+            *al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
+            return 0;
+        }
+
+        s->s3->group_id = group_id;
+        EVP_PKEY_free(s->s3->tmp.pkey);
+        s->s3->tmp.pkey = NULL;
+        return 1;
+    }
+
     if (group_id != s->s3->group_id) {
         /*
          * This isn't for the group that we sent in the original
@@ -1222,7 +1294,8 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
     return 1;
 }
 
-int tls_parse_stoc_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     unsigned int identity;
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index df1e6c2..b555d68 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -14,8 +14,8 @@
 /*
  * Parse the client's renegotiation binding and abort if it's not right
  */
-int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                               int *al)
+int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx, int *al)
 {
     unsigned int ilen;
     const unsigned char *data;
@@ -73,8 +73,8 @@ int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
  *   extension.
  * - On session reconnect, the servername extension may be absent.
  */
-int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                               int *al)
+int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx, int *al)
 {
     unsigned int servname_type;
     PACKET sni, hostname;
@@ -116,6 +116,8 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
             return 0;
         }
 
+        OPENSSL_free(s->session->ext.hostname);
+        s->session->ext.hostname = NULL;
         if (!PACKET_strndup(&hostname, &s->session->ext.hostname)) {
             *al = TLS1_AD_INTERNAL_ERROR;
             return 0;
@@ -136,7 +138,8 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 }
 
 #ifndef OPENSSL_NO_SRP
-int tls_parse_ctos_srp(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_ctos_srp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
     PACKET srp_I;
 
@@ -160,8 +163,8 @@ int tls_parse_ctos_srp(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
 #endif
 
 #ifndef OPENSSL_NO_EC
-int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al)
+int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al)
 {
     PACKET ec_point_format_list;
 
@@ -184,8 +187,8 @@ int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 }
 #endif                          /* OPENSSL_NO_EC */
 
-int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                  int *al)
+int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     if (s->ext.session_ticket_cb &&
             !s->ext.session_ticket_cb(s, PACKET_data(pkt),
@@ -198,8 +201,8 @@ int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
     return 1;
 }
 
-int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                            int *al)
+int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al)
 {
     PACKET supported_sig_algs;
 
@@ -218,8 +221,8 @@ int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 }
 
 #ifndef OPENSSL_NO_OCSP
-int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                  int *al)
+int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al)
 {
     PACKET responder_id_list, exts;
 
@@ -317,7 +320,8 @@ int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 #endif
 
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_parse_ctos_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_ctos_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
     /*
      * We shouldn't accept this extension on a
@@ -335,7 +339,8 @@ int tls_parse_ctos_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
  * extension, not including type and length. |al| is a pointer to the alert
  * value to send in the event of a failure. Returns: 1 on success, 0 on error.
  */
-int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx, int *al)
 {
     PACKET protocol_list, save_protocol_list, protocol;
 
@@ -358,6 +363,9 @@ int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
         }
     } while (PACKET_remaining(&protocol_list) != 0);
 
+    OPENSSL_free(s->s3->alpn_proposed);
+    s->s3->alpn_proposed = NULL;
+    s->s3->alpn_proposed_len = 0;
     if (!PACKET_memdup(&save_protocol_list,
                        &s->s3->alpn_proposed, &s->s3->alpn_proposed_len)) {
         *al = TLS1_AD_INTERNAL_ERROR;
@@ -368,8 +376,8 @@ int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
 }
 
 #ifndef OPENSSL_NO_SRTP
-int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                            int *al)
+int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al)
 {
     STACK_OF(SRTP_PROTECTION_PROFILE) *srvr;
     unsigned int ct, mki_len, id;
@@ -439,7 +447,8 @@ int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 }
 #endif
 
-int tls_parse_ctos_etm(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_ctos_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
     if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC))
         s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
@@ -448,43 +457,12 @@ int tls_parse_ctos_etm(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
 }
 
 /*
- * Checks a list of |groups| to determine if the |group_id| is in it. If it is
- * and |checkallow| is 1 then additionally check if the group is allowed to be
- * used. Returns 1 if the group is in the list (and allowed if |checkallow| is
- * 1) or 0 otherwise.
- */
-#ifndef OPENSSL_NO_TLS1_3
-static int check_in_list(SSL *s, unsigned int group_id,
-                         const unsigned char *groups, size_t num_groups,
-                         int checkallow)
-{
-    size_t i;
-
-    if (groups == NULL || num_groups == 0)
-        return 0;
-
-    for (i = 0; i < num_groups; i++, groups += 2) {
-        unsigned int share_id = (groups[0] << 8) | (groups[1]);
-
-        if (group_id == share_id
-                && (!checkallow
-                    || tls_curve_allowed(s, groups, SSL_SECOP_CURVE_CHECK))) {
-            break;
-        }
-    }
-
-    /* If i == num_groups then not in the list */
-    return i < num_groups;
-}
-#endif
-
-/*
  * Process a psk_kex_modes extension received in the ClientHello. |pkt| contains
  * the raw PACKET data for the extension. Returns 1 on success or 0 on failure.
  * If a failure occurs then |*al| is set to an appropriate alert value.
  */
-int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al)
+int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     PACKET psk_kex_modes;
@@ -512,8 +490,8 @@ int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
  * the raw PACKET data for the extension. Returns 1 on success or 0 on failure.
  * If a failure occurs then |*al| is set to an appropriate alert value.
  */
-int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                             int *al)
+int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                             size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     unsigned int group_id;
@@ -642,8 +620,8 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
 }
 
 #ifndef OPENSSL_NO_EC
-int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, X509 *x,
-                                    size_t chainidx, int *al)
+int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, unsigned int context,
+                                    X509 *x, size_t chainidx, int *al)
 {
     PACKET supported_groups_list;
 
@@ -655,6 +633,9 @@ int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, X509 *x,
         return 0;
     }
 
+    OPENSSL_free(s->session->ext.supportedgroups);
+    s->session->ext.supportedgroups = NULL;
+    s->session->ext.supportedgroups_len = 0;
     if (!PACKET_memdup(&supported_groups_list,
                        &s->session->ext.supportedgroups,
                        &s->session->ext.supportedgroups_len)) {
@@ -666,7 +647,8 @@ int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, X509 *x,
 }
 #endif
 
-int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_ctos_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
     /* The extension must always be empty */
     if (PACKET_remaining(pkt) != 0) {
@@ -679,7 +661,8 @@ int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
     return 1;
 }
 
-int tls_parse_ctos_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
+int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al)
 {
     PACKET identities, binders, binder;
     size_t binderoffset, hashsize;
@@ -780,8 +763,8 @@ err:
 /*
  * Add the server's renegotiation binding
  */
-int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, X509 *x, size_t
-                                   chainidx, int *al)
+int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx, int *al)
 {
     if (!s->s3->send_connection_binding)
         return 1;
@@ -802,8 +785,8 @@ int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, X509 *x, size_t
     return 1;
 }
 
-int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, 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)
 {
     if (s->hit || s->servername_done != 1
             || s->session->ext.hostname == NULL)
@@ -819,8 +802,8 @@ int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, X509 *x,
 }
 
 #ifndef OPENSSL_NO_EC
-int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, X509 *x,
-                                     size_t chainidx, int *al)
+int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx, int *al)
 {
     unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
     unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
@@ -845,7 +828,8 @@ int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, X509 *x,
 }
 #endif
 
-int tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
                                       size_t chainidx, int *al)
 {
     if (!s->ext.ticket_expected || !tls_use_ticket(s)) {
@@ -863,8 +847,9 @@ int tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt, X509 *x,
 }
 
 #ifndef OPENSSL_NO_OCSP
-int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt, X509 *x,
-                                     size_t chainidx, int *al)
+int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
+                                      size_t chainidx, int *al)
 {
     if (!s->ext.status_expected)
         return 1;
@@ -894,7 +879,8 @@ int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt, X509 *x,
 #endif
 
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
                                       size_t chainidx, int *al)
 {
     const unsigned char *npa;
@@ -922,8 +908,8 @@ int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, X509 *x,
 }
 #endif
 
-int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                            int *al)
+int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al)
 {
     if (s->s3->alpn_selected == NULL)
         return 1;
@@ -944,8 +930,8 @@ int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 }
 
 #ifndef OPENSSL_NO_SRTP
-int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                int *al)
+int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx, int *al)
 {
     if (s->srtp_profile == NULL)
         return 1;
@@ -964,8 +950,8 @@ int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 }
 #endif
 
-int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al)
+int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al)
 {
     if ((s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) == 0)
         return 1;
@@ -991,8 +977,8 @@ int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
     return 1;
 }
 
-int tls_construct_stoc_ems(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al)
+int tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al)
 {
     if ((s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) == 0)
         return 1;
@@ -1006,8 +992,8 @@ int tls_construct_stoc_ems(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
     return 1;
 }
 
-int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al)
+int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al)
 {
 #ifndef OPENSSL_NO_TLS1_3
     unsigned char *encodedPoint;
@@ -1015,7 +1001,21 @@ int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
     EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;
 
     if (ckey == NULL) {
-        /* No key_share received from client; must be resuming. */
+        /* No key_share received from client */
+        if (s->hello_retry_request) {
+            if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
+                    || !WPACKET_start_sub_packet_u16(pkt)
+                    || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)
+                    || !WPACKET_close(pkt)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+                       ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+
+            return 1;
+        }
+
+        /* Must be resuming. */
         if (!s->hit || !tls13_generate_handshake_secret(s, NULL, 0)) {
             *al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
@@ -1065,8 +1065,8 @@ int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
     return 1;
 }
 
-int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, X509 *x,
-                                     size_t chainidx, int *al)
+int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx, int *al)
 {
     const unsigned char cryptopro_ext[36] = {
         0xfd, 0xe8,         /* 65000 */
@@ -1090,8 +1090,8 @@ int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, X509 *x,
     return 1;
 }
 
-int tls_construct_stoc_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al)
+int tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al)
 {
     if (!s->hit)
         return 1;
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index e5c60ae..152600b 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -60,6 +60,7 @@
 #include <openssl/bn.h>
 #include <openssl/engine.h>
 
+static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt);
 static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt);
 
 static ossl_inline int cert_req_allowed(SSL *s);
@@ -137,6 +138,17 @@ static int ossl_statem_client13_read_transition(SSL *s, int mt)
     default:
         break;
 
+    case TLS_ST_CW_CLNT_HELLO:
+        /*
+         * This must a ClientHello following a HelloRetryRequest, so the only
+         * thing we can get now is a ServerHello.
+         */
+        if (mt == SSL3_MT_SERVER_HELLO) {
+            st->hand_state = TLS_ST_CR_SRVR_HELLO;
+            return 1;
+        }
+        break;
+
     case TLS_ST_CR_SRVR_HELLO:
         if (mt == SSL3_MT_ENCRYPTED_EXTENSIONS) {
             st->hand_state = TLS_ST_CR_ENCRYPTED_EXTENSIONS;
@@ -210,8 +222,8 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
     int ske_expected;
 
     /*
-     * Note that after a ClientHello we don't know what version we are going
-     * to negotiate yet, so we don't take this branch until later
+     * Note that after writing the first ClientHello we don't know what version
+     * we are going to negotiate yet, so we don't take this branch until later.
      */
     if (SSL_IS_TLS13(s)) {
         if (!ossl_statem_client13_read_transition(s, mt))
@@ -234,6 +246,11 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
                 st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
                 return 1;
             }
+        } else {
+            if (mt == SSL3_MT_HELLO_RETRY_REQUEST) {
+                st->hand_state = TLS_ST_CR_HELLO_RETRY_REQUEST;
+                return 1;
+            }
         }
         break;
 
@@ -390,15 +407,23 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
      */
 
     /*
-     * Note: There are no cases for TLS_ST_BEFORE or TLS_ST_CW_CLNT_HELLO,
-     * because we haven't negotiated TLSv1.3 yet at that point. They are
-     * handled by ossl_statem_client_write_transition().
+     * Note: There are no cases for TLS_ST_BEFORE because we haven't negotiated
+     * TLSv1.3 yet at that point. They are handled by
+     * ossl_statem_client_write_transition().
      */
     switch (st->hand_state) {
     default:
         /* Shouldn't happen */
         return WRITE_TRAN_ERROR;
 
+    case TLS_ST_CW_CLNT_HELLO:
+        /* We only hit this in the case of HelloRetryRequest */
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_CR_HELLO_RETRY_REQUEST:
+        st->hand_state = TLS_ST_CW_CLNT_HELLO;
+        return WRITE_TRAN_CONTINUE;
+
     case TLS_ST_CR_FINISHED:
         st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
                                                     : TLS_ST_CW_FINISHED;
@@ -779,6 +804,9 @@ size_t ossl_statem_client_max_message_size(SSL *s)
     case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
         return HELLO_VERIFY_REQUEST_MAX_LENGTH;
 
+    case TLS_ST_CR_HELLO_RETRY_REQUEST:
+        return HELLO_RETRY_REQUEST_MAX_LENGTH;
+
     case TLS_ST_CR_CERT:
         return s->max_cert_list;
 
@@ -836,6 +864,9 @@ MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt)
     case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
         return dtls_process_hello_verify(s, pkt);
 
+    case TLS_ST_CR_HELLO_RETRY_REQUEST:
+        return tls_process_hello_retry_request(s, pkt);
+
     case TLS_ST_CR_CERT:
         return tls_process_server_certificate(s, pkt);
 
@@ -1432,6 +1463,52 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
     return MSG_PROCESS_ERROR;
 }
 
+static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
+{
+    unsigned int sversion;
+    int errorcode;
+    RAW_EXTENSION *extensions = NULL;
+    int al;
+    PACKET extpkt;
+
+    if (!PACKET_get_net_2(pkt, &sversion)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    s->hello_retry_request = 1;
+
+    /* This will fail if it doesn't choose TLSv1.3+ */
+    errorcode = ssl_choose_client_version(s, sversion);
+    if (errorcode != 0) {
+        al = SSL_AD_PROTOCOL_VERSION;
+        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, errorcode);
+        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);
+        goto f_err;
+    }
+
+    if (!tls_collect_extensions(s, &extpkt, EXT_TLS1_3_HELLO_RETRY_REQUEST,
+                                &extensions, &al)
+            || !tls_parse_all_extensions(s, EXT_TLS1_3_HELLO_RETRY_REQUEST,
+                                         extensions, NULL, 0, &al))
+        goto f_err;
+
+    OPENSSL_free(extensions);
+
+    return MSG_PROCESS_FINISHED_READING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    ossl_statem_set_error(s);
+    OPENSSL_free(extensions);
+    return MSG_PROCESS_ERROR;
+}
+
 MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
 {
     int al, i, ret = MSG_PROCESS_ERROR, exp_idx;
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 8e7245b..d7564e6 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -1434,21 +1434,22 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
 
     switch (server_version) {
     default:
+        if (!SSL_IS_TLS13(s)) {
+            if (version_cmp(s, client_version, s->version) < 0)
+                return SSL_R_WRONG_SSL_VERSION;
+            /*
+             * If this SSL handle is not from a version flexible method we don't
+             * (and never did) check min/max FIPS or Suite B constraints.  Hope
+             * that's OK.  It is up to the caller to not choose fixed protocol
+             * versions they don't want.  If not, then easy to fix, just return
+             * ssl_method_error(s, s->method)
+             */
+            return 0;
+        }
         /*
-         * TODO(TLS1.3): This check will fail if someone attempts to do
-         * renegotiation in TLS1.3 at the moment. We need to ensure we disable
-         * renegotiation for TLS1.3
-         */
-        if (version_cmp(s, client_version, s->version) < 0)
-            return SSL_R_WRONG_SSL_VERSION;
-        /*
-         * If this SSL handle is not from a version flexible method we don't
-         * (and never did) check min/max FIPS or Suite B constraints.  Hope
-         * that's OK.  It is up to the caller to not choose fixed protocol
-         * versions they don't want.  If not, then easy to fix, just return
-         * ssl_method_error(s, s->method)
+         * Fall through if we are TLSv1.3 already (this means we must be after
+         * a HelloRetryRequest
          */
-        return 0;
     case TLS_ANY_VERSION:
         table = tls_version_table;
         break;
@@ -1503,6 +1504,15 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
         }
 
         if (best_vers > 0) {
+            if (SSL_IS_TLS13(s)) {
+                /*
+                 * We get here if this is after a HelloRetryRequest. In this
+                 * case we just check that we still negotiated TLSv1.3
+                 */
+                if (best_vers != TLS1_3_VERSION)
+                    return SSL_R_UNSUPPORTED_PROTOCOL;
+                return 0;
+            }
             s->version = best_vers;
             s->method = best_method;
             return 0;
@@ -1585,6 +1595,9 @@ int ssl_choose_client_version(SSL *s, int version)
             continue;
         if (vent->cmeth == NULL)
             break;
+        if (s->hello_retry_request && version != TLS1_3_VERSION)
+            return SSL_R_WRONG_SSL_VERSION;
+
         method = vent->cmeth();
         err = ssl_method_error(s, method);
         if (err != 0)
@@ -1725,3 +1738,31 @@ int ssl_set_client_hello_version(SSL *s)
     s->client_version = ver_max;
     return 0;
 }
+
+/*
+ * Checks a list of |groups| to determine if the |group_id| is in it. If it is
+ * and |checkallow| is 1 then additionally check if the group is allowed to be
+ * used. Returns 1 if the group is in the list (and allowed if |checkallow| is
+ * 1) or 0 otherwise.
+ */
+int check_in_list(SSL *s, unsigned int group_id, const unsigned char *groups,
+                  size_t num_groups, int checkallow)
+{
+    size_t i;
+
+    if (groups == NULL || num_groups == 0)
+        return 0;
+
+    for (i = 0; i < num_groups; i++, groups += 2) {
+        unsigned int share_id = (groups[0] << 8) | (groups[1]);
+
+        if (group_id == share_id
+                && (!checkallow
+                    || tls_curve_allowed(s, groups, SSL_SECOP_CURVE_CHECK))) {
+            break;
+        }
+    }
+
+    /* If i == num_groups then not in the list */
+    return i < num_groups;
+}
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index cb6457f..fa13a26 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -19,6 +19,7 @@
 /* The spec allows for a longer length than this, but we limit it */
 #define HELLO_VERIFY_REQUEST_MAX_LENGTH 258
 #define SERVER_HELLO_MAX_LENGTH         20000
+#define HELLO_RETRY_REQUEST_MAX_LENGTH  20000
 #define ENCRYPTED_EXTENSIONS_MAX_LENGTH 20000
 #define SERVER_KEY_EXCH_MAX_LENGTH      102400
 #define SERVER_HELLO_DONE_MAX_LENGTH    0
@@ -68,6 +69,9 @@ int statem_flush(SSL *s);
 
 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);
+
 /*
  * TLS/DTLS client state machine functions
  */
@@ -173,161 +177,180 @@ __owur int tls_psk_do_binder(SSL *s, const EVP_MD *md,
                              SSL_SESSION *sess, int sign);
 
 /* Server Extension processing */
-int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                               int *al);
-int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                               int *al);
+int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx, int *al);
+int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_SRP
-int tls_parse_ctos_srp(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+int tls_parse_ctos_srp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_EC
-int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al);
-int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, X509 *x,
-                                    size_t chainidx, int *al);
+int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al);
+int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, unsigned int context,
+                                    X509 *x, size_t chainidx, int *al);
 #endif
-int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                  int *al);
-int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                            int *al);
+int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
+int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al);
 #ifndef OPENSSL_NO_OCSP
-int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                  int *al);
+int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_parse_ctos_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+int tls_parse_ctos_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
 #endif
-int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx, int *al);
 #ifndef OPENSSL_NO_SRTP
-int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                            int *al);
+int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al);
 #endif
-int tls_parse_ctos_etm(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
-int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                             int *al);
-int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
-int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al);
-int tls_parse_ctos_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+int tls_parse_ctos_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
+int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                             size_t chainidx, int *al);
+int tls_parse_ctos_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
+int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al);
+int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
 
-int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, X509 *x,
-                                   size_t chainidx, int *al);
-int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, X509 *x,
-                                   size_t chainidx, int *al);
+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);
 #ifndef OPENSSL_NO_EC
-int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, X509 *x,
-                                     size_t chainidx, int *al);
+int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx, int *al);
 #endif
-int tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_stoc_session_ticket(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
                                       size_t chainidx, int *al);
 #ifndef OPENSSL_NO_OCSP
-int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_stoc_status_request(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
                                       size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
                                       size_t chainidx, int *al);
 #endif
-int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                            int *al);
+int tls_construct_stoc_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al);
 #ifndef OPENSSL_NO_SRTP
-int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                int *al);
+int tls_construct_stoc_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx, int *al);
 #endif
-int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al);
-int tls_construct_stoc_ems(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al);
-int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al);
+int tls_construct_stoc_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al);
+int tls_construct_stoc_ems(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al);
+int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al);
 /*
  * Not in public headers as this is not an official extension. Only used when
  * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set.
  */
 #define TLSEXT_TYPE_cryptopro_bug      0xfde8
-int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, X509 *x,
-                                     size_t chainidx, int *al);
-int tls_construct_stoc_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al);
+int tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx, int *al);
+int tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al);
 
 /* Client Extension processing */
-int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, X509 *x,
-                                   size_t chainidx, int *al);
-int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, X509 *x,
-                                   size_t chainidx, int *al);
+int tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx, int *al);
+int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, unsigned int context,
+                                   X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_SRP
-int tls_construct_ctos_srp(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                   int *al);
+int tls_construct_ctos_srp(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_EC
-int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, X509 *x,
-                                     size_t chainidx, int *al);
-int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_ctos_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx, int *al);
+int tls_construct_ctos_supported_groups(SSL *s, WPACKET *pkt,
+                                        unsigned int context, X509 *x,
                                         size_t chainidx, int *al);
 #endif
-int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
                                       size_t chainidx, int *al);
-int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                int *al);
+int tls_construct_ctos_sig_algs(SSL *s, WPACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_OCSP
-int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt,
+                                      unsigned int context, X509 *x,
                                       size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al);
+int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al);
 #endif
-int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                            int *al);
+int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al);
 #ifndef OPENSSL_NO_SRTP
-int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                int *al);
+int tls_construct_ctos_use_srtp(SSL *s, WPACKET *pkt, unsigned int context,
+                                X509 *x, size_t chainidx, int *al);
 #endif
-int tls_construct_ctos_etm(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al);
+int tls_construct_ctos_etm(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al);
 #ifndef OPENSSL_NO_CT
-int tls_construct_ctos_sct(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al);
+int tls_construct_ctos_sct(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al);
 #endif
-int tls_construct_ctos_ems(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al);
-int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt, X509 *x,
+int tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al);
+int tls_construct_ctos_supported_versions(SSL *s, WPACKET *pkt,
+                                          unsigned int context, X509 *x,
                                           size_t chainidx, int *al);
-int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al);
-int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, X509 *x,
-                                     size_t chainidx, int *al);
-int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                               int *al);
-int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
-                           int *al);
-int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                               int *al);
-int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                               int *al);
+int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al);
+int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, unsigned int context,
+                                     X509 *x, size_t chainidx, int *al);
+int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, unsigned int context,
+                               X509 *x, size_t chainidx, int *al);
+int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
+                           size_t chainidx, int *al);
+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);
 #ifndef OPENSSL_NO_EC
-int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                 int *al);
+int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, unsigned int context,
+                                 X509 *x, size_t chainidx, int *al);
 #endif
-int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                  int *al);
+int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
 #ifndef OPENSSL_NO_OCSP
-int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                                  int *al);
+int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, unsigned int context,
+                                  X509 *x, size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_CT
-int tls_parse_stoc_sct(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+int tls_parse_stoc_sct(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
 #endif
 #ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_parse_stoc_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+int tls_parse_stoc_npn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
 #endif
-int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                        size_t chainidx, int *al);
 #ifndef OPENSSL_NO_SRTP
-int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                            int *al);
+int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                            size_t chainidx, int *al);
 #endif
-int tls_parse_stoc_etm(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
-int tls_parse_stoc_ems(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
-int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
-                             int *al);
-int tls_parse_stoc_psk(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al);
+int tls_parse_stoc_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
+int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
+int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                             size_t chainidx, int *al);
+int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+                       size_t chainidx, int *al);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index de0fcc0..93ba63e 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -62,6 +62,7 @@
 #include <openssl/md5.h>
 
 static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt);
+static int tls_construct_hello_retry_request(SSL *s, WPACKET *pkt);
 static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
                                                       PACKET *cipher_suites,
                                                       STACK_OF(SSL_CIPHER)
@@ -82,11 +83,6 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
     OSSL_STATEM *st = &s->statem;
 
     /*
-     * TODO(TLS1.3): This is still based on the TLSv1.2 state machine. Over time
-     * we will update this to look more like real TLSv1.3
-     */
-
-    /*
      * Note: There is no case for TLS_ST_BEFORE because at that stage we have
      * not negotiated TLSv1.3 yet, so that case is handled by
      * ossl_statem_server_read_transition()
@@ -95,6 +91,13 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
     default:
         break;
 
+    case TLS_ST_SW_HELLO_RETRY_REQUEST:
+        if (mt == SSL3_MT_CLIENT_HELLO) {
+            st->hand_state = TLS_ST_SR_CLNT_HELLO;
+            return 1;
+        }
+        break;
+
     case TLS_ST_SW_FINISHED:
         if (s->s3->tmp.cert_request) {
             if (mt == SSL3_MT_CERTIFICATE) {
@@ -406,9 +409,15 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
         return WRITE_TRAN_ERROR;
 
     case TLS_ST_SR_CLNT_HELLO:
-        st->hand_state = TLS_ST_SW_SRVR_HELLO;
+        if (s->hello_retry_request)
+            st->hand_state = TLS_ST_SW_HELLO_RETRY_REQUEST;
+        else
+            st->hand_state = TLS_ST_SW_SRVR_HELLO;
         return WRITE_TRAN_CONTINUE;
 
+    case TLS_ST_SW_HELLO_RETRY_REQUEST:
+        return WRITE_TRAN_FINISHED;
+
     case TLS_ST_SW_SRVR_HELLO:
         st->hand_state = TLS_ST_SW_ENCRYPTED_EXTENSIONS;
         return WRITE_TRAN_CONTINUE;
@@ -693,6 +702,11 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
         /* No post work to be done */
         break;
 
+    case TLS_ST_SW_HELLO_RETRY_REQUEST:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        break;
+
     case TLS_ST_SW_HELLO_REQ:
         if (statem_flush(s) != 1)
             return WORK_MORE_A;
@@ -904,6 +918,11 @@ int ossl_statem_server_construct_message(SSL *s, WPACKET *pkt,
         *confunc = tls_construct_encrypted_extensions;
         *mt = SSL3_MT_ENCRYPTED_EXTENSIONS;
         break;
+
+    case TLS_ST_SW_HELLO_RETRY_REQUEST:
+        *confunc = tls_construct_hello_retry_request;
+        *mt = SSL3_MT_HELLO_RETRY_REQUEST;
+        break;
     }
 
     return 1;
@@ -1200,6 +1219,12 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
     if (clienthello.isv2) {
         unsigned int mt;
 
+        if (!SSL_IS_FIRST_HANDSHAKE(s) || s->hello_retry_request) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNEXPECTED_MESSAGE);
+            goto f_err;
+        }
+
         /*-
          * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2
          * header is sent directly on the wire, not wrapped as a TLS
@@ -1402,7 +1427,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
 
     if (protverr) {
         SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr);
-        if ((!s->enc_write_ctx && !s->write_hash)) {
+        if (SSL_IS_FIRST_HANDSHAKE(s)) {
             /* like ssl3_get_record, send alert using remote version number */
             s->version = s->client_version = clienthello.legacy_version;
         }
@@ -1817,13 +1842,6 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
             s->s3->tmp.new_cipher = s->session->cipher;
         }
 
-        if (!(s->verify_mode & SSL_VERIFY_PEER)) {
-            if (!ssl3_digest_cached_records(s, 0)) {
-                al = SSL_AD_INTERNAL_ERROR;
-                goto f_err;
-            }
-        }
-
         /*-
          * we now have the following setup.
          * client_random
@@ -1950,6 +1968,12 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt)
         goto err;
     }
 
+    if (!(s->verify_mode & SSL_VERIFY_PEER)
+            && !ssl3_digest_cached_records(s, 0)) {
+        al = SSL_AD_INTERNAL_ERROR;
+        goto err;
+    }
+
     return 1;
  err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
@@ -3502,6 +3526,10 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
         return NULL;
     }
 
+    OPENSSL_free(s->s3->tmp.ciphers_raw);
+    s->s3->tmp.ciphers_raw = NULL;
+    s->s3->tmp.ciphers_rawlen = 0;
+
     if (sslv2format) {
         size_t numciphers = PACKET_remaining(cipher_suites) / n;
         PACKET sslv2ciphers = *cipher_suites;
@@ -3607,3 +3635,27 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
     sk_SSL_CIPHER_free(sk);
     return NULL;
 }
+
+static int tls_construct_hello_retry_request(SSL *s, WPACKET *pkt)
+{
+    int al = SSL_AD_INTERNAL_ERROR;
+
+    /*
+     * TODO(TLS1.3): Remove the DRAFT version before release
+     * (should be s->version)
+     */
+    if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)
+            || !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;
+    }
+
+    /* Ditch the session. We'll create a new one next time around */
+    SSL_SESSION_free(s->session);
+    s->session = NULL;
+    s->hit = 0;
+
+    return 1;
+}
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index 9da8f75..5561e8f 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -83,16 +83,17 @@ static ssl_trace_tbl ssl_handshake_tbl[] = {
     {SSL3_MT_SERVER_HELLO, "ServerHello"},
     {DTLS1_MT_HELLO_VERIFY_REQUEST, "HelloVerifyRequest"},
     {SSL3_MT_NEWSESSION_TICKET, "NewSessionTicket"},
+    {SSL3_MT_HELLO_RETRY_REQUEST, "HelloRetryRequest"},
+    {SSL3_MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions"},
     {SSL3_MT_CERTIFICATE, "Certificate"},
     {SSL3_MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange"},
     {SSL3_MT_CERTIFICATE_REQUEST, "CertificateRequest"},
-    {SSL3_MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange"},
-    {SSL3_MT_CERTIFICATE_STATUS, "CertificateStatus"},
     {SSL3_MT_SERVER_DONE, "ServerHelloDone"},
     {SSL3_MT_CERTIFICATE_VERIFY, "CertificateVerify"},
     {SSL3_MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange"},
+    {SSL3_MT_CERTIFICATE_STATUS, "CertificateStatus"},
+    {SSL3_MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange"},
     {SSL3_MT_FINISHED, "Finished"},
-    {SSL3_MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions"},
     {SSL3_MT_CERTIFICATE_STATUS, "CertificateStatus"}
 };
 
@@ -650,7 +651,8 @@ static int ssl_print_signature(BIO *bio, int indent, SSL *s,
     return ssl_print_hexbuf(bio, indent, "Signature", 2, pmsg, pmsglen);
 }
 
-static int ssl_print_extension(BIO *bio, int indent, int server, int extype,
+static int ssl_print_extension(BIO *bio, int indent, int server,
+                               unsigned char mt, int extype,
                                const unsigned char *ext, size_t extlen)
 {
     size_t xlen, share_len;
@@ -729,6 +731,17 @@ static int ssl_print_extension(BIO *bio, int indent, int server, int extype,
         break;
 
     case TLSEXT_TYPE_key_share:
+        if (mt == SSL3_MT_HELLO_RETRY_REQUEST) {
+            int group_id;
+
+            if (extlen != 2)
+                return 0;
+            group_id = (ext[0] << 8) | ext[1];
+            BIO_indent(bio, indent + 4, 80);
+            BIO_printf(bio, "NamedGroup: %s\n",
+                       ssl_trace_str(group_id, ssl_groups_tbl));
+            break;
+        }
         if (extlen < 2)
             return 0;
         if (server) {
@@ -782,7 +795,8 @@ static int ssl_print_extension(BIO *bio, int indent, int server, int extype,
 }
 
 static int ssl_print_extensions(BIO *bio, int indent, int server,
-                                const unsigned char **msgin, size_t *msginlen)
+                                unsigned char mt, const unsigned char **msgin,
+                                size_t *msginlen)
 {
     size_t extslen, msglen = *msginlen;
     const unsigned char *msg = *msgin;
@@ -808,7 +822,8 @@ static int ssl_print_extensions(BIO *bio, int indent, int server,
         if (msglen < extlen + 4)
             return 0;
         msg += 4;
-        if (!ssl_print_extension(bio, indent + 2, server, extype, msg, extlen))
+        if (!ssl_print_extension(bio, indent + 2, server, mt, extype, msg,
+                                 extlen))
             return 0;
         msg += extlen;
         msglen -= extlen + 4;
@@ -869,7 +884,8 @@ static int ssl_print_client_hello(BIO *bio, SSL *ssl, int indent,
         msglen--;
         len--;
     }
-    if (!ssl_print_extensions(bio, indent, 0, &msg, &msglen))
+    if (!ssl_print_extensions(bio, indent, 0, SSL3_MT_CLIENT_HELLO, &msg,
+                              &msglen))
         return 0;
     return 1;
 }
@@ -914,7 +930,8 @@ static int ssl_print_server_hello(BIO *bio, int indent,
         msg++;
         msglen--;
     }
-    if (!ssl_print_extensions(bio, indent, 1, &msg, &msglen))
+    if (!ssl_print_extensions(bio, indent, 1, SSL3_MT_SERVER_HELLO, &msg,
+                              &msglen))
         return 0;
     return 1;
 }
@@ -1130,7 +1147,8 @@ static int ssl_print_certificates(BIO *bio, SSL *s, int server, int indent,
     while (clen > 0) {
         if (!ssl_print_certificate(bio, indent + 2, &msg, &clen))
             return 0;
-        if (!ssl_print_extensions(bio, indent + 2, server, &msg, &clen))
+        if (!ssl_print_extensions(bio, indent + 2, server, SSL3_MT_CERTIFICATE,
+                                  &msg, &clen))
             return 0;
 
     }
@@ -1318,8 +1336,18 @@ static int ssl_print_handshake(BIO *bio, SSL *ssl, int server,
             return 0;
         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))
+            return 0;
+        break;
+
     case SSL3_MT_ENCRYPTED_EXTENSIONS:
-        if (!ssl_print_extensions(bio, indent + 2, 1, &msg, &msglen))
+        if (!ssl_print_extensions(bio, indent + 2, 1,
+                                  SSL3_MT_ENCRYPTED_EXTENSIONS, &msg, &msglen))
             return 0;
         break;
 
diff --git a/test/recipes/70-test_key_share.t b/test/recipes/70-test_key_share.t
index b0f8c09..e5212d4 100755
--- a/test/recipes/70-test_key_share.t
+++ b/test/recipes/70-test_key_share.t
@@ -69,79 +69,89 @@ my $proxy = TLSProxy::Proxy->new(
 #We assume that test_ssl_new and friends will test the happy path for this,
 #so we concentrate on the less common scenarios
 
-#Test 1: An empty key_shares extension should not succeed
+#Test 1: An empty key_shares extension should succeed after a HelloRetryRequest
 $testtype = EMPTY_EXTENSION;
 $direction = CLIENT_TO_SERVER;
 $proxy->filter(\&modify_key_shares_filter);
+$proxy->serverflags("-curves P-256");
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 19;
-#TODO(TLS1.3): Actually this should succeed after a HelloRetryRequest - but
-#we've not implemented that yet, so for now we look for a fail
-ok(TLSProxy::Message->fail(), "Empty key_shares");
+plan tests => 21;
+ok(TLSProxy::Message->success(), "Success after HRR");
 
-#Test 2: A missing key_shares extension should not succeed
+#Test 2: The server sending an HRR requesting a group the client already sent
+#        should fail
+$proxy->clear();
+$proxy->start();
+ok(TLSProxy::Message->fail(), "Server asks for group already provided");
+
+#Test 3: A missing key_shares extension should not succeed
 $proxy->clear();
 $testtype = MISSING_EXTENSION;
 $proxy->start();
-#TODO(TLS1.3): As above this should really succeed after a HelloRetryRequest,
-#but we look for fail for now
 ok(TLSProxy::Message->fail(), "Missing key_shares extension");
 
-#Test 3: No acceptable key_shares should fail
+#Test 4: No initial acceptable key_shares should succeed after a
+#        HelloRetryRequest
 $proxy->clear();
-$testtype = NO_ACCEPTABLE_KEY_SHARES;
+$proxy->filter(undef);
+$proxy->serverflags("-curves P-256");
 $proxy->start();
-#TODO(TLS1.3): Again this should go around the loop of a HelloRetryRequest but
-#we fail for now
-ok(TLSProxy::Message->fail(), "No acceptable key_shares");
+ok(TLSProxy::Message->success(), "No initial acceptable key_shares");
 
-#Test 4: A non preferred but acceptable key_share should succeed
+#Test 5: No acceptable key_shares and no shared groups should fail
 $proxy->clear();
 $proxy->filter(undef);
+$proxy->serverflags("-curves P-256");
+$proxy->clientflags("-curves P-384");
+$proxy->start();
+ok(TLSProxy::Message->fail(), "No acceptable key_shares");
+
+#Test 6: A non preferred but acceptable key_share should succeed
+$proxy->clear();
 $proxy->clientflags("-curves P-256");
 $proxy->start();
 ok(TLSProxy::Message->success(), "Non preferred key_share");
 $proxy->filter(\&modify_key_shares_filter);
 
-#Test 5: An acceptable key_share after a list of non-acceptable ones should
+#Test 7: An acceptable key_share after a list of non-acceptable ones should
 #succeed
 $proxy->clear();
 $testtype = ACCEPTABLE_AT_END;
 $proxy->start();
 ok(TLSProxy::Message->success(), "Acceptable key_share at end of list");
 
-#Test 6: An acceptable key_share but for a group not in supported_groups should
+#Test 8: An acceptable key_share but for a group not in supported_groups should
 #fail
 $proxy->clear();
 $testtype = NOT_IN_SUPPORTED_GROUPS;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "Acceptable key_share not in supported_groups");
 
-#Test 7: Too short group_id should fail
+#Test 9: Too short group_id should fail
 $proxy->clear();
 $testtype = GROUP_ID_TOO_SHORT;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "Group id too short");
 
-#Test 8: key_exchange length mismatch should fail
+#Test 10: key_exchange length mismatch should fail
 $proxy->clear();
 $testtype = KEX_LEN_MISMATCH;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "key_exchange length mismatch");
 
-#Test 9: Zero length key_exchange should fail
+#Test 11: Zero length key_exchange should fail
 $proxy->clear();
 $testtype = ZERO_LEN_KEX_DATA;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "zero length key_exchange data");
 
-#Test 10: Trailing data on key_share list should fail
+#Test 12: Trailing data on key_share list should fail
 $proxy->clear();
 $testtype = TRAILING_DATA;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "key_share list trailing data");
 
-#Test 11: Multiple acceptable key_shares - we choose the first one
+#Test 13: Multiple acceptable key_shares - we choose the first one
 $proxy->clear();
 $direction = SERVER_TO_CLIENT;
 $testtype = LOOK_ONLY;
@@ -150,45 +160,45 @@ $proxy->start();
 ok(TLSProxy::Message->success() && ($selectedgroupid == P_256),
    "Multiple acceptable key_shares");
 
-#Test 12: Multiple acceptable key_shares - we choose the first one (part 2)
+#Test 14: Multiple acceptable key_shares - we choose the first one (part 2)
 $proxy->clear();
 $proxy->clientflags("-curves X25519:P-256");
 $proxy->start();
 ok(TLSProxy::Message->success() && ($selectedgroupid == X25519),
    "Multiple acceptable key_shares (part 2)");
 
-#Test 13: Server sends key_share that wasn't offerred should fail
+#Test 15: Server sends key_share that wasn't offerred should fail
 $proxy->clear();
 $testtype = SELECT_X25519;
 $proxy->clientflags("-curves P-256");
 $proxy->start();
 ok(TLSProxy::Message->fail(), "Non offered key_share");
 
-#Test 14: Too short group_id in ServerHello should fail
+#Test 16: Too short group_id in ServerHello should fail
 $proxy->clear();
 $testtype = GROUP_ID_TOO_SHORT;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "Group id too short in ServerHello");
 
-#Test 15: key_exchange length mismatch in ServerHello should fail
+#Test 17: key_exchange length mismatch in ServerHello should fail
 $proxy->clear();
 $testtype = KEX_LEN_MISMATCH;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "key_exchange length mismatch in ServerHello");
 
-#Test 16: Zero length key_exchange in ServerHello should fail
+#Test 18: Zero length key_exchange in ServerHello should fail
 $proxy->clear();
 $testtype = ZERO_LEN_KEX_DATA;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "zero length key_exchange data in ServerHello");
 
-#Test 17: Trailing data on key_share in ServerHello should fail
+#Test 19: Trailing data on key_share in ServerHello should fail
 $proxy->clear();
 $testtype = TRAILING_DATA;
 $proxy->start();
 ok(TLSProxy::Message->fail(), "key_share trailing data in ServerHello");
 
-#Test 18: key_share should not be sent if the client is not capable of
+#Test 20: key_share should not be sent if the client is not capable of
 #         negotiating TLSv1.3
 $proxy->clear();
 $proxy->filter(undef);
@@ -200,7 +210,7 @@ ok(TLSProxy::Message->success()
    "No key_share for TLS<=1.2 client");
 $proxy->filter(\&modify_key_shares_filter);
 
-#Test 19: A server not capable of negotiating TLSv1.3 should not attempt to
+#Test 21: A server not capable of negotiating TLSv1.3 should not attempt to
 #         process a key_share
 $proxy->clear();
 $direction = CLIENT_TO_SERVER;
@@ -288,8 +298,10 @@ sub modify_key_shares_filter
                     0x00; #Trailing garbage
             }
 
-            $message->set_extension(
-                TLSProxy::Message::EXT_SUPPORTED_GROUPS, $suppgroups);
+            if ($testtype != EMPTY_EXTENSION) {
+                $message->set_extension(
+                    TLSProxy::Message::EXT_SUPPORTED_GROUPS, $suppgroups);
+            }
 
             if ($testtype == MISSING_EXTENSION) {
                 $message->delete_extension(
diff --git a/test/recipes/70-test_tls13kexmodes.t b/test/recipes/70-test_tls13kexmodes.t
index 9383519..07020c6 100755
--- a/test/recipes/70-test_tls13kexmodes.t
+++ b/test/recipes/70-test_tls13kexmodes.t
@@ -35,6 +35,10 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
 @handmessages = (
     [TLSProxy::Message::MT_CLIENT_HELLO,
         checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_HELLO_RETRY_REQUEST,
+        checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE],
+    [TLSProxy::Message::MT_CLIENT_HELLO,
+        checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE],
     [TLSProxy::Message::MT_SERVER_HELLO,
         checkhandshake::ALL_HANDSHAKES],
     [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS,
@@ -42,9 +46,9 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
     [TLSProxy::Message::MT_CERTIFICATE_REQUEST,
         checkhandshake::CLIENT_AUTH_HANDSHAKE],
     [TLSProxy::Message::MT_CERTIFICATE,
-        checkhandshake::ALL_HANDSHAKES & ~checkhandshake::RESUME_HANDSHAKE],
+        checkhandshake::ALL_HANDSHAKES & ~(checkhandshake::RESUME_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE)],
     [TLSProxy::Message::MT_CERTIFICATE_VERIFY,
-        checkhandshake::ALL_HANDSHAKES & ~checkhandshake::RESUME_HANDSHAKE],
+        checkhandshake::ALL_HANDSHAKES & ~(checkhandshake::RESUME_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE)],
     [TLSProxy::Message::MT_FINISHED,
         checkhandshake::ALL_HANDSHAKES],
     [TLSProxy::Message::MT_CERTIFICATE,
@@ -86,6 +90,30 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
         checkhandshake::PSK_CLI_EXTENSION],
 
+    [TLSProxy::Message::MT_HELLO_RETRY_REQUEST, TLSProxy::Message::EXT_KEY_SHARE,
+        checkhandshake::KEY_SHARE_HRR_EXTENSION],
+
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME,
+        checkhandshake::SERVER_NAME_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST,
+        checkhandshake::STATUS_REQUEST_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN,
+        checkhandshake::ALPN_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT,
+        checkhandshake::SCT_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK_KEX_MODES,
+        checkhandshake::PSK_KEX_MODES_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
+        checkhandshake::PSK_CLI_EXTENSION],
+
     [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
         checkhandshake::KEY_SHARE_SRV_EXTENSION],
     [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_PSK,
@@ -117,7 +145,7 @@ 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 => 7;
+plan tests => 11;
 ok(TLSProxy::Message->success(), "Initial connection");
 
 #Test 2: Attempt a resume with no kex modes extension. Should not resume
@@ -192,6 +220,62 @@ checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
                | checkhandshake::PSK_SRV_EXTENSION,
                "Resume with non-dhe kex mode");
 
+#Test 8: Attempt a resume with both non-dhe and dhe kex mode, but unacceptable
+#        initial key_share. Should resume with a key_share following an HRR
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+$proxy->serverflags("-curves P-256");
+$testtype = BOTH_KEX_MODES;
+$proxy->start();
+checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::PSK_KEX_MODES_EXTENSION
+               | checkhandshake::KEY_SHARE_SRV_EXTENSION
+               | checkhandshake::KEY_SHARE_HRR_EXTENSION
+               | checkhandshake::PSK_CLI_EXTENSION
+               | checkhandshake::PSK_SRV_EXTENSION,
+               "Resume with both kex modes and HRR");
+
+#Test 9: Attempt a resume with dhe kex mode only and an unnacceptable initial
+#        key_share. Should resume with a key_share following an HRR
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+$proxy->serverflags("-curves P-256");
+$testtype = DHE_KEX_MODE_ONLY;
+$proxy->start();
+checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::PSK_KEX_MODES_EXTENSION
+               | checkhandshake::KEY_SHARE_SRV_EXTENSION
+               | checkhandshake::KEY_SHARE_HRR_EXTENSION
+               | checkhandshake::PSK_CLI_EXTENSION
+               | checkhandshake::PSK_SRV_EXTENSION,
+               "Resume with dhe kex mode and HRR");
+
+#Test 10: Attempt a resume with both non-dhe and dhe kex mode, unacceptable
+#         initial key_share and no overlapping groups. Should resume without a
+#         key_share
+$proxy->clear();
+$proxy->clientflags("-curves P-384 -sess_in ".$session);
+$proxy->serverflags("-curves P-256");
+$testtype = BOTH_KEX_MODES;
+$proxy->start();
+checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::PSK_KEX_MODES_EXTENSION
+               | checkhandshake::PSK_CLI_EXTENSION
+               | checkhandshake::PSK_SRV_EXTENSION,
+               "Resume with both kex modes, no overlapping groups");
+
+#Test 11: Attempt a resume with dhe kex mode only, unacceptable
+#         initial key_share and no overlapping groups. Should fail
+$proxy->clear();
+$proxy->clientflags("-curves P-384 -sess_in ".$session);
+$proxy->serverflags("-curves P-256");
+$testtype = DHE_KEX_MODE_ONLY;
+$proxy->start();
+ok(TLSProxy::Message->fail(), "Resume with dhe kex mode, no overlapping groups");
+
 unlink $session;
 
 sub modify_kex_modes_filter
diff --git a/test/recipes/70-test_tls13messages.t b/test/recipes/70-test_tls13messages.t
index 609a4f4..0d25bef 100755
--- a/test/recipes/70-test_tls13messages.t
+++ b/test/recipes/70-test_tls13messages.t
@@ -35,6 +35,10 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
 @handmessages = (
     [TLSProxy::Message::MT_CLIENT_HELLO,
         checkhandshake::ALL_HANDSHAKES],
+    [TLSProxy::Message::MT_HELLO_RETRY_REQUEST,
+        checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE],
+    [TLSProxy::Message::MT_CLIENT_HELLO,
+        checkhandshake::HRR_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE],
     [TLSProxy::Message::MT_SERVER_HELLO,
         checkhandshake::ALL_HANDSHAKES],
     [TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS,
@@ -42,9 +46,9 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
     [TLSProxy::Message::MT_CERTIFICATE_REQUEST,
         checkhandshake::CLIENT_AUTH_HANDSHAKE],
     [TLSProxy::Message::MT_CERTIFICATE,
-        checkhandshake::ALL_HANDSHAKES & ~checkhandshake::RESUME_HANDSHAKE],
+        checkhandshake::ALL_HANDSHAKES & ~(checkhandshake::RESUME_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE)],
     [TLSProxy::Message::MT_CERTIFICATE_VERIFY,
-        checkhandshake::ALL_HANDSHAKES & ~checkhandshake::RESUME_HANDSHAKE],
+        checkhandshake::ALL_HANDSHAKES & ~(checkhandshake::RESUME_HANDSHAKE | checkhandshake::HRR_RESUME_HANDSHAKE)],
     [TLSProxy::Message::MT_FINISHED,
         checkhandshake::ALL_HANDSHAKES],
     [TLSProxy::Message::MT_CERTIFICATE,
@@ -86,6 +90,30 @@ $ENV{CTLOG_FILE} = srctop_file("test", "ct", "log_list.conf");
     [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
         checkhandshake::PSK_CLI_EXTENSION],
 
+    [TLSProxy::Message::MT_HELLO_RETRY_REQUEST, TLSProxy::Message::EXT_KEY_SHARE,
+        checkhandshake::KEY_SHARE_HRR_EXTENSION],
+
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SERVER_NAME,
+        checkhandshake::SERVER_NAME_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_STATUS_REQUEST,
+        checkhandshake::STATUS_REQUEST_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_GROUPS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SIG_ALGS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_ALPN,
+        checkhandshake::ALPN_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SCT,
+        checkhandshake::SCT_CLI_EXTENSION],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_SUPPORTED_VERSIONS,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK_KEX_MODES,
+        checkhandshake::DEFAULT_EXTENSIONS],
+    [TLSProxy::Message::MT_CLIENT_HELLO, TLSProxy::Message::EXT_PSK,
+        checkhandshake::PSK_CLI_EXTENSION],
+
     [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_KEY_SHARE,
         checkhandshake::DEFAULT_EXTENSIONS],
     [TLSProxy::Message::MT_SERVER_HELLO, TLSProxy::Message::EXT_PSK,
@@ -115,7 +143,7 @@ $proxy->serverconnects(2);
 $proxy->clientflags("-sess_out ".$session);
 $proxy->sessionfile($session);
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 13;
+plan tests => 15;
 checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
                checkhandshake::DEFAULT_EXTENSIONS,
                "Default handshake test");
@@ -129,7 +157,6 @@ checkhandshake($proxy, checkhandshake::RESUME_HANDSHAKE,
                | checkhandshake::PSK_CLI_EXTENSION
                | checkhandshake::PSK_SRV_EXTENSION,
                "Resumption handshake test");
-unlink $session;
 
 #Test 3: A status_request handshake (client request only)
 $proxy->clear();
@@ -248,3 +275,25 @@ checkhandshake($proxy, checkhandshake::DEFAULT_HANDSHAKE,
                | checkhandshake::STATUS_REQUEST_CLI_EXTENSION
                | checkhandshake::STATUS_REQUEST_SRV_EXTENSION,
                "SCT handshake test");
+
+#Test 14: HRR Handshake
+$proxy->clear();
+$proxy->serverflags("-curves P-256");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::HRR_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::KEY_SHARE_HRR_EXTENSION,
+               "HRR handshake test");
+
+#Test 15: Resumption handshake with HRR
+$proxy->clear();
+$proxy->clientflags("-sess_in ".$session);
+$proxy->serverflags("-curves P-256");
+$proxy->start();
+checkhandshake($proxy, checkhandshake::HRR_RESUME_HANDSHAKE,
+               checkhandshake::DEFAULT_EXTENSIONS
+               | checkhandshake::KEY_SHARE_HRR_EXTENSION
+               | checkhandshake::PSK_CLI_EXTENSION
+               | checkhandshake::PSK_SRV_EXTENSION,
+               "Resumption handshake with HRR test");
+unlink $session;
diff --git a/test/testlib/checkhandshake.pm b/test/testlib/checkhandshake.pm
index 44f7b1a..43efe81 100644
--- a/test/testlib/checkhandshake.pm
+++ b/test/testlib/checkhandshake.pm
@@ -24,8 +24,10 @@ use constant {
     RENEG_HANDSHAKE => 16,
     NPN_HANDSHAKE => 32,
     EC_HANDSHAKE => 64,
+    HRR_HANDSHAKE => 128,
+    HRR_RESUME_HANDSHAKE => 256,
 
-    ALL_HANDSHAKES => 127
+    ALL_HANDSHAKES => 511
 };
 
 use constant {
@@ -49,7 +51,8 @@ use constant {
     PSK_CLI_EXTENSION => 0x00008000,
     PSK_SRV_EXTENSION => 0x00010000,
     KEY_SHARE_SRV_EXTENSION => 0x00020000,
-    PSK_KEX_MODES_EXTENSION => 0x00040000
+    PSK_KEX_MODES_EXTENSION => 0x00040000,
+    KEY_SHARE_HRR_EXTENSION => 0x00080000
 };
 
 our @handmessages = ();
@@ -66,34 +69,51 @@ sub checkhandshake($$$$)
         my $clienthelloseen = 0;
 
         #First count the number of tests
+        my $nextmess = 0;
+        my $message = undef;
+        my $chnum = 0;
         for ($numtests = 0; $handmessages[$loop][1] != 0; $loop++) {
-            $numtests++ if (($handmessages[$loop][1] & $handtype) != 0);
-        }
+            next if (($handmessages[$loop][1] & $handtype) == 0);
+            if (scalar @{$proxy->message_list} > $nextmess) {
+                $message = ${$proxy->message_list}[$nextmess];
+                $nextmess++;
+            } else {
+                $message = undef;
+            }
+            $numtests++;
 
-        #Add number of extensions we check plus 2 for the number of messages
-        #that contain extensions
-        $numtests += $#extensions + 2;
-        #In a renegotiation we will have double the number of extension tests
-        if (($handtype & RENEG_HANDSHAKE) != 0) {
-            $numtests += $#extensions + 2;
+            next if (!defined $message);
+            $chnum = 1 if $message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
+                          && TLSProxy::Proxy::is_tls13();
+            next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
+                    && $message->mt() != TLSProxy::Message::MT_HELLO_RETRY_REQUEST
+                    && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO
+                    && $message->mt() !=
+                       TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS
+                    && $message->mt() != TLSProxy::Message::MT_CERTIFICATE);
+
+            next if $message->mt() == TLSProxy::Message::MT_CERTIFICATE
+                    && !TLSProxy::Proxy::is_tls13();
+
+            my $extchnum = 0;
+            for (my $extloop = 0;
+                    $extensions[$extloop][2] != 0;
+                    $extloop++) {
+                $extchnum = 1 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO
+                                 && TLSProxy::Proxy::is_tls13();
+                next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO
+                                 && $extchnum != $chnum;
+                next if ($message->mt() != $extensions[$extloop][0]);
+                $numtests++;
+            }
+            $numtests++;
         }
-        #In TLS1.3 there are 4 messages with extensions (i.e. 2 extra) and no
-        #renegotiations: 1 ClientHello, 1 ServerHello, 1 EncryptedExtensions,
-        #1 Certificate
-        $numtests += 2 if ($proxy->is_tls13());
-        #Except in Client auth where we have an extra Certificate message, and
-        #one extension gets checked twice (once in each Certificate message)
-        $numtests += 2 if ($proxy->is_tls13()
-                          && ($handtype & CLIENT_AUTH_HANDSHAKE) != 0);
-        #And in a resumption handshake we don't get Certificate at all and the
-        #Certificate extension doesn't get checked at all
-        $numtests -= 2 if ($proxy->is_tls13()
-                          && ($handtype & RESUME_HANDSHAKE) != 0);
 
         plan tests => $numtests;
 
-        my $nextmess = 0;
-        my $message = undef;
+        $nextmess = 0;
+        $message = undef;
+        $chnum = 0;
         for ($loop = 0; $handmessages[$loop][1] != 0; $loop++) {
             next if (($handmessages[$loop][1] & $handtype) == 0);
             if (scalar @{$proxy->message_list} > $nextmess) {
@@ -111,8 +131,11 @@ sub checkhandshake($$$$)
                    "Message type check. Got ".$message->mt
                    .", expected ".$handmessages[$loop][0]);
             }
+            $chnum = 1 if $message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
+                          && TLSProxy::Proxy::is_tls13();
 
             next if ($message->mt() != TLSProxy::Message::MT_CLIENT_HELLO
+                    && $message->mt() != TLSProxy::Message::MT_HELLO_RETRY_REQUEST
                     && $message->mt() != TLSProxy::Message::MT_SERVER_HELLO
                     && $message->mt() !=
                        TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS
@@ -123,14 +146,22 @@ sub checkhandshake($$$$)
 
             if ($message->mt() == TLSProxy::Message::MT_CLIENT_HELLO) {
                 #Add renegotiate extension we will expect if renegotiating
-                $exttype |= RENEGOTIATE_CLI_EXTENSION if ($clienthelloseen);
+                $exttype |= RENEGOTIATE_CLI_EXTENSION
+                    if ($clienthelloseen && !TLSProxy::Proxy::is_tls13());
                 $clienthelloseen = 1;
             }
             #Now check that we saw the extensions we expected
             my $msgexts = $message->extension_data();
-
+            my $extchnum = 0;
             for (my $extloop = 0, $extcount = 0; $extensions[$extloop][2] != 0;
                                 $extloop++) {
+                #In TLSv1.3 we can have two ClientHellos if there has been a
+                #HelloRetryRequest, and they may have different extensions. Skip
+                #if these are extensions for a different ClientHello
+                $extchnum = 1 if $extensions[$extloop][0] != TLSProxy::Message::MT_CLIENT_HELLO
+                                 && TLSProxy::Proxy::is_tls13();
+                next if $extensions[$extloop][0] == TLSProxy::Message::MT_CLIENT_HELLO
+                                 && $extchnum != $chnum;
                 next if ($message->mt() != $extensions[$extloop][0]);
                 ok (($extensions[$extloop][2] & $exttype) == 0
                       || defined ($msgexts->{$extensions[$extloop][1]}),
@@ -138,7 +169,7 @@ sub checkhandshake($$$$)
                     ." Extension: ".($extensions[$extloop][2] & $exttype).", "
                     .$extloop.")");
                 $extcount++ if (($extensions[$extloop][2] & $exttype) != 0);
-             }
+            }
             ok($extcount == keys %$msgexts, "Extensions count mismatch ("
                                             .$extcount.", ".(keys %$msgexts)
                                             .")");
diff --git a/util/TLSProxy/EncryptedExtensions.pm b/util/TLSProxy/HelloRetryRequest.pm
similarity index 76%
copy from util/TLSProxy/EncryptedExtensions.pm
copy to util/TLSProxy/HelloRetryRequest.pm
index 81242e2..a15c054 100644
--- a/util/TLSProxy/EncryptedExtensions.pm
+++ b/util/TLSProxy/HelloRetryRequest.pm
@@ -7,7 +7,7 @@
 
 use strict;
 
-package TLSProxy::EncryptedExtensions;
+package TLSProxy::HelloRetryRequest;
 
 use vars '@ISA';
 push @ISA, 'TLSProxy::Message';
@@ -23,7 +23,7 @@ sub new
 
     my $self = $class->SUPER::new(
         $server,
-        TLSProxy::Message::MT_ENCRYPTED_EXTENSIONS,
+        TLSProxy::Message::MT_HELLO_RETRY_REQUEST,
         $data,
         $records,
         $startoffset,
@@ -37,15 +37,25 @@ sub new
 sub parse
 {
     my $self = shift;
+    my $ptr = 2;
 
-    my $extensions_len = unpack('n', $self->data);
+    TLSProxy::Proxy->is_tls13(1);
+
+    my ($server_version) = unpack('n', $self->data);
+    # TODO(TLS1.3): Replace this reference to draft version before release
+    if ($server_version == TLSProxy::Record::VERS_TLS_1_3_DRAFT) {
+        $server_version = TLSProxy::Record::VERS_TLS_1_3;
+    }
+
+    my $extensions_len = unpack('n', substr($self->data, $ptr));
     if (!defined $extensions_len) {
         $extensions_len = 0;
     }
 
+    $ptr += 2;
     my $extension_data;
     if ($extensions_len != 0) {
-        $extension_data = substr($self->data, 2);
+        $extension_data = substr($self->data, $ptr);
 
         if (length($extension_data) != $extensions_len) {
             die "Invalid extension length\n";
@@ -64,6 +74,7 @@ sub parse
         $extensions{$type} = $extdata;
     }
 
+    $self->server_version($server_version);
     $self->extension_data(\%extensions);
 
     print "    Extensions Len:".$extensions_len."\n";
@@ -88,12 +99,21 @@ sub set_message_contents
         }
     }
 
-    $data = pack('n', length($extensions));
+    $data = pack('n', $self->server_version);
+    $data .= pack('n', length($extensions));
     $data .= $extensions;
     $self->data($data);
 }
 
 #Read/write accessors
+sub server_version
+{
+    my $self = shift;
+    if (@_) {
+      $self->{server_version} = shift;
+    }
+    return $self->{server_version};
+}
 sub extension_data
 {
     my $self = shift;
diff --git a/util/TLSProxy/Message.pm b/util/TLSProxy/Message.pm
index ab90586..ce469c4 100644
--- a/util/TLSProxy/Message.pm
+++ b/util/TLSProxy/Message.pm
@@ -17,6 +17,7 @@ use constant {
     MT_CLIENT_HELLO => 1,
     MT_SERVER_HELLO => 2,
     MT_NEW_SESSION_TICKET => 4,
+    MT_HELLO_RETRY_REQUEST => 6,
     MT_ENCRYPTED_EXTENSIONS => 8,
     MT_CERTIFICATE => 11,
     MT_SERVER_KEY_EXCHANGE => 12,
@@ -47,6 +48,7 @@ my %message_type = (
     MT_CLIENT_HELLO, "ClientHello",
     MT_SERVER_HELLO, "ServerHello",
     MT_NEW_SESSION_TICKET, "NewSessionTicket",
+    MT_HELLO_RETRY_REQUEST, "HelloRetryRequest",
     MT_ENCRYPTED_EXTENSIONS, "EncryptedExtensions",
     MT_CERTIFICATE, "Certificate",
     MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange",
@@ -260,6 +262,15 @@ sub create_message
             [@message_frag_lens]
         );
         $message->parse();
+    } elsif ($mt == MT_HELLO_RETRY_REQUEST) {
+        $message = TLSProxy::HelloRetryRequest->new(
+            $server,
+            $data,
+            [@message_rec_list],
+            $startoffset,
+            [@message_frag_lens]
+        );
+        $message->parse();
     } elsif ($mt == MT_SERVER_HELLO) {
         $message = TLSProxy::ServerHello->new(
             $server,
diff --git a/util/TLSProxy/Proxy.pm b/util/TLSProxy/Proxy.pm
index cee3bc5..189bcb8 100644
--- a/util/TLSProxy/Proxy.pm
+++ b/util/TLSProxy/Proxy.pm
@@ -16,6 +16,7 @@ use IO::Select;
 use TLSProxy::Record;
 use TLSProxy::Message;
 use TLSProxy::ClientHello;
+use TLSProxy::HelloRetryRequest;
 use TLSProxy::ServerHello;
 use TLSProxy::EncryptedExtensions;
 use TLSProxy::Certificate;


More information about the openssl-commits mailing list