Update crypto negotation to draft 15.

BUG=77

Change-Id: If568412655aae240b072c29d763a5b17bb5ca3f7
Reviewed-on: https://boringssl-review.googlesource.com/10840
Reviewed-by: Steven Valdez <svaldez@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index c5b3b1f..31394c0 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -626,18 +626,6 @@
     if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) {
       return 0;
     }
-    /* Add PSK ciphers for TLS 1.3 resumption. */
-    uint16_t session_version;
-    if (ssl->session != NULL &&
-        ssl->method->version_from_wire(&session_version,
-                                       ssl->session->ssl_version) &&
-        session_version >= TLS1_3_VERSION) {
-      uint16_t resumption_cipher;
-      if (ssl_cipher_get_ecdhe_psk_cipher(cipher, &resumption_cipher) &&
-          !CBB_add_u16(&child, resumption_cipher)) {
-        return 0;
-      }
-    }
   }
 
   /* If all ciphers were disabled, return the error to the caller. */
@@ -952,16 +940,16 @@
   }
 
   if (ssl->session != NULL) {
-    if (ssl->session->cipher != c) {
-      al = SSL_AD_ILLEGAL_PARAMETER;
-      OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
-      goto f_err;
-    }
     if (ssl->session->ssl_version != ssl->version) {
       al = SSL_AD_ILLEGAL_PARAMETER;
       OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED);
       goto f_err;
     }
+    if (ssl->session->cipher != c) {
+      al = SSL_AD_ILLEGAL_PARAMETER;
+      OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+      goto f_err;
+    }
     if (!ssl_session_is_context_valid(ssl, ssl->session)) {
       /* This is actually a client application bug. */
       al = SSL_AD_ILLEGAL_PARAMETER;
diff --git a/ssl/internal.h b/ssl/internal.h
index 4719acb..3e7c053 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -172,12 +172,14 @@
 /* SSL_kPSK is only set for plain PSK, not ECDHE_PSK. */
 #define SSL_kPSK 0x00000008L
 #define SSL_kCECPQ1 0x00000010L
+#define SSL_kGENERIC 0x00000020L
 
 /* Bits for |algorithm_auth| (server authentication). */
 #define SSL_aRSA 0x00000001L
 #define SSL_aECDSA 0x00000002L
 /* SSL_aPSK is set for both PSK and ECDHE_PSK. */
 #define SSL_aPSK 0x00000004L
+#define SSL_aGENERIC 0x00000008L
 
 #define SSL_aCERT (SSL_aRSA | SSL_aECDSA)
 
@@ -241,11 +243,6 @@
 /* ssl_cipher_get_value returns the cipher suite id of |cipher|. */
 uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher);
 
-/* ssl_cipher_get_resumption_cipher returns the cipher suite id of the cipher
- * matching |cipher| with PSK enabled. */
-int ssl_cipher_get_ecdhe_psk_cipher(const SSL_CIPHER *cipher,
-                                    uint16_t *out_cipher);
-
 /* ssl_cipher_get_key_type returns the |EVP_PKEY_*| value corresponding to the
  * server key used in |cipher| or |EVP_PKEY_NONE| if there is none. */
 int ssl_cipher_get_key_type(const SSL_CIPHER *cipher);
diff --git a/ssl/ssl_cipher.c b/ssl/ssl_cipher.c
index 4831e9b..08a4e65 100644
--- a/ssl/ssl_cipher.c
+++ b/ssl/ssl_cipher.c
@@ -343,6 +343,41 @@
      SSL_HANDSHAKE_MAC_SHA384,
     },
 
+    /* TLS 1.3 suites. */
+
+    /* Cipher 1301 */
+    {
+      TLS1_TXT_AES_128_GCM_SHA256,
+      TLS1_CK_AES_128_GCM_SHA256,
+      SSL_kGENERIC,
+      SSL_aGENERIC,
+      SSL_AES128GCM,
+      SSL_AEAD,
+      SSL_HANDSHAKE_MAC_SHA256,
+    },
+
+    /* Cipher 1302 */
+    {
+      TLS1_TXT_AES_256_GCM_SHA384,
+      TLS1_CK_AES_256_GCM_SHA384,
+      SSL_kGENERIC,
+      SSL_aGENERIC,
+      SSL_AES256GCM,
+      SSL_AEAD,
+      SSL_HANDSHAKE_MAC_SHA384,
+    },
+
+    /* Cipher 1303 */
+    {
+      TLS1_TXT_CHACHA20_POLY1305_SHA256,
+      TLS1_CK_CHACHA20_POLY1305_SHA256,
+      SSL_kGENERIC,
+      SSL_aGENERIC,
+      SSL_CHACHA20POLY1305,
+      SSL_AEAD,
+      SSL_HANDSHAKE_MAC_SHA256,
+    },
+
     /* CECPQ1 (combined elliptic curve + post-quantum) suites. */
 
     /* Cipher 16B7 */
@@ -608,28 +643,6 @@
      SSL_HANDSHAKE_MAC_SHA256,
     },
 
-    /* Cipher D001 */
-    {
-     TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
-     TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
-     SSL_kECDHE,
-     SSL_aPSK,
-     SSL_AES128GCM,
-     SSL_AEAD,
-     SSL_HANDSHAKE_MAC_SHA256,
-    },
-
-    /* Cipher D002 */
-    {
-     TLS1_TXT_ECDHE_PSK_WITH_AES_256_GCM_SHA384,
-     TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384,
-     SSL_kECDHE,
-     SSL_aPSK,
-     SSL_AES256GCM,
-     SSL_AEAD,
-     SSL_HANDSHAKE_MAC_SHA384,
-    },
-
 };
 
 static const size_t kCiphersLen = OPENSSL_ARRAY_SIZE(kCiphers);
@@ -1063,14 +1076,6 @@
           (min_version != 0 && SSL_CIPHER_get_min_version(cp) != min_version)) {
         continue;
       }
-
-      /* The following ciphers are internal implementation details of TLS 1.3
-       * resumption but are not yet finalized. Disable them by default until
-       * then. */
-      if (cp->id == TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256 ||
-          cp->id == TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384) {
-        continue;
-      }
     }
 
     /* add the cipher if it has not been added yet. */
@@ -1410,15 +1415,17 @@
   /* Now arrange all ciphers by preference:
    * TODO(davidben): Compute this order once and copy it. */
 
-  /* Everything else being equal, prefer ECDHE_ECDSA then ECDHE_RSA over other
-   * key exchange mechanisms */
+  /* Everything else being equal, prefer TLS 1.3 ciphers then ECDHE_ECDSA then
+   * ECDHE_RSA over other key exchange mechanisms */
 
+  ssl_cipher_apply_rule(0, SSL_kGENERIC, SSL_aGENERIC, ~0u, ~0u, 0, CIPHER_ADD,
+                        -1, 0, &head, &tail);
   ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, 0, CIPHER_ADD, -1,
                         0, &head, &tail);
   ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0,
                         &head, &tail);
-  ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0,
-                        &head, &tail);
+  ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0, &head,
+                        &tail);
 
   /* Order the bulk ciphers. First the preferred AEAD ciphers. We prefer
    * CHACHA20 unless there is hardware support for fast and constant-time
@@ -1458,7 +1465,7 @@
                         &tail);
 
   /* Move ciphers without forward secrecy to the end. */
-  ssl_cipher_apply_rule(0, ~(SSL_kDHE | SSL_kECDHE), ~0u, ~0u, ~0u, 0,
+  ssl_cipher_apply_rule(0, (SSL_kRSA | SSL_kPSK), ~0u, ~0u, ~0u, 0,
                         CIPHER_ORD, -1, 0, &head, &tail);
 
   /* Now disable everything (maintaining the ordering!) */
@@ -1569,30 +1576,6 @@
   return id & 0xffff;
 }
 
-int ssl_cipher_get_ecdhe_psk_cipher(const SSL_CIPHER *cipher,
-                                    uint16_t *out_cipher) {
-  switch (cipher->id) {
-    case TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
-    case TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
-    case TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
-      *out_cipher = TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 & 0xffff;
-      return 1;
-
-    case TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
-    case TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
-    case TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256:
-      *out_cipher = TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256 & 0xffff;
-      return 1;
-
-    case TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
-    case TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
-    case TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384:
-      *out_cipher = TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384 & 0xffff;
-      return 1;
-  }
-  return 0;
-}
-
 int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher) {
   return (cipher->algorithm_enc & SSL_AES) != 0;
 }
@@ -1656,6 +1639,11 @@
 }
 
 uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher) {
+  if (cipher->algorithm_mkey == SSL_kGENERIC ||
+      cipher->algorithm_auth == SSL_aGENERIC) {
+    return TLS1_3_VERSION;
+  }
+
   if (cipher->algorithm_prf != SSL_HANDSHAKE_MAC_DEFAULT) {
     /* Cipher suites before TLS 1.2 use the default PRF, while all those added
      * afterwards specify a particular hash. */
@@ -1665,11 +1653,8 @@
 }
 
 uint16_t SSL_CIPHER_get_max_version(const SSL_CIPHER *cipher) {
-  if (cipher->algorithm_mac == SSL_AEAD &&
-      (cipher->algorithm_enc & SSL_CHACHA20POLY1305_OLD) == 0 &&
-      (cipher->algorithm_mkey & SSL_kECDHE) != 0 &&
-      /* TODO(davidben,svaldez): Support PSK-based ciphers in TLS 1.3. */
-      (cipher->algorithm_auth & SSL_aCERT) != 0) {
+  if (cipher->algorithm_mkey == SSL_kGENERIC ||
+      cipher->algorithm_auth == SSL_aGENERIC) {
     return TLS1_3_VERSION;
   }
   return TLS1_2_VERSION;
@@ -1730,6 +1715,10 @@
       assert(cipher->algorithm_auth == SSL_aPSK);
       return "PSK";
 
+    case SSL_kGENERIC:
+      assert(cipher->algorithm_auth == SSL_aGENERIC);
+      return "GENERIC";
+
     default:
       assert(0);
       return "UNKNOWN";
@@ -1788,16 +1777,23 @@
   const char *enc_name = ssl_cipher_get_enc_name(cipher);
   const char *prf_name = ssl_cipher_get_prf_name(cipher);
 
-  /* The final name is TLS_{kx_name}_WITH_{enc_name}_{prf_name}. */
-  size_t len = 4 + strlen(kx_name) + 6 + strlen(enc_name) + 1 +
-      strlen(prf_name) + 1;
+  /* The final name is TLS_{kx_name}_WITH_{enc_name}_{prf_name} or
+   * TLS_{enc_name}_{prf_name} depending on whether the cipher is AEAD-only. */
+  size_t len = 4 + strlen(enc_name) + 1 + strlen(prf_name) + 1;
+
+  if (cipher->algorithm_mkey != SSL_kGENERIC) {
+    len += strlen(kx_name) + 6;
+  }
+
   char *ret = OPENSSL_malloc(len);
   if (ret == NULL) {
     return NULL;
   }
+
   if (BUF_strlcpy(ret, "TLS_", len) >= len ||
-      BUF_strlcat(ret, kx_name, len) >= len ||
-      BUF_strlcat(ret, "_WITH_", len) >= len ||
+      (cipher->algorithm_mkey != SSL_kGENERIC &&
+       (BUF_strlcat(ret, kx_name, len) >= len ||
+        BUF_strlcat(ret, "_WITH_", len) >= len)) ||
       BUF_strlcat(ret, enc_name, len) >= len ||
       BUF_strlcat(ret, "_", len) >= len ||
       BUF_strlcat(ret, prf_name, len) >= len) {
@@ -1805,6 +1801,7 @@
     OPENSSL_free(ret);
     return NULL;
   }
+
   assert(strlen(ret) + 1 == len);
   return ret;
 }
@@ -1885,6 +1882,10 @@
       kx = "PSK";
       break;
 
+    case SSL_kGENERIC:
+      kx = "GENERIC";
+      break;
+
     default:
       kx = "unknown";
   }
@@ -1902,6 +1903,10 @@
       au = "PSK";
       break;
 
+    case SSL_aGENERIC:
+      au = "GENERIC";
+      break;
+
     default:
       au = "unknown";
       break;
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index b580d95..f17dc0a 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1515,7 +1515,8 @@
   SSL_SESSION *session = SSL_get_session(ssl);
   if (session == NULL ||
       session->cipher == NULL ||
-      !SSL_CIPHER_is_ECDHE(session->cipher)) {
+      (ssl3_protocol_version(ssl) < TLS1_3_VERSION &&
+       !SSL_CIPHER_is_ECDHE(session->cipher))) {
     return 0;
   }
 
@@ -2030,6 +2031,12 @@
 
 void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k,
                                        uint32_t *out_mask_a) {
+  if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+    *out_mask_k = SSL_kGENERIC;
+    *out_mask_a = SSL_aGENERIC;
+    return;
+  }
+
   uint32_t mask_k = 0;
   uint32_t mask_a = 0;
 
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index be6443c..f6d1732 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -814,30 +814,34 @@
 } CIPHER_RFC_NAME_TEST;
 
 static const CIPHER_RFC_NAME_TEST kCipherRFCNameTests[] = {
-  { SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA" },
-  { TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA" },
-  { TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" },
-  { TLS1_CK_DHE_RSA_WITH_AES_256_SHA256,
-    "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" },
-  { TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256,
-    "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" },
-  { TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384,
-    "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" },
-  { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
-    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" },
-  { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
-    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" },
-  { TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
-    "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" },
-  { TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA,
-    "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA" },
-  { TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-    "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" },
-  // These names are non-standard:
-  { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD,
-    "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" },
-  { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD,
-    "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" },
+    {SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"},
+    {TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"},
+    {TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"},
+    {TLS1_CK_DHE_RSA_WITH_AES_256_SHA256,
+     "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"},
+    {TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256,
+     "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"},
+    {TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384,
+     "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"},
+    {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+     "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"},
+    {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+     "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"},
+    {TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+     "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"},
+    {TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+     "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"},
+    {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+     "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"},
+    {TLS1_CK_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384"},
+    {TLS1_CK_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256"},
+    {TLS1_CK_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256"},
+
+    // These names are non-standard:
+    {TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD,
+     "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"},
+    {TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD,
+     "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"},
 };
 
 static bool TestCipherGetRFCName(void) {
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 0da212b..b9d359e 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1240,13 +1240,10 @@
     return 1;
   }
 
-  /* OCSP stapling is forbidden on a non-certificate cipher. */
-  if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
-    return 0;
-  }
-
   if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
-    if (CBS_len(contents) != 0) {
+    /* OCSP stapling is forbidden on non-certificate ciphers. */
+    if (CBS_len(contents) != 0 ||
+        !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
       return 0;
     }
 
@@ -1258,6 +1255,11 @@
     return 1;
   }
 
+  /* In TLS 1.3, OCSP stapling is forbidden on resumption. */
+  if (ssl->s3->session_reused) {
+    return 0;
+  }
+
   uint8_t status_type;
   CBS ocsp_response;
   if (!CBS_get_u8(contents, &status_type) ||
@@ -1298,7 +1300,9 @@
 static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) {
   if (!ssl->s3->tmp.ocsp_stapling_requested ||
       ssl->ctx->ocsp_response_length == 0 ||
-      !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
+      ssl->s3->session_reused ||
+      (ssl3_protocol_version(ssl) < TLS1_3_VERSION &&
+       !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher))) {
     return 1;
   }
 
@@ -2231,8 +2235,13 @@
                                         uint8_t *out_alert, CBS *contents) {
   uint16_t group_id;
   CBS key_shares;
-  if (!tls1_get_shared_group(ssl, &group_id) ||
-      !CBS_get_u16_length_prefixed(contents, &key_shares) ||
+  if (!tls1_get_shared_group(ssl, &group_id)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_GROUP);
+    *out_alert = SSL_AD_HANDSHAKE_FAILURE;
+    return 0;
+  }
+
+  if (!CBS_get_u16_length_prefixed(contents, &key_shares) ||
       CBS_len(contents) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
     return 0;
@@ -2286,6 +2295,7 @@
     OPENSSL_free(secret);
     SSL_ECDH_CTX_cleanup(&group);
     CBB_cleanup(&public_key);
+    *out_alert = SSL_AD_ILLEGAL_PARAMETER;
     return 0;
   }
 
@@ -2298,10 +2308,6 @@
 }
 
 int ssl_ext_key_share_add_serverhello(SSL *ssl, CBB *out) {
-  if (ssl->s3->tmp.new_cipher->algorithm_mkey != SSL_kECDHE) {
-    return 1;
-  }
-
   uint16_t group_id;
   CBB kse_bytes, public_key;
   if (!tls1_get_shared_group(ssl, &group_id) ||
diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go
index 4ce4629..656a3d0 100644
--- a/ssl/test/runner/cipher_suites.go
+++ b/ssl/test/runner/cipher_suites.go
@@ -101,38 +101,20 @@
 	return crypto.SHA256
 }
 
-// TODO(nharper): Remove this function when TLS 1.3 cipher suites get
-// refactored to break out the AEAD/PRF from everything else. Once that's
-// done, this won't be necessary anymore.
-func ecdhePSKSuite(id uint16) uint16 {
-	switch id {
-	case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-		TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
-		TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
-		return TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256
-	case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
-		TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
-		TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256:
-		return TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256
-	case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
-		TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
-		TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384:
-		return TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384
-	}
-	return 0
-}
-
 var cipherSuites = []*cipherSuite{
 	// Ciphersuite order is chosen so that ECDHE comes before plain RSA
 	// and RC4 comes before AES (because of the Lucky13 attack).
-	{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteTLS13, nil, nil, aeadCHACHA20POLY1305},
-	{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteTLS13, nil, nil, aeadCHACHA20POLY1305},
+	{TLS_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, nil, suiteTLS13, nil, nil, aeadCHACHA20POLY1305},
+	{TLS_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, nil, suiteTLS13, nil, nil, aeadAESGCM},
+	{TLS_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, nil, suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
+	{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
 	{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD, 32, 0, noIV, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadCHACHA20POLY1305Old},
 	{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD, 32, 0, noIV, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadCHACHA20POLY1305Old},
-	{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteTLS13, nil, nil, aeadAESGCM},
-	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteTLS13, nil, nil, aeadAESGCM},
-	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM},
-	{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
 	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, noIV, ecdheRSAKA, suiteECDHE | suiteNoDTLS, cipherRC4, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, noIV, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteNoDTLS, cipherRC4, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
@@ -164,9 +146,7 @@
 	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
 	{TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, dheRSAKA, 0, cipher3DES, macSHA1, nil},
 	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, rsaKA, 0, cipher3DES, macSHA1, nil},
-	{TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12 | suiteTLS13, nil, nil, aeadCHACHA20POLY1305},
-	{TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12 | suiteTLS13, nil, nil, aeadAESGCM},
-	{TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12 | suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12, nil, nil, aeadCHACHA20POLY1305},
 	{TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil},
 	{TLS_PSK_WITH_RC4_128_SHA, 16, 20, noIV, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil},
@@ -562,8 +542,9 @@
 const (
 	TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD   uint16 = 0xcc13
 	TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD uint16 = 0xcc14
-	TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256             uint16 = 0xd001
-	TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384             uint16 = 0xd002
+	TLS_AES_128_GCM_SHA256                            uint16 = 0x1301
+	TLS_AES_256_GCM_SHA384                            uint16 = 0x1302
+	TLS_CHACHA20_POLY1305_SHA256                      uint16 = 0x1303
 	TLS_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256      uint16 = 0x16b7
 	TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256    uint16 = 0x16b8
 	TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384            uint16 = 0x16b9
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 599ce02..ae46505 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -27,7 +27,7 @@
 )
 
 // A draft version of TLS 1.3 that is sent over the wire for the current draft.
-const tls13DraftVersion = 0x7f0e
+const tls13DraftVersion = 0x7f0f
 
 const (
 	maxPlaintext        = 16384        // maximum plaintext payload length
@@ -1026,6 +1026,18 @@
 	// advertised in server extensions
 	AdvertiseTicketExtension bool
 
+	// NegotiatePSKResumption, if true, causes the server to attempt pure PSK
+	// resumption.
+	NegotiatePSKResumption bool
+
+	// OmitServerHelloSignatureAlgorithms, if true, causes the server to omit the
+	// signature_algorithms extension in the ServerHello.
+	OmitServerHelloSignatureAlgorithms bool
+
+	// IncludeServerHelloSignatureAlgorithms, if true, causes the server to
+	// include the signature_algorithms extension in all ServerHellos.
+	IncludeServerHelloSignatureAlgorithms bool
+
 	// MissingKeyShare, if true, causes the TLS 1.3 implementation to skip
 	// sending a key_share extension and use the zero ECDHE secret
 	// instead.
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index f03e169..c5be2b7 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -217,24 +217,10 @@
 			// Check that the ciphersuite/version used for the
 			// previous session are still valid.
 			cipherSuiteOk := false
-			if candidateSession.vers >= VersionTLS13 {
-				// Account for ciphers changing on resumption.
-				//
-				// TODO(davidben): This will be gone with the
-				// new cipher negotiation scheme.
-				resumeCipher := ecdhePSKSuite(candidateSession.cipherSuite)
-				for _, id := range hello.cipherSuites {
-					if ecdhePSKSuite(id) == resumeCipher {
-						cipherSuiteOk = true
-						break
-					}
-				}
-			} else {
-				for _, id := range hello.cipherSuites {
-					if id == candidateSession.cipherSuite {
-						cipherSuiteOk = true
-						break
-					}
+			for _, id := range hello.cipherSuites {
+				if id == candidateSession.cipherSuite {
+					cipherSuiteOk = true
+					break
 				}
 			}
 
@@ -274,7 +260,6 @@
 			}
 
 			hello.pskIdentities = []pskIdentity{psk}
-			hello.cipherSuites = append(hello.cipherSuites, ecdhePSKSuite(session.cipherSuite))
 		}
 
 		if session.vers < VersionTLS13 || c.config.Bugs.SendBothTickets {
@@ -606,10 +591,10 @@
 	// TODO(davidben): This will need to be handled slightly earlier once
 	// 0-RTT is implemented.
 	var psk []byte
-	if hs.suite.flags&suitePSK != 0 {
-		if !hs.serverHello.hasPSKIdentity {
-			c.sendAlert(alertMissingExtension)
-			return errors.New("tls: server omitted the PSK identity extension")
+	if hs.serverHello.hasPSKIdentity {
+		if hs.serverHello.useCertAuth || !hs.serverHello.hasKeyShare {
+			c.sendAlert(alertUnsupportedExtension)
+			return errors.New("tls: server omitted KeyShare or included SignatureAlgorithms on resumption.")
 		}
 
 		// We send at most one PSK identity.
@@ -617,17 +602,17 @@
 			c.sendAlert(alertUnknownPSKIdentity)
 			return errors.New("tls: server sent unknown PSK identity")
 		}
-		if ecdhePSKSuite(hs.session.cipherSuite) != hs.suite.id {
+		if hs.session.cipherSuite != hs.suite.id {
 			c.sendAlert(alertHandshakeFailure)
-			return errors.New("tls: server sent invalid cipher suite for PSK")
+			return errors.New("tls: server sent invalid cipher suite")
 		}
 		psk = deriveResumptionPSK(hs.suite, hs.session.masterSecret)
 		hs.finishedHash.setResumptionContext(deriveResumptionContext(hs.suite, hs.session.masterSecret))
 		c.didResume = true
 	} else {
-		if hs.serverHello.hasPSKIdentity {
+		if !hs.serverHello.useCertAuth || !hs.serverHello.hasKeyShare {
 			c.sendAlert(alertUnsupportedExtension)
-			return errors.New("tls: server sent unexpected PSK identity")
+			return errors.New("tls: server omitted KeyShare and SignatureAlgorithms on non-resumption.")
 		}
 
 		psk = zeroSecret
@@ -638,12 +623,7 @@
 
 	// Resolve ECDHE and compute the handshake secret.
 	var ecdheSecret []byte
-	if hs.suite.flags&suiteECDHE != 0 && !c.config.Bugs.MissingKeyShare && !c.config.Bugs.SecondClientHelloMissingKeyShare {
-		if !hs.serverHello.hasKeyShare {
-			c.sendAlert(alertMissingExtension)
-			return errors.New("tls: server omitted the key share extension")
-		}
-
+	if !c.config.Bugs.MissingKeyShare && !c.config.Bugs.SecondClientHelloMissingKeyShare {
 		curve, ok := hs.keyShares[hs.serverHello.keyShare.group]
 		if !ok {
 			c.sendAlert(alertHandshakeFailure)
@@ -657,11 +637,6 @@
 			return err
 		}
 	} else {
-		if hs.serverHello.hasKeyShare {
-			c.sendAlert(alertUnsupportedExtension)
-			return errors.New("tls: server sent unexpected key share extension")
-		}
-
 		ecdheSecret = zeroSecret
 	}
 
@@ -692,7 +667,7 @@
 
 	var chainToSend *Certificate
 	var certReq *certificateRequestMsg
-	if hs.suite.flags&suitePSK != 0 {
+	if !hs.serverHello.useCertAuth {
 		if encryptedExtensions.extensions.ocspResponse != nil {
 			c.sendAlert(alertUnsupportedExtension)
 			return errors.New("tls: server sent OCSP response without a certificate")
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index e7a1235..19578e8 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -779,6 +779,7 @@
 	keyShare            keyShareEntry
 	hasPSKIdentity      bool
 	pskIdentity         uint16
+	useCertAuth         bool
 	earlyDataIndication bool
 	compressionMethod   uint8
 	extensions          serverExtensions
@@ -831,6 +832,10 @@
 			extensions.addU16(2) // Length
 			extensions.addU16(m.pskIdentity)
 		}
+		if m.useCertAuth {
+			extensions.addU16(extensionSignatureAlgorithms)
+			extensions.addU16(0) // Length
+		}
 		if m.earlyDataIndication {
 			extensions.addU16(extensionEarlyData)
 			extensions.addU16(0) // Length
@@ -928,6 +933,11 @@
 				}
 				m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
 				m.hasPSKIdentity = true
+			case extensionSignatureAlgorithms:
+				if len(d) != 0 {
+					return false
+				}
+				m.useCertAuth = true
 			case extensionEarlyData:
 				if len(d) != 0 {
 					return false
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 934e052..c2fae55 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -396,7 +396,10 @@
 		}
 	}
 
-	_, ecdsaOk := hs.cert.PrivateKey.(*ecdsa.PrivateKey)
+	if !supportedCurve {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: no curve supported by both client and server")
+	}
 
 	pskIdentities := hs.clientHello.pskIdentities
 	if len(pskIdentities) == 0 && len(hs.clientHello.sessionTicket) > 0 && c.config.Bugs.AcceptAnySession {
@@ -431,46 +434,43 @@
 		if !ok {
 			continue
 		}
-		if !config.Bugs.AcceptAnySession {
+		if config.Bugs.AcceptAnySession {
+			// Replace the cipher suite with one known to work, to
+			// test cross-version resumption attempts.
+			sessionState.cipherSuite = TLS_AES_128_GCM_SHA256
+		} else {
 			if sessionState.vers != c.vers && c.config.Bugs.AcceptAnySession {
 				continue
 			}
 			if sessionState.ticketExpiration.Before(c.config.time()) {
 				continue
 			}
-		}
 
-		suiteId := ecdhePSKSuite(sessionState.cipherSuite)
-
-		// Check the client offered the cipher.
-		clientCipherSuites := hs.clientHello.cipherSuites
-		if config.Bugs.AcceptAnySession {
-			clientCipherSuites = []uint16{suiteId}
-		}
-		suite := mutualCipherSuite(clientCipherSuites, suiteId)
-
-		// Check the cipher is enabled by the server or is a resumption
-		// suite of one enabled by the server. Account for the cipher
-		// change on resume.
-		//
-		// TODO(davidben): The ecdhePSKSuite mess will be gone with the
-		// new cipher negotiation scheme.
-		var found bool
-		for _, id := range config.cipherSuites() {
-			if ecdhePSKSuite(id) == suiteId {
-				found = true
-				break
+			cipherSuiteOk := false
+			// Check that the client is still offering the ciphersuite in the session.
+			for _, id := range hs.clientHello.cipherSuites {
+				if id == sessionState.cipherSuite {
+					cipherSuiteOk = true
+					break
+				}
+			}
+			if !cipherSuiteOk {
+				continue
 			}
 		}
 
-		if suite != nil && found {
-			hs.sessionState = sessionState
-			hs.suite = suite
-			hs.hello.hasPSKIdentity = true
-			hs.hello.pskIdentity = uint16(i)
-			c.didResume = true
-			break
+		// Check that we also support the ciphersuite from the session.
+		suite := c.tryCipherSuite(sessionState.cipherSuite, c.config.cipherSuites(), c.vers, true, true)
+		if suite == nil {
+			continue
 		}
+
+		hs.sessionState = sessionState
+		hs.suite = suite
+		hs.hello.hasPSKIdentity = true
+		hs.hello.pskIdentity = uint16(i)
+		c.didResume = true
+		break
 	}
 
 	// If not resuming, select the cipher suite.
@@ -485,7 +485,7 @@
 		}
 
 		for _, id := range preferenceList {
-			if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, supportedCurve, ecdsaOk, false); hs.suite != nil {
+			if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, true, true); hs.suite != nil {
 				break
 			}
 		}
@@ -505,9 +505,11 @@
 	hs.finishedHash.discardHandshakeBuffer()
 	hs.writeClientHash(hs.clientHello.marshal())
 
+	hs.hello.useCertAuth = hs.sessionState == nil
+
 	// Resolve PSK and compute the early secret.
 	var psk []byte
-	if hs.suite.flags&suitePSK != 0 {
+	if hs.sessionState != nil {
 		psk = deriveResumptionPSK(hs.suite, hs.sessionState.masterSecret)
 		hs.finishedHash.setResumptionContext(deriveResumptionContext(hs.suite, hs.sessionState.masterSecret))
 	} else {
@@ -517,9 +519,23 @@
 
 	earlySecret := hs.finishedHash.extractKey(hs.finishedHash.zeroSecret(), psk)
 
+	if config.Bugs.OmitServerHelloSignatureAlgorithms {
+		hs.hello.useCertAuth = false
+	} else if config.Bugs.IncludeServerHelloSignatureAlgorithms {
+		hs.hello.useCertAuth = true
+	}
+
+	hs.hello.hasKeyShare = true
+	if hs.sessionState != nil && config.Bugs.NegotiatePSKResumption {
+		hs.hello.hasKeyShare = false
+	}
+	if config.Bugs.MissingKeyShare {
+		hs.hello.hasKeyShare = false
+	}
+
 	// Resolve ECDHE and compute the handshake secret.
 	var ecdheSecret []byte
-	if hs.suite.flags&suiteECDHE != 0 && !config.Bugs.MissingKeyShare {
+	if hs.hello.hasKeyShare {
 		// Look for the key share corresponding to our selected curve.
 		var selectedKeyShare *keyShareEntry
 		for i := range hs.clientHello.keyShares {
@@ -671,7 +687,7 @@
 	c.out.useTrafficSecret(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, serverWrite)
 	c.in.useTrafficSecret(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, clientWrite)
 
-	if hs.suite.flags&suitePSK == 0 {
+	if hs.hello.useCertAuth {
 		if hs.clientHello.ocspStapling {
 			encryptedExtensions.extensions.ocspResponse = hs.cert.OCSPStaple
 		}
@@ -696,7 +712,7 @@
 		c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal())
 	}
 
-	if hs.suite.flags&suitePSK == 0 {
+	if hs.hello.useCertAuth {
 		if config.ClientAuth >= RequestClientCert {
 			// Request a client certificate
 			certReq := &certificateRequestMsg{
@@ -757,7 +773,7 @@
 
 		hs.writeServerHash(certVerify.marshal())
 		c.writeRecord(recordTypeHandshake, certVerify.marshal())
-	} else {
+	} else if hs.sessionState != nil {
 		// Pick up certificates from the session instead.
 		if len(hs.sessionState.certificates) > 0 {
 			if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil {
@@ -968,7 +984,7 @@
 	}
 
 	for _, id := range preferenceList {
-		if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk, true); hs.suite != nil {
+		if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil {
 			break
 		}
 	}
@@ -1134,7 +1150,11 @@
 		}
 	}
 
-	if !c.config.Bugs.AcceptAnySession {
+	if c.config.Bugs.AcceptAnySession {
+		// Replace the cipher suite with one known to work, to test
+		// cross-version resumption attempts.
+		hs.sessionState.cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA
+	} else {
 		// Never resume a session for a different SSL version.
 		if c.vers != hs.sessionState.vers {
 			return false
@@ -1154,7 +1174,8 @@
 	}
 
 	// Check that we also support the ciphersuite from the session.
-	hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers, hs.ellipticOk, hs.ecdsaOk, true)
+	hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), c.vers, hs.ellipticOk, hs.ecdsaOk)
+
 	if hs.suite == nil {
 		return false
 	}
@@ -1726,7 +1747,7 @@
 
 // tryCipherSuite returns a cipherSuite with the given id if that cipher suite
 // is acceptable to use.
-func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk, pskOk bool) *cipherSuite {
+func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite {
 	for _, supported := range supportedCipherSuites {
 		if id == supported {
 			var candidate *cipherSuite
@@ -1740,10 +1761,14 @@
 			if candidate == nil {
 				continue
 			}
+
 			// Don't select a ciphersuite which we can't
 			// support for this client.
-			if (candidate.flags&suitePSK != 0) && !pskOk {
-				continue
+			if version >= VersionTLS13 || candidate.flags&suiteTLS13 != 0 {
+				if version < VersionTLS13 || candidate.flags&suiteTLS13 == 0 {
+					continue
+				}
+				return candidate
 			}
 			if (candidate.flags&suiteECDHE != 0) && !ellipticOk {
 				continue
@@ -1754,9 +1779,6 @@
 			if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
 				continue
 			}
-			if version >= VersionTLS13 && candidate.flags&suiteTLS13 == 0 {
-				continue
-			}
 			if c.isDTLS && candidate.flags&suiteNoDTLS != 0 {
 				continue
 			}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index f536ceb..e164843 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -789,6 +789,14 @@
 }
 
 func runTest(test *testCase, shimPath string, mallocNumToFail int64) error {
+	// Help debugging panics on the Go side.
+	defer func() {
+		if r := recover(); r != nil {
+			fmt.Fprintf(os.Stderr, "Test '%s' panicked.\n", test.name)
+			panic(r)
+		}
+	}()
+
 	if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
 		panic("Error expected without shouldFail in " + test.name)
 	}
@@ -1059,8 +1067,9 @@
 	{"ECDHE-PSK-AES128-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA},
 	{"ECDHE-PSK-AES256-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA},
 	{"ECDHE-PSK-CHACHA20-POLY1305", TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256},
-	{"ECDHE-PSK-AES128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256},
-	{"ECDHE-PSK-AES256-GCM-SHA384", TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384},
+	{"AEAD-CHACHA20-POLY1305", TLS_CHACHA20_POLY1305_SHA256},
+	{"AEAD-AES128-GCM-SHA256", TLS_AES_128_GCM_SHA256},
+	{"AEAD-AES256-GCM-SHA384", TLS_AES_256_GCM_SHA384},
 	{"NULL-SHA", TLS_RSA_WITH_NULL_SHA},
 }
 
@@ -1076,24 +1085,7 @@
 }
 
 func isTLS13Suite(suiteName string) bool {
-	// Only AEADs.
-	if !hasComponent(suiteName, "GCM") && !hasComponent(suiteName, "POLY1305") {
-		return false
-	}
-	// No old CHACHA20_POLY1305.
-	if hasComponent(suiteName, "CHACHA20-POLY1305-OLD") {
-		return false
-	}
-	// Must have ECDHE.
-	// TODO(davidben,svaldez): Add pure PSK support.
-	if !hasComponent(suiteName, "ECDHE") {
-		return false
-	}
-	// TODO(davidben,svaldez): Add PSK support.
-	if hasComponent(suiteName, "PSK") {
-		return false
-	}
-	return true
+	return strings.HasPrefix(suiteName, "AEAD-")
 }
 
 func isDTLSCipher(suiteName string) bool {
@@ -1418,19 +1410,6 @@
 			expectedError: ":WRONG_CERTIFICATE_TYPE:",
 		},
 		{
-			name: "CertMismatchRSA-TLS13",
-			config: Config{
-				MaxVersion:   VersionTLS13,
-				CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
-				Certificates: []Certificate{ecdsaP256Certificate},
-				Bugs: ProtocolBugs{
-					SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
-				},
-			},
-			shouldFail:    true,
-			expectedError: ":WRONG_CERTIFICATE_TYPE:",
-		},
-		{
 			name: "CertMismatchECDSA",
 			config: Config{
 				MaxVersion:   VersionTLS12,
@@ -1444,23 +1423,9 @@
 			expectedError: ":WRONG_CERTIFICATE_TYPE:",
 		},
 		{
-			name: "CertMismatchECDSA-TLS13",
-			config: Config{
-				MaxVersion:   VersionTLS13,
-				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
-				Certificates: []Certificate{rsaCertificate},
-				Bugs: ProtocolBugs{
-					SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
-				},
-			},
-			shouldFail:    true,
-			expectedError: ":WRONG_CERTIFICATE_TYPE:",
-		},
-		{
 			name: "EmptyCertificateList",
 			config: Config{
-				MaxVersion:   VersionTLS12,
-				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+				MaxVersion: VersionTLS12,
 				Bugs: ProtocolBugs{
 					EmptyCertificateList: true,
 				},
@@ -1471,8 +1436,7 @@
 		{
 			name: "EmptyCertificateList-TLS13",
 			config: Config{
-				MaxVersion:   VersionTLS13,
-				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+				MaxVersion: VersionTLS13,
 				Bugs: ProtocolBugs{
 					EmptyCertificateList: true,
 				},
@@ -2427,6 +2391,10 @@
 					shouldClientFail = true
 					shouldServerFail = true
 				}
+				if isTLS13Suite(suite.name) && ver.version < VersionTLS13 {
+					shouldClientFail = true
+					shouldServerFail = true
+				}
 				if !isDTLSCipher(suite.name) && protocol == dtls {
 					shouldClientFail = true
 					shouldServerFail = true
@@ -2622,18 +2590,21 @@
 		testType: serverTest,
 		name:     "UnknownCipher",
 		config: Config{
+			MaxVersion:   VersionTLS12,
 			CipherSuites: []uint16{bogusCipher, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 			Bugs: ProtocolBugs{
 				AdvertiseAllConfiguredCiphers: true,
 			},
 		},
 	})
+
+	// The server must be tolerant to bogus ciphers.
 	testCases = append(testCases, testCase{
 		testType: serverTest,
 		name:     "UnknownCipher-TLS13",
 		config: Config{
 			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{bogusCipher, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			CipherSuites: []uint16{bogusCipher, TLS_AES_128_GCM_SHA256},
 			Bugs: ProtocolBugs{
 				AdvertiseAllConfiguredCiphers: true,
 			},
@@ -2761,6 +2732,7 @@
 			testCases = append(testCases, testCase{
 				name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
 				config: Config{
+					MaxVersion:   VersionTLS12,
 					CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
 					Certificates: []Certificate{ecdsaP256Certificate},
 					Bugs: ProtocolBugs{
@@ -2771,6 +2743,19 @@
 				shouldFail:    true,
 				expectedError: ":BAD_SIGNATURE:",
 			})
+			testCases = append(testCases, testCase{
+				name: fmt.Sprintf("BadECDSA-%d-%d-TLS13", badR, badS),
+				config: Config{
+					MaxVersion:   VersionTLS13,
+					Certificates: []Certificate{ecdsaP256Certificate},
+					Bugs: ProtocolBugs{
+						BadECDSAR: badR,
+						BadECDSAS: badS,
+					},
+				},
+				shouldFail:    true,
+				expectedError: ":BAD_SIGNATURE:",
+			})
 		}
 	}
 }
@@ -5271,15 +5256,12 @@
 func addResumptionVersionTests() {
 	for _, sessionVers := range tlsVersions {
 		for _, resumeVers := range tlsVersions {
-			cipher := TLS_RSA_WITH_AES_128_CBC_SHA
-			if sessionVers.version >= VersionTLS13 || resumeVers.version >= VersionTLS13 {
-				// TLS 1.3 only shares ciphers with TLS 1.2, so
-				// we skip certain combinations and use a
-				// different cipher to test with.
-				cipher = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
-				if sessionVers.version < VersionTLS12 || resumeVers.version < VersionTLS12 {
-					continue
-				}
+			// SSL 3.0 does not have tickets and TLS 1.3 does not
+			// have session IDs, so skip their cross-resumption
+			// tests.
+			if (sessionVers.version >= VersionTLS13 && resumeVers.version == VersionSSL30) ||
+				(resumeVers.version >= VersionTLS13 && sessionVers.version == VersionSSL30) {
+				continue
 			}
 
 			protocols := []protocol{tls}
@@ -5298,8 +5280,7 @@
 						name:          "Resume-Client" + suffix,
 						resumeSession: true,
 						config: Config{
-							MaxVersion:   sessionVers.version,
-							CipherSuites: []uint16{cipher},
+							MaxVersion: sessionVers.version,
 							Bugs: ProtocolBugs{
 								ExpectNoTLS12Session: sessionVers.version >= VersionTLS13,
 								ExpectNoTLS13PSK:     sessionVers.version < VersionTLS13,
@@ -5324,13 +5305,11 @@
 						name:          "Resume-Client-Mismatch" + suffix,
 						resumeSession: true,
 						config: Config{
-							MaxVersion:   sessionVers.version,
-							CipherSuites: []uint16{cipher},
+							MaxVersion: sessionVers.version,
 						},
 						expectedVersion: sessionVers.version,
 						resumeConfig: &Config{
-							MaxVersion:   resumeVers.version,
-							CipherSuites: []uint16{cipher},
+							MaxVersion: resumeVers.version,
 							Bugs: ProtocolBugs{
 								AcceptAnySession: true,
 							},
@@ -5346,13 +5325,11 @@
 					name:          "Resume-Client-NoResume" + suffix,
 					resumeSession: true,
 					config: Config{
-						MaxVersion:   sessionVers.version,
-						CipherSuites: []uint16{cipher},
+						MaxVersion: sessionVers.version,
 					},
 					expectedVersion: sessionVers.version,
 					resumeConfig: &Config{
-						MaxVersion:   resumeVers.version,
-						CipherSuites: []uint16{cipher},
+						MaxVersion: resumeVers.version,
 					},
 					newSessionsOnResume:   true,
 					expectResumeRejected:  true,
@@ -5365,14 +5342,12 @@
 					name:          "Resume-Server" + suffix,
 					resumeSession: true,
 					config: Config{
-						MaxVersion:   sessionVers.version,
-						CipherSuites: []uint16{cipher},
+						MaxVersion: sessionVers.version,
 					},
 					expectedVersion:      sessionVers.version,
 					expectResumeRejected: sessionVers.version != resumeVers.version,
 					resumeConfig: &Config{
-						MaxVersion:   resumeVers.version,
-						CipherSuites: []uint16{cipher},
+						MaxVersion: resumeVers.version,
 						Bugs: ProtocolBugs{
 							SendBothTickets: true,
 						},
@@ -5406,13 +5381,13 @@
 		resumeSession: true,
 		config: Config{
 			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
 		},
 		resumeConfig: &Config{
 			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
 			Bugs: ProtocolBugs{
-				SendCipherSuite: TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+				SendCipherSuite: TLS_AES_256_GCM_SHA384,
 			},
 		},
 		shouldFail:    true,
@@ -5841,6 +5816,7 @@
 	// Not all ciphers involve a signature. Advertise a list which gives all
 	// versions a signing cipher.
 	signingCiphers := []uint16{
+		TLS_AES_128_GCM_SHA256,
 		TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
 		TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
 		TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
@@ -6113,8 +6089,7 @@
 		testType: serverTest,
 		name:     "ServerAuth-SignatureType-TLS13",
 		config: Config{
-			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			MaxVersion: VersionTLS13,
 			VerifySignatureAlgorithms: []signatureAlgorithm{
 				signatureECDSAWithP521AndSHA512,
 				signatureRSAPKCS1WithSHA384,
@@ -6185,8 +6160,7 @@
 	testCases = append(testCases, testCase{
 		name: "Verify-ServerAuth-SignatureType-TLS13",
 		config: Config{
-			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			MaxVersion: VersionTLS13,
 			SignSignatureAlgorithms: []signatureAlgorithm{
 				signatureRSAPSSWithSHA256,
 			},
@@ -6299,8 +6273,7 @@
 		testType: serverTest,
 		name:     "ServerAuth-NoFallback-TLS13",
 		config: Config{
-			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			MaxVersion: VersionTLS13,
 			VerifySignatureAlgorithms: []signatureAlgorithm{
 				signatureRSAPKCS1WithSHA1,
 			},
@@ -6369,8 +6342,7 @@
 	testCases = append(testCases, testCase{
 		name: "ServerAuth-Enforced-TLS13",
 		config: Config{
-			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			MaxVersion: VersionTLS13,
 			SignSignatureAlgorithms: []signatureAlgorithm{
 				signatureRSAPKCS1WithMD5,
 			},
@@ -6532,7 +6504,6 @@
 		name: "CheckLeafCurve-TLS13",
 		config: Config{
 			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
 			Certificates: []Certificate{ecdsaP256Certificate},
 		},
 		flags: []string{"-p384-only"},
@@ -6556,7 +6527,6 @@
 		name: "ECDSACurveMismatch-Verify-TLS13",
 		config: Config{
 			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
 			Certificates: []Certificate{ecdsaP256Certificate},
 			SignSignatureAlgorithms: []signatureAlgorithm{
 				signatureECDSAWithP384AndSHA384,
@@ -6575,8 +6545,7 @@
 		testType: serverTest,
 		name:     "ECDSACurveMismatch-Sign-TLS13",
 		config: Config{
-			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+			MaxVersion: VersionTLS13,
 			VerifySignatureAlgorithms: []signatureAlgorithm{
 				signatureECDSAWithP384AndSHA384,
 				signatureECDSAWithP256AndSHA256,
@@ -7207,7 +7176,6 @@
 			name: "CurveTest-Client-" + curve.name + "-TLS13",
 			config: Config{
 				MaxVersion:       VersionTLS13,
-				CipherSuites:     []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 				CurvePreferences: []CurveID{curve.id},
 			},
 			flags: []string{
@@ -7235,7 +7203,6 @@
 			name:     "CurveTest-Server-" + curve.name + "-TLS13",
 			config: Config{
 				MaxVersion:       VersionTLS13,
-				CipherSuites:     []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 				CurvePreferences: []CurveID{curve.id},
 			},
 			flags: []string{
@@ -7251,11 +7218,22 @@
 		testType: serverTest,
 		name:     "UnknownCurve",
 		config: Config{
+			MaxVersion:       VersionTLS12,
 			CipherSuites:     []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 			CurvePreferences: []CurveID{bogusCurve, CurveP256},
 		},
 	})
 
+	// The server must be tolerant to bogus curves.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "UnknownCurve-TLS13",
+		config: Config{
+			MaxVersion:       VersionTLS13,
+			CurvePreferences: []CurveID{bogusCurve, CurveP256},
+		},
+	})
+
 	// The server must not consider ECDHE ciphers when there are no
 	// supported curves.
 	testCases = append(testCases, testCase{
@@ -7275,14 +7253,13 @@
 		testType: serverTest,
 		name:     "NoSupportedCurves-TLS13",
 		config: Config{
-			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
 				NoSupportedCurves: true,
 			},
 		},
 		shouldFail:    true,
-		expectedError: ":NO_SHARED_CIPHER:",
+		expectedError: ":NO_SHARED_GROUP:",
 	})
 
 	// The server must fall back to another cipher when there are no
@@ -7317,8 +7294,7 @@
 	testCases = append(testCases, testCase{
 		name: "BadECDHECurve-TLS13",
 		config: Config{
-			MaxVersion:   VersionTLS13,
-			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			MaxVersion: VersionTLS13,
 			Bugs: ProtocolBugs{
 				SendCurve: bogusCurve,
 			},
@@ -7347,8 +7323,7 @@
 		// HelloRetryRequest requests an unsupported curve.
 		name: "UnsupportedCurve-ServerHello-TLS13",
 		config: Config{
-			MaxVersion:       VersionTLS12,
-			CipherSuites:     []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			MaxVersion:       VersionTLS13,
 			CurvePreferences: []CurveID{CurveP384},
 			Bugs: ProtocolBugs{
 				SendCurve: CurveP256,
@@ -7377,7 +7352,6 @@
 		name: "InvalidECDHPoint-Client-TLS13",
 		config: Config{
 			MaxVersion:       VersionTLS13,
-			CipherSuites:     []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 			CurvePreferences: []CurveID{CurveP256},
 			Bugs: ProtocolBugs{
 				InvalidECDHPoint: true,
@@ -7405,7 +7379,6 @@
 		name:     "InvalidECDHPoint-Server-TLS13",
 		config: Config{
 			MaxVersion:       VersionTLS13,
-			CipherSuites:     []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 			CurvePreferences: []CurveID{CurveP256},
 			Bugs: ProtocolBugs{
 				InvalidECDHPoint: true,
@@ -8300,6 +8273,47 @@
 func addTLS13HandshakeTests() {
 	testCases = append(testCases, testCase{
 		testType: clientTest,
+		name:     "NegotiatePSKResumption-TLS13",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				NegotiatePSKResumption: true,
+			},
+		},
+		resumeSession: true,
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "OmitServerHelloSignatureAlgorithms",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				OmitServerHelloSignatureAlgorithms: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "IncludeServerHelloSignatureAlgorithms",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				IncludeServerHelloSignatureAlgorithms: true,
+			},
+		},
+		resumeSession: true,
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_EXTENSION:",
+	})
+
+	testCases = append(testCases, testCase{
+		testType: clientTest,
 		name:     "MissingKeyShare-Client",
 		config: Config{
 			MaxVersion: VersionTLS13,
@@ -8308,7 +8322,7 @@
 			},
 		},
 		shouldFail:    true,
-		expectedError: ":MISSING_KEY_SHARE:",
+		expectedError: ":UNEXPECTED_EXTENSION:",
 	})
 
 	testCases = append(testCases, testCase{
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index aa80b69..8f1b516 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -145,9 +145,30 @@
     return ssl_hs_error;
   }
 
+  assert(ssl->s3->have_version);
+  memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE);
+
+  const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
+  if (cipher == NULL) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+    return ssl_hs_error;
+  }
+
+  /* Check if the cipher is disabled. */
+  if ((cipher->algorithm_mkey & ssl->cert->mask_k) ||
+      (cipher->algorithm_auth & ssl->cert->mask_a) ||
+      SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) ||
+      SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl) ||
+      !sk_SSL_CIPHER_find(ssl_get_ciphers_by_id(ssl), NULL, cipher)) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+    return ssl_hs_error;
+  }
+
   /* Parse out the extensions. */
-  int have_key_share = 0, have_pre_shared_key = 0;
-  CBS key_share, pre_shared_key;
+  int have_key_share = 0, have_pre_shared_key = 0, have_sigalgs = 0;
+  CBS key_share, pre_shared_key, sigalgs;
   while (CBS_len(&extensions) != 0) {
     uint16_t type;
     CBS extension;
@@ -177,6 +198,15 @@
         pre_shared_key = extension;
         have_pre_shared_key = 1;
         break;
+      case TLSEXT_TYPE_signature_algorithms:
+        if (have_sigalgs) {
+          OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
+          ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+          return ssl_hs_error;
+        }
+        sigalgs = extension;
+        have_sigalgs = 1;
+        break;
       default:
         OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
@@ -184,8 +214,12 @@
     }
   }
 
-  assert(ssl->s3->have_version);
-  memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE);
+  /* We only support PSK_AUTH and PSK_DHE_KE. */
+  if (!have_key_share || have_sigalgs == have_pre_shared_key) {
+    OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+    return ssl_hs_error;
+  }
 
   uint8_t alert = SSL_AD_DECODE_ERROR;
   if (have_pre_shared_key) {
@@ -207,6 +241,12 @@
       return ssl_hs_error;
     }
 
+    if (ssl->session->cipher != cipher) {
+      OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+      return ssl_hs_error;
+    }
+
     if (!ssl_session_is_context_valid(ssl, ssl->session)) {
       /* This is actually a client application bug. */
       OPENSSL_PUT_ERROR(SSL,
@@ -224,109 +264,56 @@
       return ssl_hs_error;
     }
     ssl_set_session(ssl, NULL);
-  } else {
-    if (!ssl_get_new_session(ssl, 0)) {
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-      return ssl_hs_error;
-    }
-  }
-
-  const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
-  if (cipher == NULL) {
-    OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+  } else if (!ssl_get_new_session(ssl, 0)) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
     return ssl_hs_error;
   }
 
-  if (!ssl->s3->session_reused) {
-    /* Check if the cipher is disabled. */
-    if ((cipher->algorithm_mkey & ssl->cert->mask_k) ||
-        (cipher->algorithm_auth & ssl->cert->mask_a) ||
-        SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) ||
-        SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl) ||
-        !sk_SSL_CIPHER_find(ssl_get_ciphers_by_id(ssl), NULL, cipher)) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-      return ssl_hs_error;
-    }
-  } else {
-    uint16_t resumption_cipher;
-    if (!ssl_cipher_get_ecdhe_psk_cipher(ssl->s3->new_session->cipher,
-                                         &resumption_cipher) ||
-        resumption_cipher != ssl_cipher_get_value(cipher)) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-      return ssl_hs_error;
-    }
-  }
-
   ssl->s3->new_session->cipher = cipher;
   ssl->s3->tmp.new_cipher = cipher;
 
   /* The PRF hash is now known. Set up the key schedule. */
-  static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
-  size_t resumption_ctx_len =
+  size_t hash_len =
       EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
+
+  /* Derive resumption material. */
+  uint8_t resumption_ctx[EVP_MAX_MD_SIZE] = {0};
+  uint8_t psk_secret[EVP_MAX_MD_SIZE] = {0};
   if (ssl->s3->session_reused) {
-    uint8_t resumption_ctx[EVP_MAX_MD_SIZE];
-    if (!tls13_resumption_context(ssl, resumption_ctx, resumption_ctx_len,
+    if (!tls13_resumption_context(ssl, resumption_ctx, hash_len,
                                   ssl->s3->new_session) ||
-        !tls13_init_key_schedule(ssl, resumption_ctx, resumption_ctx_len)) {
+        !tls13_resumption_psk(ssl, psk_secret, hash_len,
+                              ssl->s3->new_session)) {
       return ssl_hs_error;
     }
-  } else if (!tls13_init_key_schedule(ssl, kZeroes, resumption_ctx_len)) {
-    return ssl_hs_error;
   }
 
-  /* Resolve PSK and incorporate it into the secret. */
-  if (cipher->algorithm_auth == SSL_aPSK) {
-    if (!ssl->s3->session_reused) {
-      OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
-      return ssl_hs_error;
-    }
-
-    uint8_t resumption_psk[EVP_MAX_MD_SIZE];
-    if (!tls13_resumption_psk(ssl, resumption_psk, hs->hash_len,
-                              ssl->s3->new_session) ||
-        !tls13_advance_key_schedule(ssl, resumption_psk, hs->hash_len)) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-      return ssl_hs_error;
-    }
-  } else if (!tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len)) {
+  /* Set up the key schedule, hash in the ClientHello, and incorporate the PSK
+   * into the running secret. */
+  if (!tls13_init_key_schedule(ssl, resumption_ctx, hash_len) ||
+      !tls13_advance_key_schedule(ssl, psk_secret, hash_len)) {
     return ssl_hs_error;
   }
 
   /* Resolve ECDHE and incorporate it into the secret. */
-  if (cipher->algorithm_mkey == SSL_kECDHE) {
-    if (!have_key_share) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
-      return ssl_hs_error;
-    }
+  uint8_t *dhe_secret;
+  size_t dhe_secret_len;
+  if (!ssl_ext_key_share_parse_serverhello(ssl, &dhe_secret, &dhe_secret_len,
+                                           &alert, &key_share)) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+    return ssl_hs_error;
+  }
 
-    uint8_t *dhe_secret;
-    size_t dhe_secret_len;
-    if (!ssl_ext_key_share_parse_serverhello(ssl, &dhe_secret, &dhe_secret_len,
-                                             &alert, &key_share)) {
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
-      return ssl_hs_error;
-    }
-
-    int ok = tls13_advance_key_schedule(ssl, dhe_secret, dhe_secret_len);
+  if (!tls13_advance_key_schedule(ssl, dhe_secret, dhe_secret_len)) {
     OPENSSL_free(dhe_secret);
-    if (!ok) {
-      return ssl_hs_error;
-    }
-  } else {
-    if (have_key_share) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
-      return ssl_hs_error;
-    }
-    if (!tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len)) {
-      return ssl_hs_error;
-    }
+    return ssl_hs_error;
+  }
+  OPENSSL_free(dhe_secret);
+
+  if (have_sigalgs &&
+      CBS_len(&sigalgs) != 0) {
+    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+    return ssl_hs_error;
   }
 
   /* If there was no HelloRetryRequest, the version negotiation logic has
@@ -374,8 +361,8 @@
                                                          SSL_HANDSHAKE *hs) {
   ssl->s3->tmp.cert_request = 0;
 
-  /* CertificateRequest may only be sent in certificate-based ciphers. */
-  if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
+  /* CertificateRequest may only be sent in non-resumption handshakes. */
+  if (ssl->s3->session_reused) {
     hs->state = state_process_server_finished;
     return ssl_hs_ok;
   }
@@ -436,15 +423,6 @@
     return ssl_hs_error;
   }
 
-  /* Check the certificate matches the cipher suite.
-   *
-   * TODO(davidben): Remove this check when switching to the new TLS 1.3 cipher
-   * suite negotiation. */
-  if (!ssl_check_leaf_certificate(ssl, ssl->s3->new_session->peer)) {
-    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-    return ssl_hs_error;
-  }
-
   hs->state = state_process_server_certificate_verify;
   return ssl_hs_read_message;
 }
@@ -464,7 +442,6 @@
 static enum ssl_hs_wait_t do_process_server_finished(SSL *ssl,
                                                      SSL_HANDSHAKE *hs) {
   static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
-
   if (!tls13_check_message_type(ssl, SSL3_MT_FINISHED) ||
       !tls13_process_finished(ssl) ||
       !ssl->method->hash_current_message(ssl) ||
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index 9e146e6..984cc5c 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -51,32 +51,11 @@
 
 static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
 
-static int resolve_psk_secret(SSL *ssl) {
-  SSL_HANDSHAKE *hs = ssl->s3->hs;
-
-  if (ssl->s3->tmp.new_cipher->algorithm_auth != SSL_aPSK) {
-    return tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len);
-  }
-
-  uint8_t resumption_psk[EVP_MAX_MD_SIZE];
-  if (!tls13_resumption_psk(ssl, resumption_psk, hs->hash_len,
-                            ssl->s3->new_session) ||
-      !tls13_advance_key_schedule(ssl, resumption_psk, hs->hash_len)) {
-    return 0;
-  }
-
-  return 1;
-}
-
 static int resolve_ecdhe_secret(SSL *ssl, int *out_need_retry,
                                 struct ssl_early_callback_ctx *early_ctx) {
   *out_need_retry = 0;
-  SSL_HANDSHAKE *hs = ssl->s3->hs;
 
-  if (ssl->s3->tmp.new_cipher->algorithm_mkey != SSL_kECDHE) {
-    return tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len);
-  }
-
+  /* We only support connections that include an ECDHE key exchange. */
   CBS key_share;
   if (!ssl_early_callback_get_extension(early_ctx, &key_share,
                                         TLSEXT_TYPE_key_share)) {
@@ -139,13 +118,11 @@
     return 0;
   }
 
-  uint16_t resumption_cipher;
   if (session != NULL &&
       /* Only resume if the session's version matches. */
       (session->ssl_version != ssl->version ||
-       !ssl_cipher_get_ecdhe_psk_cipher(session->cipher, &resumption_cipher) ||
-       !ssl_client_cipher_list_contains_cipher(&client_hello,
-                                               resumption_cipher))) {
+       !ssl_client_cipher_list_contains_cipher(
+           &client_hello, (uint16_t)SSL_CIPHER_get_id(session->cipher)))) {
     SSL_SESSION_free(session);
     session = NULL;
   }
@@ -227,39 +204,32 @@
     }
 
     ssl->s3->new_session->cipher = cipher;
-    ssl->s3->tmp.new_cipher = cipher;
-  } else {
-    uint16_t resumption_cipher;
-    if (!ssl_cipher_get_ecdhe_psk_cipher(ssl->s3->new_session->cipher,
-                                         &resumption_cipher)) {
-      OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
-      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-      return ssl_hs_error;
-    }
-    ssl->s3->tmp.new_cipher = SSL_get_cipher_by_value(resumption_cipher);
   }
 
+  ssl->s3->tmp.new_cipher = ssl->s3->new_session->cipher;
   ssl->method->received_flight(ssl);
 
-  /* The PRF hash is now known. Set up the key schedule and hash the
-   * ClientHello. */
-  size_t resumption_ctx_len =
+
+  /* The PRF hash is now known. */
+  size_t hash_len =
       EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
+
+  /* Derive resumption material. */
+  uint8_t resumption_ctx[EVP_MAX_MD_SIZE] = {0};
+  uint8_t psk_secret[EVP_MAX_MD_SIZE] = {0};
   if (ssl->s3->session_reused) {
-    uint8_t resumption_ctx[EVP_MAX_MD_SIZE];
-    if (!tls13_resumption_context(ssl, resumption_ctx, resumption_ctx_len,
+    if (!tls13_resumption_context(ssl, resumption_ctx, hash_len,
                                   ssl->s3->new_session) ||
-        !tls13_init_key_schedule(ssl, resumption_ctx, resumption_ctx_len)) {
-      return ssl_hs_error;
-    }
-  } else {
-    if (!tls13_init_key_schedule(ssl, kZeroes, resumption_ctx_len)) {
+        !tls13_resumption_psk(ssl, psk_secret, hash_len,
+                              ssl->s3->new_session)) {
       return ssl_hs_error;
     }
   }
 
-  /* Resolve PSK and incorporate it into the secret. */
-  if (!resolve_psk_secret(ssl)) {
+  /* Set up the key schedule, hash in the ClientHello, and incorporate the PSK
+   * into the running secret. */
+  if (!tls13_init_key_schedule(ssl, resumption_ctx, hash_len) ||
+      !tls13_advance_key_schedule(ssl, psk_secret, hash_len)) {
     return ssl_hs_error;
   }
 
@@ -345,14 +315,27 @@
       !CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) ||
       !CBB_add_u16_length_prefixed(&body, &extensions) ||
       !ssl_ext_pre_shared_key_add_serverhello(ssl, &extensions) ||
-      !ssl_ext_key_share_add_serverhello(ssl, &extensions) ||
-      !ssl->method->finish_message(ssl, &cbb)) {
-    CBB_cleanup(&cbb);
-    return ssl_hs_error;
+      !ssl_ext_key_share_add_serverhello(ssl, &extensions)) {
+    goto err;
+  }
+
+  if (!ssl->s3->session_reused) {
+    if (!CBB_add_u16(&extensions, TLSEXT_TYPE_signature_algorithms) ||
+        !CBB_add_u16(&extensions, 0)) {
+      goto err;
+    }
+  }
+
+  if (!ssl->method->finish_message(ssl, &cbb)) {
+    goto err;
   }
 
   hs->state = state_send_encrypted_extensions;
   return ssl_hs_write_message;
+
+err:
+  CBB_cleanup(&cbb);
+  return ssl_hs_error;
 }
 
 static enum ssl_hs_wait_t do_send_encrypted_extensions(SSL *ssl,
@@ -378,8 +361,8 @@
                                                       SSL_HANDSHAKE *hs) {
   /* Determine whether to request a client certificate. */
   ssl->s3->tmp.cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER);
-  /* CertificateRequest may only be sent in certificate-based ciphers. */
-  if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
+  /* CertificateRequest may only be sent in non-resumption handshakes. */
+  if (ssl->s3->session_reused) {
     ssl->s3->tmp.cert_request = 0;
   }
 
@@ -424,7 +407,7 @@
 
 static enum ssl_hs_wait_t do_send_server_certificate(SSL *ssl,
                                                      SSL_HANDSHAKE *hs) {
-  if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
+  if (ssl->s3->session_reused) {
     hs->state = state_send_server_finished;
     return ssl_hs_ok;
   }