Start using the key_share data to derive the PMS
authorMatt Caswell <matt@openssl.org>
Wed, 2 Nov 2016 15:03:56 +0000 (15:03 +0000)
committerMatt Caswell <matt@openssl.org>
Wed, 16 Nov 2016 10:09:46 +0000 (10:09 +0000)
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@openssl.org>
13 files changed:
include/openssl/ssl.h
ssl/s3_lib.c
ssl/ssl_err.c
ssl/ssl_locl.h
ssl/statem/statem_clnt.c
ssl/statem/statem_srvr.c
ssl/t1_enc.c
ssl/t1_lib.c
test/recipes/70-test_sslsessiontick.t
test/recipes/70-test_tlsextms.t
test/recipes/80-test_ssl_new.t
test/ssl-tests/08-npn.conf
test/ssl-tests/08-npn.conf.in

index fdef8c54e3d2d5d778c6fdd471b2dc14810a99de..f05ec9d0b49df765fd41c36f6e821a566878a578 100644 (file)
@@ -2099,8 +2099,10 @@ 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_READ_STATE_MACHINE                         352
index 2439167307f66f490ad0d2e16cc8991b169ad6d1..bcc0f9e5fd3367e86f7fc7054dd9baeb49480896 100644 (file)
@@ -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;
index fcd4375c24fd7ccf358e04f3ad2a6fdee8195363..4b4559d08eea80bb0397a7b2669fd3fdaa948d57 100644 (file)
@@ -49,10 +49,14 @@ 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),
index ec0d0b48248d5355eeebf714f72ba3e2e55fe96a..88b2f8b575598dfca2b89e0f30107efaf0c830ab 100644 (file)
@@ -1879,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);
index e0d53fe33b546872f6b404da0f86902a650a6a88..feda8d211986e3cb34e3d96863d6703b3ae4ff16 100644 (file)
@@ -106,6 +106,112 @@ static int key_exchange_expected(SSL *s)
     return 0;
 }
 
+/*
+ * 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: Success (transition allowed)
+ *  0: Error (transition not allowed)
+ */
+static int ossl_statem_client13_read_transition(SSL *s, int mt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * 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
@@ -121,6 +227,13 @@ 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 +384,94 @@ 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.
+ *
+ * Return values:
+ * WRITE_TRAN_ERROR - an error occurred
+ * WRITE_TRAN_CONTINUE - Successful transition, more writing to be done
+ * WRITE_TRAN_FINISHED - Successful transition, no more writing to be done
+ */
+static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * 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:
+        if (s->s3->tmp.cert_req)
+            st->hand_state = TLS_ST_CW_CERT;
+        else
+            st->hand_state = TLS_ST_CW_CHANGE;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_CERT:
+        /* If a non-empty Certificate we also send CertificateVerify */
+        if (s->s3->tmp.cert_req == 1)
+            st->hand_state = TLS_ST_CW_CERT_VRFY;
+        else
+            st->hand_state = 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;
+        } else {
+            return WRITE_TRAN_FINISHED;
+        }
+
+    case TLS_ST_CR_FINISHED:
+        if (s->hit) {
+            st->hand_state = TLS_ST_CW_CHANGE;
+            return WRITE_TRAN_CONTINUE;
+        } else {
+            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.
+ *
+ * Return values:
+ * WRITE_TRAN_ERROR - an error occurred
+ * WRITE_TRAN_CONTINUE - Successful transition, more writing to be done
+ * WRITE_TRAN_FINISHED - Successful transition, no more writing to be done
  */
 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 +2476,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 +2512,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 +2820,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;
index 38a1b6931d8b76df775cc58c99f2539fb881be29..0e910aa2f2e51c46a1555425320066691edd0be6 100644 (file)
@@ -68,10 +68,90 @@ 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)
+ */
+static int ossl_statem_server13_read_transition(SSL *s, int mt)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * 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|.
  *
  *  Valid return values are:
  *  1: Success (transition allowed)
@@ -81,6 +161,9 @@ 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 +387,116 @@ 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.
+ *
+ * Return values:
+ * WRITE_TRAN_ERROR - an error occurred
+ * WRITE_TRAN_CONTINUE - Successful transition, more writing to be done
+ * WRITE_TRAN_FINISHED - Successful transition, no more writing to be done
+ */
+static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
+
+    /*
+     * 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) {
+            if (s->tlsext_ticket_expected)
+                st->hand_state = TLS_ST_SW_SESSION_TICKET;
+            else
+                st->hand_state = 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;
+        } else if (s->tlsext_ticket_expected) {
+            st->hand_state = TLS_ST_SW_SESSION_TICKET;
+        } else {
+            st->hand_state = 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.
+ *
+ * Return values:
+ * WRITE_TRAN_ERROR - an error occurred
+ * WRITE_TRAN_CONTINUE - Successful transition, more writing to be done
+ * WRITE_TRAN_FINISHED - Successful transition, no more writing to be done
  */
 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 */
@@ -2316,7 +2502,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;
@@ -2376,7 +2562,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;
@@ -2776,6 +2962,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
@@ -2931,6 +3118,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 (s->version == TLS1_3_VERSION && !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
index 8d1e350a6110656dde7f46253ff88a2a2bf3e718..df2ce3703057e9879fe353c92b6112e5894aee67 100644 (file)
@@ -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 has). This will need to be removed later
+     */
+    if ((s->session->flags & SSL_SESS_FLAG_EXTMS)
+            && s->version != TLS1_3_VERSION) {
         unsigned char hash[EVP_MAX_MD_SIZE * 2];
         size_t hashlen;
         /*
index f87b7ef1ea1ce60523f3ce9f2b8759c359dcc0e3..46ca29099e6e6c9c71e89ef7d574005bf5fa3dd0 100644 (file)
@@ -1684,9 +1684,15 @@ int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al)
             OPENSSL_free(encodedPoint);
             return 0;
         }
+        OPENSSL_free(encodedPoint);
 
         s->s3->tmp.pkey = skey;
-        OPENSSL_free(encodedPoint);
+
+        if (ssl_derive(s, skey, ckey, 1) == 0) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
     }
 
     if (!custom_ext_add(s, 1, pkt, al)) {
@@ -2633,7 +2639,8 @@ 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) || s->version < TLS1_3_VERSION)) {
             s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
             if (!s->hit)
                 s->session->flags |= SSL_SESS_FLAG_EXTMS;
@@ -2668,7 +2675,6 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
                 return 0;
             }
 
-            /* TODO(TLS1.3): Create skey from ckey */
             skey = ssl_generate_pkey(ckey);
 
             if (!PACKET_as_length_prefixed_2(&spkt, &encoded_pt)) {
@@ -2685,10 +2691,12 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
                 return 0;
             }
 
-            /*
-             * TODO(TLS1.3): Throw it all away for now, later we will use the
-             * two keys.
-             */
+            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
@@ -3128,7 +3136,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
@@ -3139,7 +3147,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,
index 89ef12f75bc45b8a905960528befdfea01a143ea..0c29ec7ce0dd894ffa59e04c46f77ec33c92c1d1 100755 (executable)
@@ -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) {
index 1248594c068331fa71e324c534c6a9092aeb4aa3..dd2a6a47f639a98deef7544092fc85e9c00d0471 100644 (file)
@@ -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,21 @@ 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;
+if (!disabled("tls1_3")) {
+    $numtests++;
+}
+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 +69,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 +77,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 +86,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 +100,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 +117,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 +134,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 +151,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 +168,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;
index d89aa3cf059af8ee1b050b9373f9042ad4a9f194..65d2be9e5e2d39bd43ee2116f009e1b8b98856da 100644 (file)
@@ -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,
index 9115ef458b890c5f5c0cf54ce1cd5d31aa548896..f38b3f6975ce0656e56ee3a4fba9259a52ae968d 100644 (file)
@@ -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
 
index 8a1f4ec91630bade4fe28c2bd90069617a7f88ec..b5df13d5a9ad57e5024d60261365f344eb021a13 100644 (file)
@@ -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",