[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Wed Nov 16 10:12:41 UTC 2016


The branch master has been updated
       via  395cc5cdbef001c9886719bd31dbe48bad839b5c (commit)
       via  9a5198808ae0dffd4459039bd3fc96fcfc3eeaf1 (commit)
       via  94ed2c6739754d13306fe510bb8bc19c2ad42749 (commit)
       via  5a8e54d9dc99dcc54b10e78ba0901e185fd2f77d (commit)
       via  323f212aa792904b7312d22f6107e9546a41faa4 (commit)
       via  2ee1271d8ff95d6a5036b37f7f03e1ae14436eeb (commit)
       via  ef7daaf915d7e0b7b48027f9ac4d47493adef0bb (commit)
       via  0f1e51ea115beef8a5fdd80d5a6c13ee289f980a (commit)
       via  c87386a2cd586368a61d86ede03319f910d050f4 (commit)
       via  d7c42d71ba407a4b3c26ed58263ae225976bbac3 (commit)
       via  bcec335856233cbcea4d96e3d43e1b43b8fe4182 (commit)
       via  d6d0bcddd9e7e16f413b307df4256f349e1d02cf (commit)
       via  b1834ad781ee445f5f580e5dcf4792b96ae08d1d (commit)
       via  d2c27a28c068188c1bda5109d228d94f868d06af (commit)
      from  78e09b53a40729f5e99829ccc733b592bd22fea1 (commit)


- Log -----------------------------------------------------------------
commit 395cc5cdbef001c9886719bd31dbe48bad839b5c
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 15 17:50:48 2016 +0000

    Fix a typo in a comment
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 9a5198808ae0dffd4459039bd3fc96fcfc3eeaf1
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 15 17:50:08 2016 +0000

    Move getting the curvelist for client and server out of the loop
    
    No need to continually get the list of supported curves for the client
    and server. Just do it once.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 94ed2c6739754d13306fe510bb8bc19c2ad42749
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Nov 14 14:53:31 2016 +0000

    Fixed various style issues in the key_share code
    
    Numerous style issues as well as references to TLS1_3_VERSION instead of
    SSL_IS_TLS13(s)
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 5a8e54d9dc99dcc54b10e78ba0901e185fd2f77d
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Nov 3 18:51:28 2016 +0000

    Add some tests for the key_share extension
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 323f212aa792904b7312d22f6107e9546a41faa4
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 4 09:49:16 2016 +0000

    Check key_exchange data length is not 0
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 2ee1271d8ff95d6a5036b37f7f03e1ae14436eeb
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Nov 4 00:07:50 2016 +0000

    Ensure the whole key_share extension is well formatted
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit ef7daaf915d7e0b7b48027f9ac4d47493adef0bb
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Nov 3 18:50:41 2016 +0000

    Validate that the provided key_share is in supported_groups
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 0f1e51ea115beef8a5fdd80d5a6c13ee289f980a
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Nov 2 15:03:56 2016 +0000

    Start using the key_share data to derive the PMS
    
    The previous commits put in place the logic to exchange key_share data. We
    now need to do something with that information. In <= TLSv1.2 the equivalent
    of the key_share extension is the ServerKeyExchange and ClientKeyExchange
    messages. With key_share those two messages are no longer necessary.
    
    The commit removes the SKE and CKE messages from the TLSv1.3 state machine.
    TLSv1.3 is completely different to TLSv1.2 in the messages that it sends
    and the transitions that are allowed. Therefore, rather than extend the
    existing <=TLS1.2 state transition functions, we create a whole new set for
    TLSv1.3. Intially these are still based on the TLSv1.2 ones, but over time
    they will be amended.
    
    The new TLSv1.3 transitions remove SKE and CKE completely. There's also some
    cleanup for some stuff which is not relevant to TLSv1.3 and is easy to
    remove, e.g. the DTLS support (we're not doing DTLSv1.3 yet) and NPN.
    
    I also disable EXTMS for TLSv1.3. Using it was causing some added
    complexity, so rather than fix it I removed it, since eventually it will not
    be needed anyway.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit c87386a2cd586368a61d86ede03319f910d050f4
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Nov 3 15:05:27 2016 +0000

    Add a TLS version consistency check during session resumption
    
    This is a temporary fix for while we are still using the old session
    resumption logic in the TLSv1.3 code. Due to differences in EXTMS support
    we can't resume a <=TLSv1.2 session in a TLSv1.3 connection (the EXTMS
    consistency check causes the connection to abort). This causes test
    failures.
    
    Ultimately we will rewrite the session resumption logic for TLSv1.3 so this
    problem will go away. But until then we need a quick fix to keep the tests
    happy.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit d7c42d71ba407a4b3c26ed58263ae225976bbac3
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 1 14:09:19 2016 +0000

    Add processing of the key_share received in the ServerHello
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit bcec335856233cbcea4d96e3d43e1b43b8fe4182
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 1 13:24:02 2016 +0000

    Add key_share info to the ServerHello
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit d6d0bcddd9e7e16f413b307df4256f349e1d02cf
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 1 11:17:10 2016 +0000

    Update the trace code to know about the key_share extension
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit b1834ad781ee445f5f580e5dcf4792b96ae08d1d
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Nov 1 10:53:32 2016 +0000

    Add the key_share processing to the server side
    
    At the moment the server doesn't yet do anything with this information.
    We still need to send the server's key_share info back to the client. That
    will happen in subsequent commits.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit d2c27a28c068188c1bda5109d228d94f868d06af
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Oct 31 14:49:52 2016 +0000

    Generate the key_shares extension on the client side
    
    In this commit we just generate the extension on the client side, but don't
    yet do anything with it. Subsequent commits, will add the server side
    capability.
    
    At the moment we hard code a single key_share. In the future we should make
    this configurable.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

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

Summary of changes:
 include/openssl/ssl.h                 |   6 +
 include/openssl/tls1.h                |   1 +
 ssl/s3_lib.c                          |   8 +-
 ssl/ssl_err.c                         |   8 +
 ssl/ssl_locl.h                        |   5 +-
 ssl/ssl_sess.c                        |  17 ++
 ssl/statem/statem_clnt.c              | 201 ++++++++++++++-
 ssl/statem/statem_srvr.c              | 224 ++++++++++++++++-
 ssl/t1_enc.c                          |   8 +-
 ssl/t1_lib.c                          | 459 +++++++++++++++++++++++++++++++---
 ssl/t1_trce.c                         |  32 ++-
 test/recipes/70-test_key_share.t      | 326 ++++++++++++++++++++++++
 test/recipes/70-test_sslsessiontick.t |   2 +-
 test/recipes/70-test_tlsextms.t       |  50 ++--
 test/recipes/80-test_ssl_new.t        |   3 +-
 test/ssl-tests/08-npn.conf            |  22 ++
 test/ssl-tests/08-npn.conf.in         |  33 ++-
 util/TLSProxy/Message.pm              |   2 +
 18 files changed, 1326 insertions(+), 81 deletions(-)
 create mode 100755 test/recipes/70-test_key_share.t

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index b61a992..66f7d8c 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2074,6 +2074,7 @@ int ERR_load_SSL_strings(void);
 /* Error codes for the SSL functions. */
 
 /* Function codes. */
+# define SSL_F_ADD_CLIENT_KEY_SHARE_EXT                   438
 # define SSL_F_CHECK_SUITEB_CIPHER_LIST                   331
 # define SSL_F_CT_MOVE_SCTS                               345
 # define SSL_F_CT_STRICT                                  349
@@ -2099,10 +2100,13 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_DTLS_GET_REASSEMBLED_MESSAGE               370
 # define SSL_F_DTLS_PROCESS_HELLO_VERIFY                  386
 # define SSL_F_OPENSSL_INIT_SSL                           342
+# define SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION       436
 # define SSL_F_OSSL_STATEM_CLIENT_CONSTRUCT_MESSAGE       430
 # define SSL_F_OSSL_STATEM_CLIENT_READ_TRANSITION         417
+# define SSL_F_OSSL_STATEM_SERVER13_READ_TRANSITION       437
 # define SSL_F_OSSL_STATEM_SERVER_CONSTRUCT_MESSAGE       431
 # define SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION         418
+# define SSL_F_PROCESS_KEY_SHARE_EXT                      439
 # define SSL_F_READ_STATE_MACHINE                         352
 # define SSL_F_SSL3_CHANGE_CIPHER_STATE                   129
 # define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM              130
@@ -2313,6 +2317,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_BAD_ECPOINT                                306
 # define SSL_R_BAD_HANDSHAKE_LENGTH                       332
 # define SSL_R_BAD_HELLO_REQUEST                          105
+# define SSL_R_BAD_KEY_SHARE                              108
 # define SSL_R_BAD_LENGTH                                 271
 # define SSL_R_BAD_PACKET_LENGTH                          115
 # define SSL_R_BAD_PROTOCOL_VERSION_NUMBER                116
@@ -2427,6 +2432,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_NO_SHARED_CIPHER                           193
 # define SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS             376
 # define SSL_R_NO_SRTP_PROFILES                           359
+# define SSL_R_NO_SUITABLE_KEY_SHARE                      101
 # define SSL_R_NO_VALID_SCTS                              216
 # define SSL_R_NO_VERIFY_COOKIE_CALLBACK                  403
 # define SSL_R_NULL_SSL_CTX                               195
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 1fd5788..b2d3057 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -174,6 +174,7 @@ extern "C" {
 # define TLSEXT_TYPE_session_ticket              35
 
 /* As defined for TLS1.3 */
+# define TLSEXT_TYPE_key_share                   40
 # define TLSEXT_TYPE_supported_versions          43
 
 /* Temporary extension type */
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 2439167..bcc0f9e 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -4068,7 +4068,7 @@ EVP_PKEY *ssl_generate_pkey_curve(int id)
 #endif
 
 /* Derive premaster or master secret for ECDH/DH */
-int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey)
+int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int genmaster)
 {
     int rv = 0;
     unsigned char *pms = NULL;
@@ -4093,12 +4093,12 @@ int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey)
     if (EVP_PKEY_derive(pctx, pms, &pmslen) <= 0)
         goto err;
 
-    if (s->server) {
-        /* For server generate master secret and discard premaster */
+    if (genmaster) {
+        /* Generate master secret and discard premaster */
         rv = ssl_generate_master_secret(s, pms, pmslen, 1);
         pms = NULL;
     } else {
-        /* For client just save premaster secret */
+        /* Save premaster secret */
         s->s3->tmp.pms = pms;
         s->s3->tmp.pmslen = pmslen;
         pms = NULL;
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 6c438fe..235a53c 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -19,6 +19,7 @@
 # define ERR_REASON(reason) ERR_PACK(ERR_LIB_SSL,0,reason)
 
 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_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"},
@@ -49,14 +50,19 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "dtls_get_reassembled_message"},
     {ERR_FUNC(SSL_F_DTLS_PROCESS_HELLO_VERIFY), "dtls_process_hello_verify"},
     {ERR_FUNC(SSL_F_OPENSSL_INIT_SSL), "OPENSSL_init_ssl"},
+    {ERR_FUNC(SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION),
+     "ossl_statem_client13_read_transition"},
     {ERR_FUNC(SSL_F_OSSL_STATEM_CLIENT_CONSTRUCT_MESSAGE),
      "ossl_statem_client_construct_message"},
     {ERR_FUNC(SSL_F_OSSL_STATEM_CLIENT_READ_TRANSITION),
      "ossl_statem_client_read_transition"},
+    {ERR_FUNC(SSL_F_OSSL_STATEM_SERVER13_READ_TRANSITION),
+     "ossl_statem_server13_read_transition"},
     {ERR_FUNC(SSL_F_OSSL_STATEM_SERVER_CONSTRUCT_MESSAGE),
      "ossl_statem_server_construct_message"},
     {ERR_FUNC(SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION),
      "ossl_statem_server_read_transition"},
+    {ERR_FUNC(SSL_F_PROCESS_KEY_SHARE_EXT), "process_key_share_ext"},
     {ERR_FUNC(SSL_F_READ_STATE_MACHINE), "read_state_machine"},
     {ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE), "ssl3_change_cipher_state"},
     {ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM),
@@ -342,6 +348,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_BAD_ECPOINT), "bad ecpoint"},
     {ERR_REASON(SSL_R_BAD_HANDSHAKE_LENGTH), "bad handshake length"},
     {ERR_REASON(SSL_R_BAD_HELLO_REQUEST), "bad hello request"},
+    {ERR_REASON(SSL_R_BAD_KEY_SHARE), "bad key share"},
     {ERR_REASON(SSL_R_BAD_LENGTH), "bad length"},
     {ERR_REASON(SSL_R_BAD_PACKET_LENGTH), "bad packet length"},
     {ERR_REASON(SSL_R_BAD_PROTOCOL_VERSION_NUMBER),
@@ -488,6 +495,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS),
      "no shared signature algorithms"},
     {ERR_REASON(SSL_R_NO_SRTP_PROFILES), "no srtp profiles"},
+    {ERR_REASON(SSL_R_NO_SUITABLE_KEY_SHARE), "no suitable key share"},
     {ERR_REASON(SSL_R_NO_VALID_SCTS), "no valid scts"},
     {ERR_REASON(SSL_R_NO_VERIFY_COOKIE_CALLBACK),
      "no verify cookie callback"},
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 105a487..88b2f8b 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1299,6 +1299,8 @@ typedef struct ssl3_state_st {
 
     /* For clients: peer temporary key */
 # if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
+    /* The group_id for the DH/ECDH key */
+    unsigned int group_id;
     EVP_PKEY *peer_tmp;
 # endif
 
@@ -1877,7 +1879,8 @@ __owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field,
 __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
                                       int free_pms);
 __owur EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm);
-__owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey);
+__owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey,
+                      int genmaster);
 __owur EVP_PKEY *ssl_dh_to_pkey(DH *dh);
 
 __owur const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index 825e706..47dbf85 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -588,6 +588,23 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello)
         goto err;
     }
 
+    /*
+     * TODO(TLS1.3): This is temporary, because TLSv1.3 resumption is completely
+     * different. For now though we're still using the old resumption logic, so
+     * to avoid test failures we need this. Remove this code!
+     * 
+     * Check TLS version consistency. We can't resume <=TLSv1.2 session if we
+     * have negotiated TLSv1.3, and vice versa.
+     */
+    if (!SSL_IS_DTLS(s)
+            && ((ret->ssl_version <= TLS1_2_VERSION
+                 && s->version >=TLS1_3_VERSION)
+                || (ret->ssl_version >= TLS1_3_VERSION
+                    && s->version <= TLS1_2_VERSION))) {
+        /* Continue but do not resume */
+        goto err;
+    }
+
     /* Check extended master secret extension consistency */
     if (ret->flags & SSL_SESS_FLAG_EXTMS) {
         /* If old session includes extms, but new does not: abort handshake */
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index e0d53fe..f89d317 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -108,19 +108,135 @@ static int key_exchange_expected(SSL *s)
 
 /*
  * ossl_statem_client_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when a TLS1.3 client is reading messages from the
+ * server. The message type that the server has sent is provided in |mt|. The
+ * current state is in |s->statem.hand_state|.
+ *
+ * Return values are 1 for success (transition allowed) and  0 on error
+ * (transition not allowed)
+ */
+static int ossl_statem_client13_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_CW_CLNT_HELLO, because we haven't
+     * yet negotiated TLSv1.3 at that point so that is handled by
+     * ossl_statem_client_read_transition()
+     */
+
+    switch (st->hand_state) {
+    default:
+        break;
+
+    case TLS_ST_CR_SRVR_HELLO:
+        if (s->hit) {
+            if (s->tlsext_ticket_expected) {
+                if (mt == SSL3_MT_NEWSESSION_TICKET) {
+                    st->hand_state = TLS_ST_CR_SESSION_TICKET;
+                    return 1;
+                }
+            } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                st->hand_state = TLS_ST_CR_CHANGE;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_CERTIFICATE) {
+                st->hand_state = TLS_ST_CR_CERT;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_CR_CERT:
+        /*
+         * The CertificateStatus message is optional even if
+         * |tlsext_status_expected| is set
+         */
+        if (s->tlsext_status_expected && mt == SSL3_MT_CERTIFICATE_STATUS) {
+            st->hand_state = TLS_ST_CR_CERT_STATUS;
+            return 1;
+        }
+        /* Fall through */
+
+    case TLS_ST_CR_CERT_STATUS:
+        if (mt == SSL3_MT_CERTIFICATE_REQUEST) {
+            if (cert_req_allowed(s)) {
+                st->hand_state = TLS_ST_CR_CERT_REQ;
+                return 1;
+            }
+            goto err;
+        }
+        /* Fall through */
+
+    case TLS_ST_CR_CERT_REQ:
+        if (mt == SSL3_MT_SERVER_DONE) {
+            st->hand_state = TLS_ST_CR_SRVR_DONE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CW_FINISHED:
+        if (s->tlsext_ticket_expected) {
+            if (mt == SSL3_MT_NEWSESSION_TICKET) {
+                st->hand_state = TLS_ST_CR_SESSION_TICKET;
+                return 1;
+            }
+        } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_CR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_SESSION_TICKET:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_CR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_CHANGE:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_CR_FINISHED;
+            return 1;
+        }
+        break;
+    }
+
+ err:
+    /* No valid transition found */
+    ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
+    SSLerr(SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION,
+           SSL_R_UNEXPECTED_MESSAGE);
+    return 0;
+}
+
+/*
+ * ossl_statem_client_read_transition() encapsulates the logic for the allowed
  * handshake state transitions when the client is reading messages from the
  * server. The message type that the server has sent is provided in |mt|. The
  * current state is in |s->statem.hand_state|.
  *
- *  Return values are:
- *  1: Success (transition allowed)
- *  0: Error (transition not allowed)
+ * Return values are 1 for success (transition allowed) and  0 on error
+ * (transition not allowed)
  */
 int ossl_statem_client_read_transition(SSL *s, int mt)
 {
     OSSL_STATEM *st = &s->statem;
     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
+     */
+    if (s->method->version == TLS1_3_VERSION)
+        return ossl_statem_client13_read_transition(s, mt);
+
     switch (st->hand_state) {
     default:
         break;
@@ -271,13 +387,83 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
 }
 
 /*
- * client_write_transition() works out what handshake state to move to next
- * when the client is writing messages to be sent to the server.
+ * ossl_statem_client13_write_transition() works out what handshake state to
+ * move to next when the TLSv1.3 client is writing messages to be sent to the
+ * server.
+ */
+static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
+{
+    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 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().
+     */
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        return WRITE_TRAN_ERROR;
+
+    case TLS_ST_CR_SRVR_DONE:
+        st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
+                                                    : TLS_ST_CW_CHANGE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CERT:
+        /* If a non-empty Certificate we also send CertificateVerify */
+        st->hand_state = (s->s3->tmp.cert_req == 1) ? TLS_ST_CW_CERT_VRFY
+                                                    : TLS_ST_CW_CHANGE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CERT_VRFY:
+        st->hand_state = TLS_ST_CW_CHANGE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CHANGE:
+        st->hand_state = TLS_ST_CW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_FINISHED:
+        if (s->hit) {
+            st->hand_state = TLS_ST_OK;
+            ossl_statem_set_in_init(s, 0);
+            return WRITE_TRAN_CONTINUE;
+        }
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_CR_FINISHED:
+        if (s->hit) {
+            st->hand_state = TLS_ST_CW_CHANGE;
+            return WRITE_TRAN_CONTINUE;
+        }
+        st->hand_state = TLS_ST_OK;
+        ossl_statem_set_in_init(s, 0);
+        return WRITE_TRAN_CONTINUE;
+    }
+}
+
+/*
+ * ossl_statem_client_write_transition() works out what handshake state to
+ * move to next when the client is writing messages to be sent to the server.
  */
 WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
 {
     OSSL_STATEM *st = &s->statem;
 
+    /*
+     * Note that immediately before/after a ClientHello we don't know what
+     * version we are going to negotiate yet, so we don't take this branch until
+     * later
+     */
+    if (s->method->version == TLS1_3_VERSION)
+        return ossl_statem_client13_write_transition(s);
+
     switch (st->hand_state) {
     default:
         /* Shouldn't happen */
@@ -2282,7 +2468,7 @@ static int tls_construct_cke_dhe(SSL *s, WPACKET *pkt, int *al)
     ckey = ssl_generate_pkey(skey);
     dh_clnt = EVP_PKEY_get0_DH(ckey);
 
-    if (dh_clnt == NULL || ssl_derive(s, ckey, skey) == 0)
+    if (dh_clnt == NULL || ssl_derive(s, ckey, skey, 0) == 0)
         goto err;
 
     /* send off the data */
@@ -2318,7 +2504,7 @@ static int tls_construct_cke_ecdhe(SSL *s, WPACKET *pkt, int *al)
 
     ckey = ssl_generate_pkey(skey);
 
-    if (ssl_derive(s, ckey, skey) == 0) {
+    if (ssl_derive(s, ckey, skey, 0) == 0) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_EVP_LIB);
         goto err;
     }
@@ -2626,6 +2812,7 @@ int tls_construct_client_verify(SSL *s, WPACKET *pkt)
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
         goto err;
     }
+
     if (SSL_USE_SIGALGS(s)&& !tls12_get_sigandhash(pkt, pkey, md)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
         goto err;
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 142c637..3c4d6ee 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -68,19 +68,105 @@ static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
                                                       int *al);
 
 /*
- * server_read_transition() encapsulates the logic for the allowed handshake
- * state transitions when the server is reading messages from the client. The
- * message type that the client has sent is provided in |mt|. The current state
- * is in |s->statem.hand_state|.
+ * ossl_statem_server13_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when a TLSv1.3 server is reading messages from
+ * the client. The message type that the client has sent is provided in |mt|.
+ * The current state is in |s->statem.hand_state|.
  *
- *  Valid return values are:
- *  1: Success (transition allowed)
- *  0: Error (transition not allowed)
+ * Return values are 1 for success (transition allowed) and  0 on error
+ * (transition not allowed)
+ */
+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()
+     */
+    switch (st->hand_state) {
+    default:
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+        if (s->s3->tmp.cert_request) {
+            if (mt == SSL3_MT_CERTIFICATE) {
+                st->hand_state = TLS_ST_SR_CERT;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                st->hand_state = TLS_ST_SR_CHANGE;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_SR_CERT:
+        if (s->session->peer == NULL) {
+            if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                st->hand_state = TLS_ST_SR_CHANGE;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
+                st->hand_state = TLS_ST_SR_CERT_VRFY;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_SR_CERT_VRFY:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_SR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SR_CHANGE:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_SR_FINISHED;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SW_FINISHED:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_SR_CHANGE;
+            return 1;
+        }
+        break;
+    }
+
+    /* No valid transition found */
+    ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
+    SSLerr(SSL_F_OSSL_STATEM_SERVER13_READ_TRANSITION,
+           SSL_R_UNEXPECTED_MESSAGE);
+    return 0;
+}
+
+/*
+ * ossl_statem_server_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when the server is reading messages from the
+ * client. The message type that the client has sent is provided in |mt|. The
+ * current state is in |s->statem.hand_state|.
+ *
+ * Return values are 1 for success (transition allowed) and  0 on error
+ * (transition not allowed)
  */
 int ossl_statem_server_read_transition(SSL *s, int mt)
 {
     OSSL_STATEM *st = &s->statem;
 
+    if (s->method->version == TLS1_3_VERSION)
+        return ossl_statem_server13_read_transition(s, mt);
+
     switch (st->hand_state) {
     default:
         break;
@@ -304,13 +390,108 @@ static int send_certificate_request(SSL *s)
 }
 
 /*
- * server_write_transition() works out what handshake state to move to next
- * when the server is writing messages to be sent to the client.
+ * ossl_statem_server13_write_transition() works out what handshake state to
+ * move to next when a TLSv1.3 server is writing messages to be sent to the
+ * client.
+ */
+static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
+{
+    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
+     */
+
+    /*
+     * No case for TLS_ST_BEFORE, because at that stage we have not negotiated
+     * TLSv1.3 yet, so that is handled by ossl_statem_server_write_transition()
+     */
+
+    switch (st->hand_state) {
+    default:
+        /* Shouldn't happen */
+        return WRITE_TRAN_ERROR;
+
+    case TLS_ST_SR_CLNT_HELLO:
+        st->hand_state = TLS_ST_SW_SRVR_HELLO;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_SRVR_HELLO:
+        if (s->hit)
+            st->hand_state = s->tlsext_ticket_expected
+                                ? TLS_ST_SW_SESSION_TICKET : TLS_ST_SW_CHANGE;
+        else
+            st->hand_state = TLS_ST_SW_CERT;
+
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_CERT:
+        if (s->tlsext_status_expected) {
+            st->hand_state = TLS_ST_SW_CERT_STATUS;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Fall through */
+
+    case TLS_ST_SW_CERT_STATUS:
+        if (send_certificate_request(s)) {
+            st->hand_state = TLS_ST_SW_CERT_REQ;
+            return WRITE_TRAN_CONTINUE;
+        }
+        /* Fall through */
+
+    case TLS_ST_SW_CERT_REQ:
+        st->hand_state = TLS_ST_SW_SRVR_DONE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_SRVR_DONE:
+        return WRITE_TRAN_FINISHED;
+
+    case TLS_ST_SR_FINISHED:
+        if (s->hit) {
+            st->hand_state = TLS_ST_OK;
+            ossl_statem_set_in_init(s, 0);
+            return WRITE_TRAN_CONTINUE;
+        }
+
+        st->hand_state = s->tlsext_ticket_expected ? TLS_ST_SW_SESSION_TICKET
+                                                   : TLS_ST_SW_CHANGE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_SESSION_TICKET:
+        st->hand_state = TLS_ST_SW_CHANGE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_CHANGE:
+        st->hand_state = TLS_ST_SW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_SW_FINISHED:
+        if (s->hit)
+            return WRITE_TRAN_FINISHED;
+
+        st->hand_state = TLS_ST_OK;
+        ossl_statem_set_in_init(s, 0);
+        return WRITE_TRAN_CONTINUE;
+    }
+}
+
+/*
+ * ossl_statem_server_write_transition() works out what handshake state to move
+ * to next when the server is writing messages to be sent to the client.
  */
 WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
 {
     OSSL_STATEM *st = &s->statem;
 
+    /*
+     * Note that before the ClientHello we don't know what version we are going
+     * to negotiate yet, so we don't take this branch until later
+     */
+
+    if (s->method->version == TLS1_3_VERSION)
+        return ossl_statem_server13_write_transition(s);
+
     switch (st->hand_state) {
     default:
         /* Shouldn't happen */
@@ -1263,6 +1444,15 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
         goto err;
     }
 
+    /* Check we've got a key_share for TLSv1.3 */
+    if (s->version == TLS1_3_VERSION && s->s3->peer_tmp == NULL && !s->hit) {
+        /* No suitable share */
+        /* TODO(TLS1.3): Send a HelloRetryRequest */
+        al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_SUITABLE_KEY_SHARE);
+        goto f_err;
+    }
+
     /*
      * Check if we want to use external pre-shared secret for this handshake
      * for not reused session only. We need to generate server_random before
@@ -2307,7 +2497,7 @@ static int tls_process_cke_dhe(SSL *s, PACKET *pkt, int *al)
         goto err;
     }
 
-    if (ssl_derive(s, skey, ckey) == 0) {
+    if (ssl_derive(s, skey, ckey, 1) == 0) {
         *al = SSL_AD_INTERNAL_ERROR;
         SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, ERR_R_INTERNAL_ERROR);
         goto err;
@@ -2367,7 +2557,7 @@ static int tls_process_cke_ecdhe(SSL *s, PACKET *pkt, int *al)
         }
     }
 
-    if (ssl_derive(s, skey, ckey) == 0) {
+    if (ssl_derive(s, skey, ckey, 1) == 0) {
         *al = SSL_AD_INTERNAL_ERROR;
         SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, ERR_R_INTERNAL_ERROR);
         goto err;
@@ -2767,6 +2957,7 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
         al = SSL_AD_INTERNAL_ERROR;
         goto f_err;
     }
+
 #ifdef SSL_DEBUG
     fprintf(stderr, "Using client verify alg %s\n", EVP_MD_name(md));
 #endif
@@ -2922,6 +3113,17 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
 
     sk_X509_pop_free(s->session->peer_chain, X509_free);
     s->session->peer_chain = sk;
+
+    /*
+     * Freeze the handshake buffer. For <TLS1.3 we do this after the CKE
+     * message
+     */
+    if (SSL_IS_TLS13(s) && !ssl3_digest_cached_records(s, 1)) {
+        al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        goto f_err;
+    }
+
     /*
      * Inconsistency alert: cert_chain does *not* include the peer's own
      * certificate, while we do include it in statem_clnt.c
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 8d1e350..37cd25d 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -474,7 +474,13 @@ size_t tls1_final_finish_mac(SSL *s, const char *str, size_t slen,
 int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
                                 size_t len, size_t *secret_size)
 {
-    if (s->session->flags & SSL_SESS_FLAG_EXTMS) {
+    /*
+     * TODO(TLS1.3): We haven't implemented TLS1.3 key derivation yet. For now
+     * we will just force no use of EMS (which adds complications around the
+     * handshake hash). This will need to be removed later
+     */
+    if ((s->session->flags & SSL_SESS_FLAG_EXTMS)
+            && SSL_IS_TLS13(s)) {
         unsigned char hash[EVP_MAX_MD_SIZE * 2];
         size_t hashlen;
         /*
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 338334f..74022ee 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1026,9 +1026,13 @@ static int tls1_check_duplicate_extensions(const PACKET *packet)
 int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
 {
 #ifndef OPENSSL_NO_EC
-    /* See if we support any ECC ciphersuites */
+    const unsigned char *pcurves = NULL;
+    size_t num_curves = 0;
     int using_ecc = 0;
-    if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s)) {
+
+    /* See if we support any ECC ciphersuites */
+    if ((s->version >= TLS1_VERSION && s->version <= TLS1_2_VERSION)
+            || SSL_IS_DTLS(s)) {
         int i;
         unsigned long alg_k, alg_a;
         STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
@@ -1044,6 +1048,18 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
                 break;
             }
         }
+    } else if (SSL_IS_TLS13(s)) {
+        /*
+         * TODO(TLS1.3): We always use ECC for TLSv1.3 at the moment. This will
+         * change if we implement DH key shares
+         */
+        using_ecc = 1;
+    }
+#else
+    if (SSL_IS_TLS13(s)) {
+        /* Shouldn't happen! */
+        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+        return 0;
     }
 #endif
 
@@ -1102,8 +1118,8 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
         /*
          * Add TLS extension ECPointFormats to the ClientHello message
          */
-        const unsigned char *pcurves, *pformats;
-        size_t num_curves, num_formats;
+        const unsigned char *pformats, *pcurvestmp;
+        size_t num_formats;
         size_t i;
 
         tls1_get_formatlist(s, &pformats, &num_formats);
@@ -1126,6 +1142,7 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
             SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
             return 0;
         }
+        pcurvestmp = pcurves;
 
         if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
                    /* Sub-packet for supported_groups extension */
@@ -1135,10 +1152,10 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
             return 0;
         }
         /* Copy curve ID if supported */
-        for (i = 0; i < num_curves; i++, pcurves += 2) {
+        for (i = 0; i < num_curves; i++, pcurvestmp += 2) {
             if (tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) {
-                if (!WPACKET_put_bytes_u8(pkt, pcurves[0])
-                    || !WPACKET_put_bytes_u8(pkt, pcurves[1])) {
+                if (!WPACKET_put_bytes_u8(pkt, pcurvestmp[0])
+                    || !WPACKET_put_bytes_u8(pkt, pcurvestmp[1])) {
                         SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT,
                                ERR_R_INTERNAL_ERROR);
                         return 0;
@@ -1349,8 +1366,13 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
         return 0;
     }
 
+    /* TLS1.3 specific extensions */
     if (SSL_IS_TLS13(s)) {
         int min_version, max_version, reason, currv;
+        size_t i, sharessent = 0;
+
+        /* TODO(TLS1.3): Should we add this extension for versions < TLS1.3? */
+        /* supported_versions extension */
         if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_versions)
                 || !WPACKET_start_sub_packet_u16(pkt)
                 || !WPACKET_start_sub_packet_u8(pkt)) {
@@ -1384,6 +1406,79 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
             SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
             return 0;
         }
+
+
+        /* key_share extension */
+        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
+                   /* Extension data sub-packet */
+                || !WPACKET_start_sub_packet_u16(pkt)
+                   /* KeyShare list sub-packet */
+                || !WPACKET_start_sub_packet_u16(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, 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_SSL_ADD_CLIENTHELLO_TLSEXT,
+                       ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+
+            /* 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_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_EVP_LIB);
+                return 0;
+            }
+
+            /* Encode the public key. */
+            encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
+                                                        &encodedPoint);
+            if (encodedlen == 0) {
+                SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, 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_SSL_ADD_CLIENTHELLO_TLSEXT,
+                       ERR_R_INTERNAL_ERROR);
+                EVP_PKEY_free(key_share_key);
+                OPENSSL_free(encodedPoint);
+                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->group_id = curve_id;
+            s->s3->tmp.pkey = key_share_key;
+            sharessent++;
+            OPENSSL_free(encodedPoint);
+        }
+        if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
+            SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
     }
 
     /*
@@ -1421,6 +1516,59 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al)
     return 1;
 }
 
+/*
+ * Add the key_share extension.
+ *
+ * Returns 1 on success or 0 on failure.
+ */
+static int add_client_key_share_ext(SSL *s, WPACKET *pkt, int *al)
+{
+    unsigned char *encodedPoint;
+    size_t encoded_pt_len = 0;
+    EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;
+
+    if (ckey == NULL) {
+        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    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)) {
+        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    skey = ssl_generate_pkey(ckey);
+
+    /* Generate encoding of server key */
+    encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
+    if (encoded_pt_len == 0) {
+        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_EC_LIB);
+        EVP_PKEY_free(skey);
+        return 0;
+    }
+
+    if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
+            || !WPACKET_close(pkt)) {
+        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
+        EVP_PKEY_free(skey);
+        OPENSSL_free(encodedPoint);
+        return 0;
+    }
+    OPENSSL_free(encodedPoint);
+
+    /* This causes the crypto state to be updated based on the derived keys */
+    s->s3->tmp.pkey = skey;
+    if (ssl_derive(s, skey, ckey, 1) == 0) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
 int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al)
 {
 #ifndef OPENSSL_NO_NEXTPROTONEG
@@ -1553,6 +1701,10 @@ int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al)
         }
     }
 #endif
+
+    if (SSL_IS_TLS13(s) && !s->hit && !add_client_key_share_ext(s, pkt, al))
+        return 0;
+
     if (!custom_ext_add(s, 1, pkt, al)) {
         SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
         return 0;
@@ -1743,6 +1895,198 @@ static void ssl_check_for_safari(SSL *s, const CLIENTHELLO_MSG *hello)
 }
 #endif                          /* !OPENSSL_NO_EC */
 
+
+/*
+ * Process the supported_groups extension if present. Returns success if the
+ * extension is absent, or if it has been successfully processed.
+ *
+ * Returns 1 on success or 0 on failure
+ */
+static int tls_process_supported_groups(SSL *s, CLIENTHELLO_MSG *hello)
+{
+#ifndef OPENSSL_NO_EC
+    PACKET supported_groups_list;
+    RAW_EXTENSION *suppgroups = tls_get_extension_by_type(hello->pre_proc_exts,
+                                    hello->num_extensions,
+                                    TLSEXT_TYPE_supported_groups);
+
+    if (suppgroups == NULL)
+        return 1;
+
+    /* Each group is 2 bytes and we must have at least 1. */
+    if (!PACKET_as_length_prefixed_2(&suppgroups->data,
+                                     &supported_groups_list)
+        || PACKET_remaining(&supported_groups_list) == 0
+        || (PACKET_remaining(&supported_groups_list) % 2) != 0) {
+        return 0;
+    }
+
+    if (!s->hit
+            && !PACKET_memdup(&supported_groups_list,
+                              &s->session->tlsext_supportedgroupslist,
+                              &s->session->tlsext_supportedgroupslist_length)) {
+        return 0;
+    }
+#endif
+    return 1;
+}
+
+/*
+ * 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.
+ */
+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;
+}
+
+/*
+ * Process a key_share 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.
+ */
+static int process_key_share_ext(SSL *s, PACKET *pkt, int *al)
+{
+    unsigned int group_id;
+    PACKET key_share_list, encoded_pt;
+    const unsigned char *clntcurves, *srvrcurves;
+    size_t clnt_num_curves, srvr_num_curves;
+    int group_nid, found = 0;
+    unsigned int curve_flags;
+
+    /* Sanity check */
+    if (s->s3->peer_tmp != NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!PACKET_as_length_prefixed_2(pkt, &key_share_list)) {
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
+               SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    /* Get our list of supported curves */
+    if (!tls1_get_curvelist(s, 0, &srvrcurves, &srvr_num_curves)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
+               ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    /* Get the clients list of supported curves */
+    if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
+               ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    while (PACKET_remaining(&key_share_list) > 0) {
+        if (!PACKET_get_net_2(&key_share_list, &group_id)
+                || !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt)
+                || PACKET_remaining(&encoded_pt) == 0) {
+            *al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
+                   SSL_R_LENGTH_MISMATCH);
+            return 0;
+        }
+
+        /*
+         * If we already found a suitable key_share we loop through the
+         * rest to verify the structure, but don't process them.
+         */
+        if (found)
+            continue;
+
+        /* Check if this share is in supported_groups sent from client */
+        if (!check_in_list(s, group_id, clntcurves, clnt_num_curves, 0)) {
+            *al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
+                   SSL_R_BAD_KEY_SHARE);
+            return 0;
+        }
+
+        /* Check if this share is for a group we can use */
+        if (!check_in_list(s, group_id, srvrcurves, srvr_num_curves, 1)) {
+            /* Share not suitable */
+            continue;
+        }
+
+        group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags);
+
+        if (group_nid == 0) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT,
+                   SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+            return 0;
+        }
+
+        if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) {
+            /* Can happen for some curves, e.g. X25519 */
+            EVP_PKEY *key = EVP_PKEY_new();
+
+            if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT, ERR_R_EVP_LIB);
+                EVP_PKEY_free(key);
+                return 0;
+            }
+            s->s3->peer_tmp = key;
+        } else {
+            /* Set up EVP_PKEY with named curve as parameters */
+            EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+            if (pctx == NULL
+                    || EVP_PKEY_paramgen_init(pctx) <= 0
+                    || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx,
+                                                              group_nid) <= 0
+                    || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT, ERR_R_EVP_LIB);
+                EVP_PKEY_CTX_free(pctx);
+                return 0;
+            }
+            EVP_PKEY_CTX_free(pctx);
+            pctx = NULL;
+        }
+        s->s3->group_id = group_id;
+
+        if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp,
+                PACKET_data(&encoded_pt),
+                PACKET_remaining(&encoded_pt))) {
+            *al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_PROCESS_KEY_SHARE_EXT, SSL_R_BAD_ECPOINT);
+            return 0;
+        }
+
+        found = 1;
+    }
+
+    return 1;
+}
+
 /*
  * Loop through all remaining ClientHello extensions that we collected earlier
  * and haven't already processed. For each one parse it and update the SSL
@@ -1792,6 +2136,15 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
     s->srtp_profile = NULL;
 
     /*
+     * We process the supported_groups extension first so that is done before
+     * we get to key_share which needs to use the information in it.
+     */
+    if (!tls_process_supported_groups(s, hello)) {
+        *al = TLS1_AD_INTERNAL_ERROR;
+        return 0;
+    }
+
+    /*
      * We parse all extensions to ensure the ClientHello is well-formed but,
      * unless an extension specifies otherwise, we ignore extensions upon
      * resumption.
@@ -1932,26 +2285,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
                     return 0;
                 }
             }
-        } else if (currext->type == TLSEXT_TYPE_supported_groups) {
-            PACKET supported_groups_list;
-
-            /* Each group is 2 bytes and we must have at least 1. */
-            if (!PACKET_as_length_prefixed_2(&currext->data,
-                                             &supported_groups_list)
-                || PACKET_remaining(&supported_groups_list) == 0
-                || (PACKET_remaining(&supported_groups_list) % 2) != 0) {
-                return 0;
-            }
-
-            if (!s->hit) {
-                if (!PACKET_memdup(&supported_groups_list,
-                                   &s->session->tlsext_supportedgroupslist,
-                                   &s->
-                                   session->tlsext_supportedgroupslist_length)) {
-                    *al = TLS1_AD_INTERNAL_ERROR;
-                    return 0;
-                }
-            }
         }
 #endif                          /* OPENSSL_NO_EC */
         else if (currext->type == TLSEXT_TYPE_session_ticket) {
@@ -2106,8 +2439,13 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al)
         }
 #endif
         else if (currext->type == TLSEXT_TYPE_encrypt_then_mac
-                 && !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC))
+                 && !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) {
             s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
+        } else if (currext->type == TLSEXT_TYPE_key_share
+                   && SSL_IS_TLS13(s) && !s->hit
+                   && !process_key_share_ext(s, &currext->data, al)) {
+            return 0;
+        }
         /*
          * Note: extended master secret extension handled in
          * tls_check_client_ems_support()
@@ -2396,16 +2734,70 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
                 s->s3->tmp.new_cipher->algorithm_mac != SSL_AEAD
                 && s->s3->tmp.new_cipher->algorithm_enc != SSL_RC4)
                 s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
-        } else if (type == TLSEXT_TYPE_extended_master_secret) {
+        } else if (type == TLSEXT_TYPE_extended_master_secret &&
+                (SSL_IS_DTLS(s) || !SSL_IS_TLS13(s))) {
             s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
             if (!s->hit)
                 s->session->flags |= SSL_SESS_FLAG_EXTMS;
-        }
+        } else if (type == TLSEXT_TYPE_key_share
+                && SSL_IS_TLS13(s)) {
+            unsigned int group_id;
+            PACKET encoded_pt;
+            EVP_PKEY *ckey = s->s3->tmp.pkey, *skey = NULL;
+
+            /* Sanity check */
+            if (ckey == NULL) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+
+            if (!PACKET_get_net_2(&spkt, &group_id)) {
+                *al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
+                       SSL_R_LENGTH_MISMATCH);
+                return 0;
+            }
+
+            if (group_id != s->s3->group_id) {
+                /*
+                 * This isn't for the group that we sent in the original
+                 * key_share!
+                 */
+                *al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
+                       SSL_R_BAD_KEY_SHARE);
+                return 0;
+            }
+
+            if (!PACKET_as_length_prefixed_2(&spkt, &encoded_pt)
+                    || PACKET_remaining(&encoded_pt) == 0) {
+                *al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
+                       SSL_R_LENGTH_MISMATCH);
+                return 0;
+            }
+
+            skey = ssl_generate_pkey(ckey);
+            if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt),
+                                                PACKET_remaining(&encoded_pt))) {
+                *al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, SSL_R_BAD_ECPOINT);
+                return 0;
+            }
+
+            if (ssl_derive(s, ckey, skey, 1) == 0) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                EVP_PKEY_free(skey);
+                return 0;
+            }
+            EVP_PKEY_free(skey);
         /*
          * If this extension type was not otherwise handled, but matches a
          * custom_cli_ext_record, then send it to the c callback
          */
-        else if (custom_ext_parse(s, 0, type, data, size, al) <= 0)
+        } else if (custom_ext_parse(s, 0, type, data, size, al) <= 0)
             return 0;
     }
 
@@ -2839,7 +3231,7 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
 
 /*
  * Sets the extended master secret flag if the extension is present in the
- * ClientHello
+ * ClientHello and we can support it
  * Returns:
  *  1 on success
  *  0 on error
@@ -2850,7 +3242,8 @@ int tls_check_client_ems_support(SSL *s, const CLIENTHELLO_MSG *hello)
 
     s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS;
 
-    if (s->version <= SSL3_VERSION)
+    if (!SSL_IS_DTLS(s) && (s->version < TLS1_VERSION
+                            || s->version > TLS1_2_VERSION))
         return 1;
 
     emsext = tls_get_extension_by_type(hello->pre_proc_exts,
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index 2e94c65..42cf2be 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -447,6 +447,7 @@ static ssl_trace_tbl ssl_exts_tbl[] = {
     {TLSEXT_TYPE_client_authz, "client_authz"},
     {TLSEXT_TYPE_server_authz, "server_authz"},
     {TLSEXT_TYPE_cert_type, "cert_type"},
+    {TLSEXT_TYPE_key_share, "key_share"},
     {TLSEXT_TYPE_supported_groups, "supported_groups"},
     {TLSEXT_TYPE_ec_point_formats, "ec_point_formats"},
     {TLSEXT_TYPE_srp, "srp"},
@@ -645,7 +646,7 @@ static int ssl_print_signature(BIO *bio, int indent, SSL *s,
 static int ssl_print_extension(BIO *bio, int indent, int server, int extype,
                                const unsigned char *ext, size_t extlen)
 {
-    size_t xlen;
+    size_t xlen, share_len;
     BIO_indent(bio, indent, 80);
     BIO_printf(bio, "extension_type=%s(%d), length=%d\n",
                ssl_trace_str(extype, ssl_exts_tbl), extype, (int)extlen);
@@ -718,6 +719,35 @@ static int ssl_print_extension(BIO *bio, int indent, int server, int extype,
             ssl_print_hex(bio, indent + 4, "ticket", ext, extlen);
         break;
 
+    case TLSEXT_TYPE_key_share:
+        if (extlen < 2)
+            return 0;
+        if (server) {
+            xlen = extlen;
+        } else {
+            xlen = (ext[0] << 8) | ext[1];
+            if (extlen != xlen + 2)
+                return 0;
+            ext += 2;
+        }
+        for (; xlen > 0; ext += share_len, xlen -= share_len) {
+            int group_id;
+
+            if (xlen < 4)
+                return 0;
+            group_id = (ext[0] << 8) | ext[1];
+            share_len = (ext[2] << 8) | ext[3];
+            ext += 4;
+            xlen -= 4;
+            if (xlen < share_len)
+                return 0;
+            BIO_indent(bio, indent + 4, 80);
+            BIO_printf(bio, "NamedGroup: %s\n",
+                       ssl_trace_str(group_id, ssl_groups_tbl));
+            ssl_print_hex(bio, indent + 4, "key_exchange: ", ext, share_len);
+        }
+        break;
+
     case TLSEXT_TYPE_supported_versions:
         if (extlen < 1)
             return 0;
diff --git a/test/recipes/70-test_key_share.t b/test/recipes/70-test_key_share.t
new file mode 100755
index 0000000..380b1a8
--- /dev/null
+++ b/test/recipes/70-test_key_share.t
@@ -0,0 +1,326 @@
+#! /usr/bin/env perl
+# Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/;
+use OpenSSL::Test::Utils;
+use TLSProxy::Proxy;
+use File::Temp qw(tempfile);
+
+use constant {
+    LOOK_ONLY => 0,
+    EMPTY_EXTENSION => 1,
+    MISSING_EXTENSION => 2,
+    NO_ACCEPTABLE_KEY_SHARES => 3,
+    NON_PREFERRED_KEY_SHARE => 4,
+    ACCEPTABLE_AT_END => 5,
+    NOT_IN_SUPPORTED_GROUPS => 6,
+    GROUP_ID_TOO_SHORT => 7,
+    KEX_LEN_MISMATCH => 8,
+    ZERO_LEN_KEX_DATA => 9,
+    TRAILING_DATA => 10,
+    SELECT_X25519 => 11
+};
+
+use constant {
+    CLIENT_TO_SERVER => 1,
+    SERVER_TO_CLIENT => 2
+};
+
+
+use constant {
+    X25519 => 0x1d,
+    P_256 => 0x17
+};
+
+my $testtype;
+my $direction;
+my $selectedgroupid;
+
+my $test_name = "test_key_share";
+setup($test_name);
+
+plan skip_all => "TLSProxy isn't usable on $^O"
+    if $^O =~ /^(VMS|MSWin32)$/;
+
+plan skip_all => "$test_name needs the dynamic engine feature enabled"
+    if disabled("engine") || disabled("dynamic-engine");
+
+plan skip_all => "$test_name needs the sock feature enabled"
+    if disabled("sock");
+
+plan skip_all => "$test_name needs TLS1.3 enabled"
+    if disabled("tls1_3");
+
+$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
+
+my $proxy = TLSProxy::Proxy->new(
+    undef,
+    cmdstr(app(["openssl"]), display => 1),
+    srctop_file("apps", "server.pem"),
+    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
+);
+
+#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
+$testtype = EMPTY_EXTENSION;
+$direction = CLIENT_TO_SERVER;
+$proxy->filter(\&modify_key_shares_filter);
+$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
+plan tests => 17;
+#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");
+
+#Test 2: 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
+$proxy->clear();
+$testtype = NO_ACCEPTABLE_KEY_SHARES;
+$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");
+
+#Test 4: A non preferred but acceptable key_share should succeed
+$proxy->clear();
+$proxy->filter(undef);
+$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
+#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
+#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
+$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
+$proxy->clear();
+$testtype = KEX_LEN_MISMATCH;
+$proxy->start();
+ok(TLSProxy::Message->fail(), "key_exchange length mismatch");
+
+#Test 9: 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
+$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
+$proxy->clear();
+$direction = SERVER_TO_CLIENT;
+$testtype = LOOK_ONLY;
+$proxy->clientflags("-curves P-256:X25519");
+$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)
+$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
+$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
+$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
+$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
+$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
+$proxy->clear();
+$testtype = TRAILING_DATA;
+$proxy->start();
+ok(TLSProxy::Message->fail(), "key_share trailing data in ServerHello");
+
+
+sub modify_key_shares_filter
+{
+    my $proxy = shift;
+
+    # We're only interested in the initial ClientHello
+    if (($direction == CLIENT_TO_SERVER && $proxy->flight != 0)
+            || ($direction == SERVER_TO_CLIENT && $proxy->flight != 1)) {
+        return;
+    }
+
+    foreach my $message (@{$proxy->message_list}) {
+        if ($message->mt == TLSProxy::Message::MT_CLIENT_HELLO
+                && $direction == CLIENT_TO_SERVER) {
+            my $ext;
+            my $suppgroups;
+
+            #Setup supported groups to include some unrecognised groups
+            $suppgroups = pack "C8",
+                0x00, 0x06, #List Length
+                0xff, 0xfe, #Non existing group 1
+                0xff, 0xff, #Non existing group 2
+                0x00, 0x1d; #x25519
+
+            if ($testtype == EMPTY_EXTENSION) {
+                $ext = pack "C2",
+                    0x00, 0x00;
+            } elsif ($testtype == NO_ACCEPTABLE_KEY_SHARES) {
+                $ext = pack "C12",
+                    0x00, 0x0a, #List Length
+                    0xff, 0xfe, #Non existing group 1
+                    0x00, 0x01, 0xff, #key_exchange data
+                    0xff, 0xff, #Non existing group 2
+                    0x00, 0x01, 0xff; #key_exchange data
+            } elsif ($testtype == ACCEPTABLE_AT_END) {
+                $ext = pack "C11H64",
+                    0x00, 0x29, #List Length
+                    0xff, 0xfe, #Non existing group 1
+                    0x00, 0x01, 0xff, #key_exchange data
+                    0x00, 0x1d, #x25519
+                    0x00, 0x20, #key_exchange data length
+                    "155155B95269ED5C87EAA99C2EF5A593".
+                    "EDF83495E80380089F831B94D14B1421";  #key_exchange data
+            } elsif ($testtype == NOT_IN_SUPPORTED_GROUPS) {
+                $suppgroups = pack "C4",
+                    0x00, 0x02, #List Length
+                    0x00, 0xfe; #Non existing group 1
+            } elsif ($testtype == GROUP_ID_TOO_SHORT) {
+                $ext = pack "C6H64C1",
+                    0x00, 0x25, #List Length
+                    0x00, 0x1d, #x25519
+                    0x00, 0x20, #key_exchange data length
+                    "155155B95269ED5C87EAA99C2EF5A593".
+                    "EDF83495E80380089F831B94D14B1421";  #key_exchange data
+                    0x00;       #Group id too short
+            } elsif ($testtype == KEX_LEN_MISMATCH) {
+                $ext = pack "C8",
+                    0x00, 0x06, #List Length
+                    0x00, 0x1d, #x25519
+                    0x00, 0x20, #key_exchange data length
+                    0x15, 0x51; #Only two bytes of data, but length should be 32
+            } elsif ($testtype == ZERO_LEN_KEX_DATA) {
+                $ext = pack "C10H64",
+                    0x00, 0x28, #List Length
+                    0xff, 0xfe, #Non existing group 1
+                    0x00, 0x00, #zero length key_exchange data is invalid
+                    0x00, 0x1d, #x25519
+                    0x00, 0x20, #key_exchange data length
+                    "155155B95269ED5C87EAA99C2EF5A593".
+                    "EDF83495E80380089F831B94D14B1421";  #key_exchange data
+            } elsif ($testtype == TRAILING_DATA) {
+                $ext = pack "C6H64C1",
+                    0x00, 0x24, #List Length
+                    0x00, 0x1d, #x25519
+                    0x00, 0x20, #key_exchange data length
+                    "155155B95269ED5C87EAA99C2EF5A593".
+                    "EDF83495E80380089F831B94D14B1421", #key_exchange data
+                    0x00; #Trailing garbage
+            }
+
+            $message->set_extension(
+                TLSProxy::Message::EXT_SUPPORTED_GROUPS, $suppgroups);
+
+            if ($testtype == MISSING_EXTENSION) {
+                $message->delete_extension(
+                    TLSProxy::Message::EXT_KEY_SHARE);
+            } elsif ($testtype != NOT_IN_SUPPORTED_GROUPS) {
+                $message->set_extension(
+                    TLSProxy::Message::EXT_KEY_SHARE, $ext);
+            }
+
+            $message->repack();
+        } elsif ($message->mt == TLSProxy::Message::MT_SERVER_HELLO
+                     && $direction == SERVER_TO_CLIENT) {
+            my $ext;
+            my $key_share =
+                ${$message->extension_data}{TLSProxy::Message::EXT_KEY_SHARE};
+            $selectedgroupid = unpack("n", $key_share);
+
+            if ($testtype == LOOK_ONLY) {
+                return;
+            }
+            if ($testtype == SELECT_X25519) {
+                $ext = pack "C4H64",
+                    0x00, 0x1d, #x25519
+                    0x00, 0x20, #key_exchange data length
+                    "155155B95269ED5C87EAA99C2EF5A593".
+                    "EDF83495E80380089F831B94D14B1421";  #key_exchange data
+            } elsif ($testtype == GROUP_ID_TOO_SHORT) {
+                $ext = pack "C1",
+                    0x00;
+            } elsif ($testtype == KEX_LEN_MISMATCH) {
+                $ext = pack "C6",
+                    0x00, 0x1d, #x25519
+                    0x00, 0x20, #key_exchange data length
+                    0x15, 0x51; #Only two bytes of data, but length should be 32
+            } elsif ($testtype == ZERO_LEN_KEX_DATA) {
+                $ext = pack "C4",
+                    0x00, 0x1d, #x25519
+                    0x00, 0x00, #zero length key_exchange data is invalid
+            } elsif ($testtype == TRAILING_DATA) {
+                $ext = pack "C4H64C1",
+                    0x00, 0x1d, #x25519
+                    0x00, 0x20, #key_exchange data length
+                    "155155B95269ED5C87EAA99C2EF5A593".
+                    "EDF83495E80380089F831B94D14B1421", #key_exchange data
+                    0x00; #Trailing garbage
+            }
+            $message->set_extension( TLSProxy::Message::EXT_KEY_SHARE, $ext);
+
+            $message->repack();
+        }
+    }
+}
+
+
diff --git a/test/recipes/70-test_sslsessiontick.t b/test/recipes/70-test_sslsessiontick.t
index 89ef12f..0c29ec7 100755
--- a/test/recipes/70-test_sslsessiontick.t
+++ b/test/recipes/70-test_sslsessiontick.t
@@ -229,7 +229,7 @@ sub checkmessages($$$$$$)
 			$shellotickext = 1;
 		    }
 		}
-	    } elsif ($message->mt == TLSProxy::Message::MT_CLIENT_KEY_EXCHANGE) {
+	    } elsif ($message->mt == TLSProxy::Message::MT_CERTIFICATE) {
 		#Must be doing a full handshake
 		$fullhand = 1;
 	    } elsif ($message->mt == TLSProxy::Message::MT_NEW_SESSION_TICKET) {
diff --git a/test/recipes/70-test_tlsextms.t b/test/recipes/70-test_tlsextms.t
index 1248594..dc6cf75 100644
--- a/test/recipes/70-test_tlsextms.t
+++ b/test/recipes/70-test_tlsextms.t
@@ -24,8 +24,8 @@ plan skip_all => "$test_name needs the dynamic engine feature enabled"
 plan skip_all => "$test_name needs the sock feature enabled"
     if disabled("sock");
 
-plan skip_all => "$test_name needs TLS enabled"
-    if alldisabled(available_protocols("tls"));
+plan skip_all => "$test_name needs TLSv1.0, TLSv1.1 or TLSv1.2 enabled"
+    if disabled("tls1") && disabled("tls1_1") && disabled("tls1_2");
 
 $ENV{OPENSSL_ia32cap} = '~0x200000200000000';
 
@@ -46,14 +46,19 @@ my $proxy = TLSProxy::Proxy->new(
     (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
 );
 
+#Note that EXTMS is only relevant for <TLS1.3
+
 #Test 1: By default server and client should send extended master secret
 # extension.
 #Expected result: ClientHello extension seen; ServerHello extension seen
 #                 Full handshake
 
 setrmextms(0, 0);
+$proxy->clientflags("-no_tls1_3");
 $proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 9;
+my $numtests = 9;
+$numtests++ if (!disabled("tls1_3"));
+plan tests => $numtests;
 checkmessages(1, "Default extended master secret test", 1, 1, 1);
 
 #Test 2: If client omits extended master secret extension, server should too.
@@ -62,6 +67,7 @@ checkmessages(1, "Default extended master secret test", 1, 1, 1);
 
 clearall();
 setrmextms(1, 0);
+$proxy->clientflags("-no_tls1_3");
 $proxy->start();
 checkmessages(2, "No client extension extended master secret test", 0, 0, 1);
 
@@ -69,7 +75,7 @@ checkmessages(2, "No client extension extended master secret test", 0, 0, 1);
 # Expected result: same as test 1.
 
 clearall();
-$proxy->clientflags("-no_ticket");
+$proxy->clientflags("-no_ticket -no_tls1_3");
 setrmextms(0, 0);
 $proxy->start();
 checkmessages(3, "No ticket extended master secret test", 1, 1, 1);
@@ -78,10 +84,10 @@ checkmessages(3, "No ticket extended master secret test", 1, 1, 1);
 # Expected result: same as test 2.
 
 clearall();
-$proxy->clientflags("-no_ticket");
+$proxy->clientflags("-no_ticket -no_tls1_3");
 setrmextms(1, 0);
 $proxy->start();
-checkmessages(2, "No ticket, no client extension extended master secret test", 0, 0, 1);
+checkmessages(4, "No ticket, no client extension extended master secret test", 0, 0, 1);
 
 #Test 5: Session resumption extended master secret test
 #
@@ -92,10 +98,10 @@ clearall();
 setrmextms(0, 0);
 (undef, my $session) = tempfile();
 $proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
 $proxy->start();
 $proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
 $proxy->clientstart();
 checkmessages(5, "Session resumption extended master secret test", 1, 1, 0);
 unlink $session;
@@ -109,10 +115,10 @@ clearall();
 setrmextms(1, 0);
 (undef, $session) = tempfile();
 $proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
 $proxy->start();
 $proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
 setrmextms(0, 0);
 $proxy->clientstart();
 checkmessages(6, "Session resumption extended master secret test", 1, 1, 1);
@@ -126,10 +132,10 @@ clearall();
 setrmextms(0, 0);
 (undef, $session) = tempfile();
 $proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
 $proxy->start();
 $proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
 setrmextms(1, 0);
 $proxy->clientstart();
 ok(TLSProxy::Message->fail(), "Client inconsistent session resumption");
@@ -143,10 +149,10 @@ clearall();
 setrmextms(0, 0);
 (undef, $session) = tempfile();
 $proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
 $proxy->start();
 $proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
 setrmextms(0, 1);
 $proxy->clientstart();
 ok(TLSProxy::Message->fail(), "Server inconsistent session resumption 1");
@@ -160,15 +166,27 @@ clearall();
 setrmextms(0, 1);
 (undef, $session) = tempfile();
 $proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
 $proxy->start();
 $proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
 setrmextms(0, 0);
 $proxy->clientstart();
 ok(TLSProxy::Message->fail(), "Server inconsistent session resumption 2");
 unlink $session;
 
+#Test 10: In TLS1.3 we should not negotiate extended master secret
+#Expected result: ClientHello extension seen; ServerHello extension not seen
+#                 TLS1.3 handshake (will appear as abbreviated handshake
+#                 because of no CKE message)
+if (!disabled("tls1_3")) {
+    clearall();
+    setrmextms(0, 0);
+    $proxy->start();
+    checkmessages(10, "TLS1.3 extended master secret test", 1, 0, 0);
+}
+
+
 sub extms_filter
 {
     my $proxy = shift;
diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t
index d89aa3c..65d2be9 100644
--- a/test/recipes/80-test_ssl_new.t
+++ b/test/recipes/80-test_ssl_new.t
@@ -62,7 +62,8 @@ my %conf_dependent_tests = (
 # conditions.
 my %skip = (
   "07-dtls-protocol-version.conf" => $no_dtls,
-  "08-npn.conf" => $no_tls || $no_npn,
+  "08-npn.conf" => (disabled("tls1") && disabled("tls1_1")
+                    && disabled("tls1_2")) || $no_npn,
   "10-resumption.conf" => disabled("tls1_1") || disabled("tls1_2"),
   "11-dtls_resumption.conf" => disabled("dtls1") || disabled("dtls1_2"),
   "12-ct.conf" => $no_tls || $no_ct || $no_ec,
diff --git a/test/ssl-tests/08-npn.conf b/test/ssl-tests/08-npn.conf
index 9115ef4..f38b3f6 100644
--- a/test/ssl-tests/08-npn.conf
+++ b/test/ssl-tests/08-npn.conf
@@ -38,6 +38,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [0-npn-simple-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -69,6 +70,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [1-npn-client-finds-match-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -100,6 +102,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [2-npn-client-honours-server-pref-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -131,6 +134,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [3-npn-client-first-pref-on-mismatch-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -162,6 +166,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [4-npn-no-server-support-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -188,6 +193,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [5-npn-no-client-support-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -220,6 +226,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [6-npn-with-sni-no-context-switch-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -264,6 +271,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [7-npn-with-sni-context-switch-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -308,6 +316,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [8-npn-selected-sni-server-supports-npn-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -351,6 +360,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [9-npn-selected-sni-server-does-not-support-npn-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -384,6 +394,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [10-alpn-preferred-over-npn-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -423,6 +434,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [11-sni-npn-preferred-over-alpn-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -464,6 +476,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [12-npn-simple-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -506,6 +519,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [13-npn-server-switch-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -546,11 +560,13 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [14-npn-client-switch-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [14-npn-client-switch-resumption-resume-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -596,6 +612,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [15-npn-client-first-pref-on-mismatch-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -641,6 +658,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [16-npn-no-server-support-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -676,11 +694,13 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [17-npn-no-client-support-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [17-npn-no-client-support-resumption-resume-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -721,6 +741,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [18-alpn-preferred-over-npn-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
@@ -768,6 +789,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
 [19-npn-used-if-alpn-not-supported-resumption-client]
 CipherString = DEFAULT
+MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
diff --git a/test/ssl-tests/08-npn.conf.in b/test/ssl-tests/08-npn.conf.in
index 8a1f4ec..b5df13d 100644
--- a/test/ssl-tests/08-npn.conf.in
+++ b/test/ssl-tests/08-npn.conf.in
@@ -7,14 +7,13 @@
 # https://www.openssl.org/source/license.html
 
 
-## Test version negotiation
+## Test NPN. Note that NPN is only supported up to TLSv1.2
 
 use strict;
 use warnings;
 
 package ssltests;
 
-
 our @tests = (
     {
         name => "npn-simple",
@@ -27,6 +26,7 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedNPNProtocol" => "foo",
@@ -43,6 +43,7 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo,bar",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedNPNProtocol" => "bar",
@@ -59,6 +60,7 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo,bar",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedNPNProtocol" => "bar",
@@ -75,6 +77,7 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo,bar",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedNPNProtocol" => "foo",
@@ -82,11 +85,12 @@ our @tests = (
     },
     {
         name => "npn-no-server-support",
-        server => { },
+        server => {},
         client => {
             extra => {
                 "NPNProtocols" => "foo",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedNPNProtocol" => undef,
@@ -99,7 +103,9 @@ our @tests = (
                 "NPNProtocols" => "foo",
             },
         },
-        client => { },
+        client => {
+            "MaxProtocol" => "TLSv1.2"
+        },
         test => {
             "ExpectedNPNProtocol" => undef,
         },
@@ -122,6 +128,7 @@ our @tests = (
                 "NPNProtocols" => "foo,bar",
                 "ServerName" => "server1",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedServerName" => "server1",
@@ -146,6 +153,7 @@ our @tests = (
                 "NPNProtocols" => "foo,bar",
                 "ServerName" => "server2",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedServerName" => "server2",
@@ -169,6 +177,7 @@ our @tests = (
                 "NPNProtocols" => "foo,bar",
                 "ServerName" => "server2",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedServerName" => "server2",
@@ -189,6 +198,7 @@ our @tests = (
                 "NPNProtocols" => "foo,bar",
                 "ServerName" => "server2",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
              "ExpectedServerName" => "server2",
@@ -208,6 +218,7 @@ our @tests = (
                 "ALPNProtocols" => "foo",
                 "NPNProtocols" => "bar",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedALPNProtocol" => "foo",
@@ -233,6 +244,7 @@ our @tests = (
                 "ALPNProtocols" => "foo",
                 "NPNProtocols" => "bar",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "ExpectedALPNProtocol" => undef,
@@ -251,6 +263,7 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "HandshakeMode" => "Resume",
@@ -274,6 +287,7 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo,bar,baz",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "HandshakeMode" => "Resume",
@@ -292,11 +306,13 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo,baz",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         resume_client => {
             extra => {
                 "NPNProtocols" => "bar,baz",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "HandshakeMode" => "Resume",
@@ -320,6 +336,7 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo,bar",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "HandshakeMode" => "Resume",
@@ -339,6 +356,7 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "HandshakeMode" => "Resume",
@@ -357,8 +375,11 @@ our @tests = (
             extra => {
                 "NPNProtocols" => "foo",
             },
+            "MaxProtocol" => "TLSv1.2"
+        },
+        resume_client => {
+            "MaxProtocol" => "TLSv1.2"
         },
-        resume_client => { },
         test => {
             "HandshakeMode" => "Resume",
             "ResumptionExpected" => "Yes",
@@ -383,6 +404,7 @@ our @tests = (
                 "ALPNProtocols" => "foo",
                 "NPNProtocols" => "bar,baz",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "HandshakeMode" => "Resume",
@@ -409,6 +431,7 @@ our @tests = (
                 "ALPNProtocols" => "foo",
                 "NPNProtocols" => "bar,baz",
             },
+            "MaxProtocol" => "TLSv1.2"
         },
         test => {
             "HandshakeMode" => "Resume",
diff --git a/util/TLSProxy/Message.pm b/util/TLSProxy/Message.pm
index 8a14dea..6bf5a72 100644
--- a/util/TLSProxy/Message.pm
+++ b/util/TLSProxy/Message.pm
@@ -59,10 +59,12 @@ my %message_type = (
 
 use constant {
     EXT_STATUS_REQUEST => 5,
+    EXT_SUPPORTED_GROUPS => 10,
     EXT_ENCRYPT_THEN_MAC => 22,
     EXT_EXTENDED_MASTER_SECRET => 23,
     EXT_SESSION_TICKET => 35,
     EXT_SUPPORTED_VERSIONS => 43,
+    EXT_KEY_SHARE => 40,
     # This extension does not exist and isn't recognised by OpenSSL.
     # We use it to test handling of duplicate extensions.
     EXT_DUPLICATE_EXTENSION => 1234


More information about the openssl-commits mailing list