Merge third_party/boringssl/src from https://boringssl.googlesource.com/boringssl.git at 751e889b1d791d2b91c1437248454fa1d4e101a5

This commit was generated by merge_from_chromium.py.

Change-Id: I29519d9fb4208df2bc243553f16b5d34329dd2a0
diff --git a/crypto/asn1/asn1_error.c b/crypto/asn1/asn1_error.c
index 81b9aff..8253322 100644
--- a/crypto/asn1/asn1_error.c
+++ b/crypto/asn1/asn1_error.c
@@ -98,7 +98,6 @@
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DECODE_ERROR), "DECODE_ERROR"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DECODING_ERROR), "DECODING_ERROR"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DEPTH_EXCEEDED), "DEPTH_EXCEEDED"},
-  {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED), "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ENCODE_ERROR), "ENCODE_ERROR"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ERROR_GETTING_TIME), "ERROR_GETTING_TIME"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ERROR_LOADING_SECTION), "ERROR_LOADING_SECTION"},
@@ -188,17 +187,14 @@
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNEXPECTED_EOC), "UNEXPECTED_EOC"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH), "UNIVERSALSTRING_IS_WRONG_LENGTH"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_FORMAT), "UNKNOWN_FORMAT"},
-  {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM), "UNKNOWN_MESSAGE_DIGEST_ALGORITHM"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_OBJECT_TYPE), "UNKNOWN_OBJECT_TYPE"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE), "UNKNOWN_PUBLIC_KEY_TYPE"},
-  {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM), "UNKNOWN_SIGNATURE_ALGORITHM"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_TAG), "UNKNOWN_TAG"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE), "UNSUPPORTED_ANY_DEFINED_BY_TYPE"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_CIPHER), "UNSUPPORTED_CIPHER"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM), "UNSUPPORTED_ENCRYPTION_ALGORITHM"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE), "UNSUPPORTED_PUBLIC_KEY_TYPE"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_TYPE), "UNSUPPORTED_TYPE"},
-  {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_WRONG_PUBLIC_KEY_TYPE), "WRONG_PUBLIC_KEY_TYPE"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_WRONG_TAG), "WRONG_TAG"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_WRONG_TYPE), "WRONG_TYPE"},
   {0, NULL},
diff --git a/crypto/buf/buf.c b/crypto/buf/buf.c
index 94bbeaf..3fd822e 100644
--- a/crypto/buf/buf.c
+++ b/crypto/buf/buf.c
@@ -187,7 +187,8 @@
     return NULL;
   }
 
-  BUF_strlcpy(ret, buf, alloc_size);
+  memcpy(ret, buf, size);
+  ret[size] = '\0';
   return ret;
 }
 
diff --git a/crypto/bytestring/bytestring_test.c b/crypto/bytestring/bytestring_test.c
index e4afccd..f30179d 100644
--- a/crypto/bytestring/bytestring_test.c
+++ b/crypto/bytestring/bytestring_test.c
@@ -109,6 +109,10 @@
   CBS data, contents;
 
   CBS_init(&data, kData1, sizeof(kData1));
+  if (CBS_peek_asn1_tag(&data, 0x1) ||
+      !CBS_peek_asn1_tag(&data, 0x30)) {
+    return 0;
+  }
   if (!CBS_get_asn1(&data, &contents, 0x30) ||
       CBS_len(&contents) != 2 ||
       memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) {
@@ -145,6 +149,11 @@
     return 0;
   }
 
+  CBS_init(&data, NULL, 0);
+  if (CBS_peek_asn1_tag(&data, 0x30)) {
+    return 0;
+  }
+
   return 1;
 }
 
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
index 244daba..07cc126 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -264,6 +264,13 @@
   return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
 }
 
+int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) {
+  if (CBS_len(cbs) < 1) {
+    return 0;
+  }
+  return CBS_data(cbs)[0] == tag_value;
+}
+
 int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
   CBS bytes;
   const uint8_t *data;
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
index d22274e..64a0ee8 100644
--- a/crypto/cipher/e_aes.c
+++ b/crypto/cipher/e_aes.c
@@ -612,7 +612,7 @@
 
 static const EVP_CIPHER aes_128_ecb = {
     NID_aes_128_ecb,     16 /* block_size */, 16 /* key_size */,
-    16 /* iv_len */,     sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+    0 /* iv_len */,      sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
     NULL /* app_data */, aes_init_key,        aes_ecb_cipher,
     NULL /* cleanup */,  NULL /* ctrl */};
 
@@ -640,7 +640,7 @@
 
 static const EVP_CIPHER aes_256_ecb = {
     NID_aes_128_ecb,     16 /* block_size */, 32 /* key_size */,
-    16 /* iv_len */,     sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+    0 /* iv_len */,      sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
     NULL /* app_data */, aes_init_key,        aes_ecb_cipher,
     NULL /* cleanup */,  NULL /* ctrl */};
 
@@ -760,7 +760,7 @@
 
 static const EVP_CIPHER aesni_128_ecb = {
     NID_aes_128_ecb,     16 /* block_size */, 16 /* key_size */,
-    16 /* iv_len */,     sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+    0 /* iv_len */,      sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
     NULL /* app_data */, aesni_init_key,      aesni_ecb_cipher,
     NULL /* cleanup */,  NULL /* ctrl */};
 
@@ -788,7 +788,7 @@
 
 static const EVP_CIPHER aesni_256_ecb = {
     NID_aes_128_ecb,     16 /* block_size */, 32 /* key_size */,
-    16 /* iv_len */,     sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+    0 /* iv_len */,      sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
     NULL /* app_data */, aesni_init_key,      aesni_ecb_cipher,
     NULL /* cleanup */,  NULL /* ctrl */};
 
diff --git a/crypto/evp/algorithm.c b/crypto/evp/algorithm.c
index 4ec111b..ea28dfa 100644
--- a/crypto/evp/algorithm.c
+++ b/crypto/evp/algorithm.c
@@ -66,9 +66,6 @@
 #include "internal.h"
 
 
-/* These functions use error codes under the ASN1 and X509 namespaces for
- * compatibility with OpenSSL. */
-
 int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
   const EVP_MD *digest;
   EVP_PKEY *pkey;
@@ -101,7 +98,7 @@
   if (!OBJ_find_sigid_by_algs(&sign_nid, EVP_MD_type(digest),
                               pkey->ameth->pkey_id)) {
     OPENSSL_PUT_ERROR(EVP, EVP_DigestSignAlgorithm,
-                      X509_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
+                      EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
     return 0;
   }
 
@@ -126,7 +123,7 @@
   if (!OBJ_find_sigid_algs(OBJ_obj2nid(algor->algorithm), &digest_nid,
                            &pkey_nid)) {
     OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
-                      ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+                      EVP_R_UNKNOWN_SIGNATURE_ALGORITHM);
     return 0;
   }
 
@@ -134,7 +131,7 @@
   ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
   if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id) {
     OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
-                      ASN1_R_WRONG_PUBLIC_KEY_TYPE);
+                      EVP_R_WRONG_PUBLIC_KEY_TYPE);
     return 0;
   }
 
@@ -142,7 +139,7 @@
   if (digest_nid == NID_undef) {
     if (!pkey->ameth || !pkey->ameth->digest_verify_init_from_algorithm) {
       OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
-                        ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+                        EVP_R_UNKNOWN_SIGNATURE_ALGORITHM);
       return 0;
     }
 
@@ -153,7 +150,7 @@
   digest = EVP_get_digestbynid(digest_nid);
   if (digest == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
-                      ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
+                      EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
     return 0;
   }
 
diff --git a/crypto/evp/evp_error.c b/crypto/evp/evp_error.c
index fae1aa7..d2d8aba 100644
--- a/crypto/evp/evp_error.c
+++ b/crypto/evp/evp_error.c
@@ -68,6 +68,7 @@
   {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_rsa_encrypt, 0), "pkey_rsa_encrypt"},
   {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_rsa_sign, 0), "pkey_rsa_sign"},
   {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_algor_to_md, 0), "rsa_algor_to_md"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_digest_verify_init_from_algorithm, 0), "rsa_digest_verify_init_from_algorithm"},
   {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_item_verify, 0), "rsa_item_verify"},
   {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_mgf1_to_md, 0), "rsa_mgf1_to_md"},
   {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_priv_decode, 0), "rsa_priv_decode"},
@@ -80,6 +81,7 @@
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DECODE_ERROR), "DECODE_ERROR"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_KEY_TYPES), "DIFFERENT_KEY_TYPES"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_PARAMETERS), "DIFFERENT_PARAMETERS"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED), "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIGEST_DOES_NOT_MATCH), "DIGEST_DOES_NOT_MATCH"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_DSA_KEY), "EXPECTING_AN_DSA_KEY"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_EC_KEY_KEY), "EXPECTING_AN_EC_KEY_KEY"},
@@ -114,12 +116,15 @@
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SHARED_INFO_ERROR), "SHARED_INFO_ERROR"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_DIGEST), "UNKNOWN_DIGEST"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_MASK_DIGEST), "UNKNOWN_MASK_DIGEST"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM), "UNKNOWN_MESSAGE_DIGEST_ALGORITHM"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE), "UNKNOWN_PUBLIC_KEY_TYPE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM), "UNKNOWN_SIGNATURE_ALGORITHM"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_ALGORITHM), "UNSUPPORTED_ALGORITHM"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_MASK_ALGORITHM), "UNSUPPORTED_MASK_ALGORITHM"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_MASK_PARAMETER), "UNSUPPORTED_MASK_PARAMETER"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE), "UNSUPPORTED_PUBLIC_KEY_TYPE"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_SIGNATURE_TYPE), "UNSUPPORTED_SIGNATURE_TYPE"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_WRONG_PUBLIC_KEY_TYPE), "WRONG_PUBLIC_KEY_TYPE"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_X931_UNSUPPORTED), "X931_UNSUPPORTED"},
   {0, NULL},
 };
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index ab83a8e..40012b3 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -656,7 +656,8 @@
                                                  EVP_PKEY *pkey) {
   /* Sanity check: make sure it is PSS */
   if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
-    OPENSSL_PUT_ERROR(EVP, rsa_item_verify, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
+    OPENSSL_PUT_ERROR(EVP, rsa_digest_verify_init_from_algorithm,
+                      EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
     return 0;
   }
   return rsa_pss_to_ctx(ctx, sigalg, pkey);
diff --git a/crypto/x509/x509_error.c b/crypto/x509/x509_error.c
index f8f6847..d521281 100644
--- a/crypto/x509/x509_error.c
+++ b/crypto/x509/x509_error.c
@@ -92,7 +92,6 @@
   {ERR_PACK(ERR_LIB_X509, 0, X509_R_CONTEXT_NOT_INITIALISED), "CONTEXT_NOT_INITIALISED"},
   {ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_ALREADY_DELTA), "CRL_ALREADY_DELTA"},
   {ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_VERIFY_FAILURE), "CRL_VERIFY_FAILURE"},
-  {ERR_PACK(ERR_LIB_X509, 0, X509_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED), "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED"},
   {ERR_PACK(ERR_LIB_X509, 0, X509_R_ERR_ASN1_LIB), "ERR_ASN1_LIB"},
   {ERR_PACK(ERR_LIB_X509, 0, X509_R_IDP_MISMATCH), "IDP_MISMATCH"},
   {ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_DIRECTORY), "INVALID_DIRECTORY"},
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index a64572c..752100e 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -1161,7 +1161,6 @@
 #define ASN1_R_NOT_ENOUGH_DATA 111
 #define ASN1_R_MSTRING_NOT_UNIVERSAL 112
 #define ASN1_R_UNKNOWN_FORMAT 113
-#define ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM 114
 #define ASN1_R_BAD_PASSWORD_READ 115
 #define ASN1_R_BAD_OBJECT_HEADER 116
 #define ASN1_R_ILLEGAL_CHARACTERS 117
@@ -1227,7 +1226,6 @@
 #define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 177
 #define ASN1_R_BUFFER_TOO_SMALL 178
 #define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 179
-#define ASN1_R_WRONG_PUBLIC_KEY_TYPE 180
 #define ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM 181
 #define ASN1_R_MIME_PARSE_ERROR 182
 #define ASN1_R_INVALID_OBJECT_ENCODING 183
@@ -1248,7 +1246,6 @@
 #define ASN1_R_NON_HEX_CHARACTERS 198
 #define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 199
 #define ASN1_R_EXPECTING_AN_ASN1_SEQUENCE 201
-#define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 202
 #define ASN1_R_STRING_TOO_SHORT 203
 #define ASN1_R_ILLEGAL_OPTIONAL_ANY 204
 #define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 205
@@ -1269,6 +1266,5 @@
 #define ASN1_R_ERROR_PARSING_SET_ELEMENT 220
 #define ASN1_R_WRONG_TAG 221
 #define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 222
-#define ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 223
 
 #endif
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index 1af20e8..acaba8e 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -141,6 +141,13 @@
  * ASN.1 header bytes too. */
 OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value);
 
+/* CBS_peek_asn1_tag looks ahead at the next ASN.1 tag and returns one
+ * if the next ASN.1 element on |cbs| would have tag |tag_value|. If
+ * |cbs| is empty or the tag does not match, it returns zero. Note: if
+ * it returns one, CBS_get_asn1 may still fail if the rest of the
+ * element is malformed. */
+OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value);
+
 /* CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from
  * |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to
  * the tag number and |*out_header_len| to the length of the ASN.1 header. If
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index fcbb085..e3922a3 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -836,6 +836,7 @@
 #define EVP_F_hmac_signctx 154
 #define EVP_F_EVP_DigestVerifyInitFromAlgorithm 155
 #define EVP_F_EVP_DigestSignAlgorithm 156
+#define EVP_F_rsa_digest_verify_init_from_algorithm 157
 #define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 100
 #define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 101
 #define EVP_R_INVALID_DIGEST_TYPE 102
@@ -883,5 +884,9 @@
 #define EVP_R_INVALID_PSS_SALTLEN 144
 #define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 145
 #define EVP_R_CONTEXT_NOT_INITIALISED 146
+#define EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 147
+#define EVP_R_WRONG_PUBLIC_KEY_TYPE 148
+#define EVP_R_UNKNOWN_SIGNATURE_ALGORITHM 149
+#define EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 150
 
 #endif  /* OPENSSL_HEADER_EVP_H */
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index a689921..2168613 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -392,9 +392,6 @@
 	int ssl_version;	/* what ssl version session info is
 				 * being kept in here? */
 
-	/* only really used in SSLv2 */
-	unsigned int key_arg_length;
-	unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH];
 	int master_key_length;
 	unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
 	/* session_id - valid? */
@@ -440,10 +437,6 @@
 	 * efficient and to implement a maximum cache size. */
 	struct ssl_session_st *prev,*next;
 	char *tlsext_hostname;
-	size_t tlsext_ecpointformatlist_length;
-	unsigned char *tlsext_ecpointformatlist; /* peer's list */
-	size_t tlsext_ellipticcurvelist_length;
-	uint16_t *tlsext_ellipticcurvelist; /* peer's list */
 	/* RFC4507 info */
 	uint8_t *tlsext_tick;	/* Session ticket */
 	size_t tlsext_ticklen;		/* Session ticket length */
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 3aea752..2a201aa 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -473,6 +473,18 @@
 		 * negotiated and the server is expected to send a
 		 * CertificateStatus message. */
 		char certificate_status_expected;
+
+		/* peer_ecpointformatlist contains the EC point
+		 * formats advertised by the peer. */
+		uint8_t *peer_ecpointformatlist;
+		size_t peer_ecpointformatlist_length;
+
+		/* Server-only: peer_ellipticcurvelist contains the EC
+		 * curve IDs advertised by the peer. This is only set
+		 * on the server's end. The server does not advertise
+		 * this extension to the client. */
+		uint16_t *peer_ellipticcurvelist;
+		size_t peer_ellipticcurvelist_length;
 		} tmp;
 
         /* Connection binding to prevent renegotiation attacks */
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 1d67ed3..398bec7 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -1294,7 +1294,6 @@
 #define X509_R_UNKNOWN_PURPOSE_ID 116
 #define X509_R_NEWER_CRL_NOT_NEWER 117
 #define X509_R_UNKNOWN_TRUST_ID 118
-#define X509_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 119
 #define X509_R_KEY_TYPE_MISMATCH 120
 #define X509_R_UNKNOWN_KEY_TYPE 121
 #define X509_R_BAD_X509_FILETYPE 122
diff --git a/ssl/pqueue/pqueue_test.c b/ssl/pqueue/pqueue_test.c
index 16a9ad8..08e686e 100644
--- a/ssl/pqueue/pqueue_test.c
+++ b/ssl/pqueue/pqueue_test.c
@@ -76,6 +76,7 @@
     }
     curr = next;
   }
+  pqueue_free(q);
   return 1;
 }
 
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index d574b25..b0ca507 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -292,8 +292,6 @@
 
 	memcpy(mac_secret,ms,i);
 
-	s->session->key_arg_length=0;
-
 	EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE));
 
 #ifdef OPENSSL_SSL_TRACE_CRYPTO
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 03997c9..215b3f6 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -1019,6 +1019,10 @@
 		sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
 	if (s->s3->tmp.certificate_types != NULL)
 		OPENSSL_free(s->s3->tmp.certificate_types);
+	if (s->s3->tmp.peer_ecpointformatlist)
+		OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
+	if (s->s3->tmp.peer_ellipticcurvelist)
+		OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
 	if (s->s3->handshake_buffer) {
 		BIO_free(s->s3->handshake_buffer);
 	}
@@ -1275,12 +1279,8 @@
 
 	case SSL_CTRL_GET_CURVES:
 		{
-		const uint16_t *clist;
-		size_t clistlen;
-		if (!s->session)
-			return 0;
-		clist = s->session->tlsext_ellipticcurvelist;
-		clistlen = s->session->tlsext_ellipticcurvelist_length;
+		const uint16_t *clist = s->s3->tmp.peer_ellipticcurvelist;
+		size_t clistlen = s->s3->tmp.peer_ellipticcurvelist_length;
 		if (parg)
 			{
 			size_t i;
@@ -1385,12 +1385,11 @@
 			}
 	case SSL_CTRL_GET_EC_POINT_FORMATS:
 		{
-		SSL_SESSION *sess = s->session;
-		const unsigned char **pformat = parg;
-		if (!sess || !sess->tlsext_ecpointformatlist)
+		if (!s->s3->tmp.peer_ecpointformatlist)
 			return 0;
-		*pformat = sess->tlsext_ecpointformatlist;
-		return (int)sess->tlsext_ecpointformatlist_length;
+		const uint8_t **pformat = parg;
+		*pformat = s->s3->tmp.peer_ecpointformatlist;
+		return (int)s->s3->tmp.peer_ecpointformatlist_length;
 		}
 
 	case SSL_CTRL_CHANNEL_ID:
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 8acd0eb..5e86017 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -108,7 +108,6 @@
 	ASN1_OCTET_STRING master_key;
 	ASN1_OCTET_STRING session_id;
 	ASN1_OCTET_STRING session_id_context;
-	ASN1_OCTET_STRING key_arg;
 	ASN1_INTEGER time;
 	ASN1_INTEGER timeout;
 	ASN1_INTEGER verify_result;
@@ -187,10 +186,6 @@
 	a.session_id_context.type=V_ASN1_OCTET_STRING;
 	a.session_id_context.data=in->sid_ctx;
 
-	a.key_arg.length=in->key_arg_length;
-	a.key_arg.type=V_ASN1_OCTET_STRING;
-	a.key_arg.data=in->key_arg;
-
 	if (in->time != 0L)
 		{
 		a.time.length=LSIZE2;
@@ -282,8 +277,6 @@
 	M_ASN1_I2D_len(&(a.cipher),		i2d_ASN1_OCTET_STRING);
 	M_ASN1_I2D_len(&(a.session_id),		i2d_ASN1_OCTET_STRING);
 	M_ASN1_I2D_len(&(a.master_key),		i2d_ASN1_OCTET_STRING);
-	if (in->key_arg_length > 0)
-		M_ASN1_I2D_len_IMP_opt(&(a.key_arg),i2d_ASN1_OCTET_STRING);
 	if (in->time != 0L)
 		M_ASN1_I2D_len_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
 	if (in->timeout != 0L)
@@ -321,8 +314,6 @@
 	M_ASN1_I2D_put(&(a.cipher),		i2d_ASN1_OCTET_STRING);
 	M_ASN1_I2D_put(&(a.session_id),		i2d_ASN1_OCTET_STRING);
 	M_ASN1_I2D_put(&(a.master_key),		i2d_ASN1_OCTET_STRING);
-	if (in->key_arg_length > 0)
-		M_ASN1_I2D_put_IMP_opt(&(a.key_arg),i2d_ASN1_OCTET_STRING,0);
 	if (in->time != 0L)
 		M_ASN1_I2D_put_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
 	if (in->timeout != 0L)
@@ -448,12 +439,9 @@
 
 	os.length=0;
 
+	/* [0] is the tag for key_arg, a no longer used remnant of
+	 * SSLv2. */
 	M_ASN1_D2I_get_IMP_opt(osp,d2i_ASN1_OCTET_STRING,0,V_ASN1_OCTET_STRING);
-	if (os.length > SSL_MAX_KEY_ARG_LENGTH)
-		ret->key_arg_length=SSL_MAX_KEY_ARG_LENGTH;
-	else
-		ret->key_arg_length=os.length;
-	memcpy(ret->key_arg,os.data,ret->key_arg_length);
 	if (os.data != NULL) OPENSSL_free(os.data);
 
 	ai.length=0;
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index c8de778..0cccbc7 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -702,17 +702,12 @@
 
 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
 
-	OPENSSL_cleanse(ss->key_arg,sizeof ss->key_arg);
 	OPENSSL_cleanse(ss->master_key,sizeof ss->master_key);
 	OPENSSL_cleanse(ss->session_id,sizeof ss->session_id);
 	if (ss->sess_cert != NULL) ssl_sess_cert_free(ss->sess_cert);
 	if (ss->peer != NULL) X509_free(ss->peer);
 	if (ss->tlsext_hostname != NULL) OPENSSL_free(ss->tlsext_hostname);
 	if (ss->tlsext_tick != NULL) OPENSSL_free(ss->tlsext_tick);
-	ss->tlsext_ecpointformatlist_length = 0;
-	if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist);
-	ss->tlsext_ellipticcurvelist_length = 0;
-	if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist);
 	if (ss->tlsext_signed_cert_timestamp_list != NULL)
 		OPENSSL_free(ss->tlsext_signed_cert_timestamp_list);
 	if (ss->ocsp_response != NULL)
diff --git a/ssl/ssl_test.c b/ssl/ssl_test.c
index 68889a0..a202273 100644
--- a/ssl/ssl_test.c
+++ b/ssl/ssl_test.c
@@ -13,7 +13,10 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
 #include <stdio.h>
+#include <string.h>
 
+#include <openssl/base64.h>
+#include <openssl/bio.h>
 #include <openssl/err.h>
 #include <openssl/ssl.h>
 
@@ -265,10 +268,172 @@
   return 1;
 }
 
+/* kOpenSSLSession is a serialized SSL_SESSION generated from openssl
+ * s_client -sess_out. */
+static const char kOpenSSLSession[] =
+  "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"
+  "i4gv7Y5oliyn";
+
+/* kCustomSession is a custom serialized SSL_SESSION generated by
+ * filling in missing fields from |kOpenSSLSession|. This includes
+ * providing |peer_sha256|, so |peer| is not serialized. */
+static const char kCustomSession[] =
+  "MIIBggIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
+  "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
+  "IWoJgAEBoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29t"
+  "pwcEBWhlbGxvqAcEBXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXq"
+  "KwOBfF9vE4KX0NxeLwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362z"
+  "ZnY27GpTw+Kwd751CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3"
+  "+inbMaVigtK4PLyPq+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5o"
+  "liynrSIEIAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQB"
+  "BLADBAEF";
+
+/* kCustomSession2 is kCustomSession with the old SSLv2-only key_arg
+ * field removed. Encoding the decoded version of kCustomSession
+ * should not preserve key_arg. */
+static const char kCustomSession2[] =
+  "MIIBfwIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ"
+  "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH"
+  "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tpwcE"
+  "BWhlbGxvqAcEBXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXqKwOB"
+  "fF9vE4KX0NxeLwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362zZnY2"
+  "7GpTw+Kwd751CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3+inb"
+  "MaVigtK4PLyPq+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5oliyn"
+  "rSIEIAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQBBLAD"
+  "BAEF";
+
+static int decode_base64(uint8_t **out, size_t *out_len, const char *in) {
+  size_t len;
+
+  if (!EVP_DecodedLength(&len, strlen(in))) {
+    fprintf(stderr, "EVP_DecodedLength failed\n");
+    return 0;
+  }
+
+  *out = OPENSSL_malloc(len);
+  if (*out == NULL) {
+    fprintf(stderr, "malloc failed\n");
+    return 0;
+  }
+
+  if (!EVP_DecodeBase64(*out, out_len, len, (const uint8_t *)in,
+                        strlen(in))) {
+    fprintf(stderr, "EVP_DecodeBase64 failed\n");
+    OPENSSL_free(*out);
+    *out = NULL;
+    return 0;
+  }
+  return 1;
+}
+
+static int test_ssl_session_asn1(const char *input_b64,
+                                 const char *expected_b64) {
+  int ret = 0, len;
+  size_t input_len, expected_len;
+  uint8_t *input = NULL, *expected = NULL, *encoded = NULL;
+  const uint8_t *cptr;
+  uint8_t *ptr;
+  SSL_SESSION *session = NULL;
+
+  /* Decode the input. */
+  if (!decode_base64(&input, &input_len, input_b64) ||
+      !decode_base64(&expected, &expected_len, expected_b64)) {
+    goto done;
+  }
+
+  /* Verify the SSL_SESSION decodes. */
+  cptr = input;
+  session = d2i_SSL_SESSION(NULL, &cptr, input_len);
+  if (session == NULL || cptr != input + input_len) {
+    fprintf(stderr, "d2i_SSL_SESSION failed\n");
+    goto done;
+  }
+
+  /* Verify the SSL_SESSION encoding round-trips. */
+  len = i2d_SSL_SESSION(session, NULL);
+  if (len < 0 || (size_t)len != expected_len) {
+    fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n");
+    goto done;
+  }
+
+  encoded = OPENSSL_malloc(expected_len);
+  if (encoded == NULL) {
+    fprintf(stderr, "malloc failed\n");
+    goto done;
+  }
+  ptr = encoded;
+  len = i2d_SSL_SESSION(session, &ptr);
+  if (len < 0 || (size_t)len != expected_len) {
+    fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n");
+    goto done;
+  }
+  if (ptr != encoded + expected_len) {
+    fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n");
+    goto done;
+  }
+  if (memcmp(expected, encoded, expected_len) != 0) {
+    fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n");
+    goto done;
+  }
+
+  ret = 1;
+
+ done:
+  if (!ret) {
+    BIO_print_errors_fp(stderr);
+  }
+
+  if (session) {
+    SSL_SESSION_free(session);
+  }
+  if (input) {
+    OPENSSL_free(input);
+  }
+  if (expected) {
+    OPENSSL_free(expected);
+  }
+  if (encoded) {
+    OPENSSL_free(encoded);
+  }
+  return ret;
+}
+
 int main(void) {
   SSL_library_init();
 
-  if (!test_cipher_rules()) {
+  if (!test_cipher_rules() ||
+      !test_ssl_session_asn1(kOpenSSLSession, kOpenSSLSession) ||
+      !test_ssl_session_asn1(kCustomSession, kCustomSession2) ||
+      !test_ssl_session_asn1(kCustomSession2, kCustomSession2)) {
     return 1;
   }
 
diff --git a/ssl/ssl_txt.c b/ssl/ssl_txt.c
index bf33ce4..c83f589 100644
--- a/ssl/ssl_txt.c
+++ b/ssl/ssl_txt.c
@@ -156,16 +156,6 @@
 		{
 		if (BIO_printf(bp,"%02X",x->master_key[i]) <= 0) goto err;
 		}
-	if (BIO_puts(bp,"\n    Key-Arg   : ") <= 0) goto err;
-	if (x->key_arg_length == 0)
-		{
-		if (BIO_puts(bp,"None") <= 0) goto err;
-		}
-	else
-		for (i=0; i<x->key_arg_length; i++)
-			{
-			if (BIO_printf(bp,"%02X",x->key_arg[i]) <= 0) goto err;
-			}
 	if (BIO_puts(bp,"\n    PSK identity: ") <= 0) goto err;
 	if (BIO_printf(bp, "%s", x->psk_identity ? x->psk_identity : "None") <= 0) goto err;
 	if (BIO_puts(bp,"\n    PSK identity hint: ") <= 0) goto err;
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 48fcd87..dd00d0a 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -334,6 +334,20 @@
 	return 1;
 	}
 
+static void tls1_cleanup_enc_ctx(EVP_CIPHER_CTX **ctx)
+	{
+	if (*ctx != NULL)
+		EVP_CIPHER_CTX_free(*ctx);
+	*ctx = NULL;
+	}
+
+static void tls1_cleanup_hash_ctx(EVP_MD_CTX **ctx)
+	{
+	if (*ctx != NULL)
+		EVP_MD_CTX_destroy(*ctx);
+	*ctx = NULL;
+	}
+
 static int tls1_change_cipher_state_aead(SSL *s, char is_read,
 	const unsigned char *key, unsigned key_len,
 	const unsigned char *iv, unsigned iv_len,
@@ -346,6 +360,17 @@
 	 * to cope with the largest pair of keys. */
 	uint8_t mac_key_and_key[32 /* HMAC(SHA256) */ + 32 /* AES-256 */];
 
+	if (is_read)
+		{
+		tls1_cleanup_enc_ctx(&s->enc_read_ctx);
+		tls1_cleanup_hash_ctx(&s->read_hash);
+		}
+	else
+		{
+		tls1_cleanup_enc_ctx(&s->enc_write_ctx);
+		tls1_cleanup_hash_ctx(&s->write_hash);
+		}
+
 	if (mac_secret_len > 0)
 		{
 		/* This is a "stateful" AEAD (for compatibility with pre-AEAD
@@ -376,7 +401,14 @@
 
 	if (!EVP_AEAD_CTX_init(&aead_ctx->ctx, aead, key, key_len,
 			       EVP_AEAD_DEFAULT_TAG_LENGTH, NULL /* engine */))
+		{
+		OPENSSL_free(aead_ctx);
+		if (is_read)
+			s->aead_read_ctx = NULL;
+		else
+			s->aead_write_ctx = NULL;
 		return 0;
+		}
 	if (iv_len > sizeof(aead_ctx->fixed_nonce))
 		{
 		OPENSSL_PUT_ERROR(SSL, tls1_change_cipher_state_aead, ERR_R_INTERNAL_ERROR);
@@ -399,6 +431,16 @@
 	return 1;
 	}
 
+static void tls1_cleanup_aead_ctx(SSL_AEAD_CTX **ctx)
+	{
+	if (*ctx != NULL)
+		{
+		EVP_AEAD_CTX_cleanup(&(*ctx)->ctx);
+		OPENSSL_free(*ctx);
+		}
+	*ctx = NULL;
+	}
+
 /* tls1_change_cipher_state_cipher performs the work needed to switch cipher
  * states when using EVP_CIPHER. The argument |is_read| is true iff this
  * function is being called due to reading, as opposed to writing, a
@@ -416,6 +458,11 @@
 	EVP_MD_CTX *mac_ctx;
 
 	if (is_read)
+		tls1_cleanup_aead_ctx(&s->aead_read_ctx);
+	else
+		tls1_cleanup_aead_ctx(&s->aead_write_ctx);
+
+	if (is_read)
 		{
 		if (s->enc_read_ctx != NULL && !SSL_IS_DTLS(s))
 			EVP_CIPHER_CTX_cleanup(s->enc_read_ctx);
@@ -499,9 +546,6 @@
 	if (!SSL_IS_DTLS(s))
 		memset(is_read ? s->s3->read_sequence : s->s3->write_sequence, 0, 8);
 
-	/* key_arg is used for SSLv2. We don't need it for TLS. */
-	s->session->key_arg_length = 0;
-
 	mac_secret_len = s->s3->tmp.new_mac_secret_size;
 
 	if (aead != NULL)
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index a14ce5a..4b13cfe 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -441,8 +441,8 @@
 	{
 	if (get_peer_curves)
 		{
-		*out_curve_ids = s->session->tlsext_ellipticcurvelist;
-		*out_curve_ids_len = s->session->tlsext_ellipticcurvelist_length;
+		*out_curve_ids = s->s3->tmp.peer_ellipticcurvelist;
+		*out_curve_ids_len = s->s3->tmp.peer_ellipticcurvelist_length;
 		return;
 		}
 
@@ -590,8 +590,8 @@
  * peer's point format preferences. */
 static int tls1_check_point_format(SSL *s, uint8_t comp_id)
 	{
-	uint8_t *p = s->session->tlsext_ecpointformatlist;
-	size_t plen = s->session->tlsext_ecpointformatlist_length;
+	uint8_t *p = s->s3->tmp.peer_ecpointformatlist;
+	size_t plen = s->s3->tmp.peer_ecpointformatlist_length;
 	size_t i;
 
 	/* If point formats extension present check it, otherwise everything
@@ -1206,7 +1206,7 @@
 	unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 	unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
 	int using_ecc = (alg_k & SSL_kEECDH) || (alg_a & SSL_aECDSA);
-	using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
+	using_ecc = using_ecc && (s->s3->tmp.peer_ecpointformatlist != NULL);
 	/* don't add extensions for SSLv3, unless doing secure renegotiation */
 	if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
 		return orig;
@@ -1436,7 +1436,7 @@
 		OPENSSL_free(s->cert->peer_sigalgs);
 		s->cert->peer_sigalgs = NULL;
 		}
-	/* Clear any shared sigtnature algorithms */
+	/* Clear any shared signature algorithms */
 	if (s->cert->shared_sigalgs)
 		{
 		OPENSSL_free(s->cert->shared_sigalgs);
@@ -1448,6 +1448,19 @@
 		s->cert->pkeys[i].digest = NULL;
 		s->cert->pkeys[i].valid_flags = 0;
 		}
+	/* Clear ECC extensions */
+	if (s->s3->tmp.peer_ecpointformatlist != 0)
+		{
+		OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
+		s->s3->tmp.peer_ecpointformatlist = NULL;
+		s->s3->tmp.peer_ecpointformatlist_length = 0;
+		}
+	if (s->s3->tmp.peer_ellipticcurvelist != 0)
+		{
+		OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
+		s->s3->tmp.peer_ellipticcurvelist = NULL;
+		s->s3->tmp.peer_ellipticcurvelist_length = 0;
+		}
 
 	/* There may be no extensions. */
 	if (CBS_len(cbs) == 0)
@@ -1593,15 +1606,12 @@
 				return 0;
 				}
 
-			if (!s->hit)
+			if (!CBS_stow(&ec_point_format_list,
+					&s->s3->tmp.peer_ecpointformatlist,
+					&s->s3->tmp.peer_ecpointformatlist_length))
 				{
-				if (!CBS_stow(&ec_point_format_list,
-						&s->session->tlsext_ecpointformatlist,
-						&s->session->tlsext_ecpointformatlist_length))
-					{
-					*out_alert = SSL_AD_INTERNAL_ERROR;
-					return 0;
-					}
+				*out_alert = SSL_AD_INTERNAL_ERROR;
+				return 0;
 				}
 			}
 		else if (type == TLSEXT_TYPE_elliptic_curves)
@@ -1618,37 +1628,34 @@
 				return 0;
 				}
 
-			if (!s->hit)
+			if (s->s3->tmp.peer_ellipticcurvelist)
 				{
-				if (s->session->tlsext_ellipticcurvelist)
-					{
-					OPENSSL_free(s->session->tlsext_ellipticcurvelist);
-					s->session->tlsext_ellipticcurvelist_length = 0;
-					}
-				s->session->tlsext_ellipticcurvelist =
-					(uint16_t*)OPENSSL_malloc(CBS_len(&elliptic_curve_list));
-				if (s->session->tlsext_ellipticcurvelist == NULL)
-					{
-					*out_alert = SSL_AD_INTERNAL_ERROR;
-					return 0;
-					}
-				num_curves = CBS_len(&elliptic_curve_list) / 2;
-				for (i = 0; i < num_curves; i++)
-					{
-					if (!CBS_get_u16(&elliptic_curve_list,
-							&s->session->tlsext_ellipticcurvelist[i]))
-						{
-						*out_alert = SSL_AD_INTERNAL_ERROR;
-						return 0;
-						}
-					}
-				if (CBS_len(&elliptic_curve_list) != 0)
-					{
-					*out_alert = SSL_AD_INTERNAL_ERROR;
-					return 0;
-					}
-				s->session->tlsext_ellipticcurvelist_length = num_curves;
+				OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist);
+				s->s3->tmp.peer_ellipticcurvelist_length = 0;
 				}
+			s->s3->tmp.peer_ellipticcurvelist =
+				(uint16_t*)OPENSSL_malloc(CBS_len(&elliptic_curve_list));
+			if (s->s3->tmp.peer_ellipticcurvelist == NULL)
+					{
+					*out_alert = SSL_AD_INTERNAL_ERROR;
+					return 0;
+					}
+			num_curves = CBS_len(&elliptic_curve_list) / 2;
+			for (i = 0; i < num_curves; i++)
+				{
+				if (!CBS_get_u16(&elliptic_curve_list,
+						&s->s3->tmp.peer_ellipticcurvelist[i]))
+					{
+					*out_alert = SSL_AD_INTERNAL_ERROR;
+					return 0;
+					}
+				}
+			if (CBS_len(&elliptic_curve_list) != 0)
+				{
+				*out_alert = SSL_AD_INTERNAL_ERROR;
+				return 0;
+				}
+			s->s3->tmp.peer_ellipticcurvelist_length = num_curves;
 			}
 		else if (type == TLSEXT_TYPE_session_ticket)
 			{
@@ -1851,6 +1858,14 @@
 		s->s3->alpn_selected = NULL;
 		}
 
+	/* Clear ECC extensions */
+	if (s->s3->tmp.peer_ecpointformatlist != 0)
+		{
+		OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
+		s->s3->tmp.peer_ecpointformatlist = NULL;
+		s->s3->tmp.peer_ecpointformatlist_length = 0;
+		}
+
 	/* There may be no extensions. */
 	if (CBS_len(cbs) == 0)
 		{
@@ -1911,15 +1926,12 @@
 				return 0;
 				}
 
-			if (!s->hit)
+			if (!CBS_stow(&ec_point_format_list,
+					&s->s3->tmp.peer_ecpointformatlist,
+					&s->s3->tmp.peer_ecpointformatlist_length))
 				{
-				if (!CBS_stow(&ec_point_format_list,
-						&s->session->tlsext_ecpointformatlist,
-						&s->session->tlsext_ecpointformatlist_length))
-					{
-					*out_alert = SSL_AD_INTERNAL_ERROR;
-					return 0;
-					}
+				*out_alert = SSL_AD_INTERNAL_ERROR;
+				return 0;
 				}
 			}
 		else if (type == TLSEXT_TYPE_session_ticket)
@@ -2379,7 +2391,10 @@
 	HMAC_Final(&hctx, tick_hmac, NULL);
 	HMAC_CTX_cleanup(&hctx);
 	if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
+		{
+		EVP_CIPHER_CTX_cleanup(&ctx);
 		return 2;
+		}
 	/* Attempt to decrypt session data */
 	/* Move p after IV to start of encrypted ticket, update length */
 	p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 5ee7c65..6b27e26 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -117,8 +117,6 @@
   if (config->advertise_npn.empty())
     return SSL_TLSEXT_ERR_NOACK;
 
-  // TODO(davidben): Support passing byte strings with NULs to the
-  // test shim.
   *out = (const uint8_t*)config->advertise_npn.data();
   *out_len = config->advertise_npn.size();
   return SSL_TLSEXT_ERR_OK;
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index cf244bc..8b2c750 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -464,6 +464,14 @@
 	// AllowSessionVersionMismatch causes the server to resume sessions
 	// regardless of the version associated with the session.
 	AllowSessionVersionMismatch bool
+
+	// CorruptTicket causes a client to corrupt a session ticket before
+	// sending it in a resume handshake.
+	CorruptTicket bool
+
+	// OversizedSessionId causes the session id that is sent with a ticket
+	// resumption attempt to be too large (33 bytes).
+	OversizedSessionId bool
 }
 
 func (c *Config) serverInit() {
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index d78e767..f4cadc2 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -148,10 +148,25 @@
 
 	if session != nil {
 		hello.sessionTicket = session.sessionTicket
+		if c.config.Bugs.CorruptTicket {
+			hello.sessionTicket = make([]byte, len(session.sessionTicket))
+			copy(hello.sessionTicket, session.sessionTicket)
+			if len(hello.sessionTicket) > 0 {
+				offset := 40
+				if offset > len(hello.sessionTicket) {
+					offset = len(hello.sessionTicket) - 1
+				}
+				hello.sessionTicket[offset] ^= 0x40
+			}
+		}
 		// A random session ID is used to detect when the
 		// server accepted the ticket and is resuming a session
 		// (see RFC 5077).
-		hello.sessionId = make([]byte, 16)
+		sessionIdLen := 16
+		if c.config.Bugs.OversizedSessionId {
+			sessionIdLen = 33
+		}
+		hello.sessionId = make([]byte, sessionIdLen)
 		if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
 			c.sendAlert(alertInternalError)
 			return errors.New("tls: short read from Rand: " + err.Error())
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 323f43f..b4c2e61 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -649,6 +649,10 @@
 }
 
 func runTest(test *testCase, buildDir string) error {
+	if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
+		panic("Error expected without shouldFail in " + test.name)
+	}
+
 	shimEnd, conn := openSocketPair()
 	shimEndResume, connResume := openSocketPair()
 
@@ -1542,6 +1546,31 @@
 		expectedNextProtoType: alpn,
 		resumeSession:         true,
 	})
+	// Resume with a corrupt ticket.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "CorruptTicket",
+		config: Config{
+			Bugs: ProtocolBugs{
+				CorruptTicket: true,
+			},
+		},
+		resumeSession: true,
+		flags:         []string{"-expect-session-miss"},
+	})
+	// Resume with an oversized session id.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "OversizedSessionId",
+		config: Config{
+			Bugs: ProtocolBugs{
+				OversizedSessionId: true,
+			},
+		},
+		resumeSession: true,
+		shouldFail: true,
+		expectedError: ":DECODE_ERROR:",
+	})
 }
 
 func addResumptionVersionTests() {