Merge from Chromium at DEPS revision db3f05efe0f9

This commit was generated by merge_to_master.py.

Change-Id: Ia542726d5df7935b2f79e8de6880d101853bb4c9
diff --git a/BUILDING b/BUILDING
index ee6b0ab..cf239e9 100644
--- a/BUILDING
+++ b/BUILDING
@@ -25,4 +25,9 @@
 BORINGSSL_SHARED_LIBRARY defined in the code which #includes the BoringSSL
 headers.
 
+To build on Windows, Yasm[2] is required for assembly. Either ensure yasm.exe
+is in %PATH% or configure CMAKE_ASM_NASM_COMPILER appropriately. Note that
+full Windows support is still in progress.
+
 [1] http://martine.github.io/ninja/
+[2] http://yasm.tortall.net/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index add0c1a..bdfaee4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,6 +8,7 @@
 elseif(MSVC)
 	# Disable warnings for implicit integer narrowing.
 	set(CMAKE_C_FLAGS "/wd4267")
+	set(CMAKE_CXX_FLAGS "/wd4267")
 endif()
 
 add_definitions(-DBORINGSSL_IMPLEMENTATION)
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index 5d656ec..d820e82 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -10,14 +10,16 @@
 	enable_language(ASM)
 else()
 	if (CMAKE_CL_64)
-		message("Using masm")
-		set(PERLASM_STYLE masm)
+		message("Using nasm")
+		set(PERLASM_STYLE nasm)
 	else()
 		message("Using win32n")
 		set(PERLASM_STYLE win32n)
 	endif()
+
+	# On Windows, we use the NASM output, specifically built with Yasm.
 	set(ASM_EXT asm)
-	enable_language(ASM_MASM)
+	enable_language(ASM_NASM)
 endif()
 
 function(perlasm dest src)
@@ -27,9 +29,10 @@
 		DEPENDS
 		${src}
 		${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl
+		${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl
 		${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl
-		${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl
-		${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl
+		${PROJECT_SOURCE_DIR}/crypto/perlasm/x86masm.pl
+		${PROJECT_SOURCE_DIR}/crypto/perlasm/x86nasm.pl
 		WORKING_DIRECTORY .
 	)
 endfunction()
diff --git a/crypto/asn1/asn1_locl.h b/crypto/asn1/asn1_locl.h
index 1444390..ca5f612 100644
--- a/crypto/asn1/asn1_locl.h
+++ b/crypto/asn1/asn1_locl.h
@@ -71,25 +71,3 @@
 	unsigned long oid_flags;
 	unsigned long str_flags;
 	} /* ASN1_PCTX */;
-
-/* ASN1 public key method structure */
-
-
-/* Method to handle CRL access.
- * In general a CRL could be very large (several Mb) and can consume large
- * amounts of resources if stored in memory by multiple processes.
- * This method allows general CRL operations to be redirected to more
- * efficient callbacks: for example a CRL entry database.
- */
-
-#define X509_CRL_METHOD_DYNAMIC		1
-
-struct x509_crl_method_st
-	{
-	int flags;
-	int (*crl_init)(X509_CRL *crl);
-	int (*crl_free)(X509_CRL *crl);
-	int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret,
-				ASN1_INTEGER *ser, X509_NAME *issuer);
-	int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk);
-	};
diff --git a/crypto/bio/CMakeLists.txt b/crypto/bio/CMakeLists.txt
index 86092f0..9178931 100644
--- a/crypto/bio/CMakeLists.txt
+++ b/crypto/bio/CMakeLists.txt
@@ -26,3 +26,6 @@
 )
 
 target_link_libraries(bio_test crypto)
+if (WIN32)
+	target_link_libraries(bio_test ws2_32)
+endif()
diff --git a/crypto/bn/asm/x86_64-gcc.c b/crypto/bn/asm/x86_64-gcc.c
index be119aa..1de0f42 100644
--- a/crypto/bn/asm/x86_64-gcc.c
+++ b/crypto/bn/asm/x86_64-gcc.c
@@ -56,6 +56,8 @@
  *    machine.
  */
 
+ /* TODO(davidben): Get this file working on Windows x64. */
+
 #undef mul
 #undef mul_add
 
diff --git a/crypto/bn/generic.c b/crypto/bn/generic.c
index b745750..53b5ce1 100644
--- a/crypto/bn/generic.c
+++ b/crypto/bn/generic.c
@@ -61,8 +61,13 @@
 #include "internal.h"
 
 
-#if defined(OPENSSL_WINDOWS) || defined(OPENSSL_NO_ASM) || \
-    (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86))
+/* Generic implementations of most operations are needed for:
+ * - Configurations without inline assembly.
+ * - Architectures other than x86 or x86_64.
+ * - Windows x84_64; x86_64-gcc.c does not build on MSVC. */
+#if defined(OPENSSL_NO_ASM) || \
+    (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) || \
+    (defined(OPENSSL_X86_64) && defined(OPENSSL_WINDOWS))
 
 #if defined(OPENSSL_WINDOWS)
 #define alloca _alloca
@@ -817,9 +822,9 @@
 #endif /* !BN_LLONG */
 
 void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
-#ifdef BN_LLONG
+#if defined(BN_LLONG)
   BN_ULLONG t;
-#else
+#elif !defined(BN_UMULT_LOHI) && !defined(BN_UMULT_HIGH)
   BN_ULONG bl, bh;
 #endif
   BN_ULONG t1, t2;
@@ -925,9 +930,9 @@
 }
 
 void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
-#ifdef BN_LLONG
+#if defined(BN_LLONG)
   BN_ULLONG t;
-#else
+#elif !defined(BN_UMULT_LOHI) && !defined(BN_UMULT_HIGH)
   BN_ULONG bl, bh;
 #endif
   BN_ULONG t1, t2;
@@ -969,9 +974,9 @@
 }
 
 void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
-#ifdef BN_LLONG
+#if defined(BN_LLONG)
   BN_ULLONG t, tt;
-#else
+#elif !defined(BN_UMULT_LOHI) && !defined(BN_UMULT_HIGH)
   BN_ULONG bl, bh;
 #endif
   BN_ULONG t1, t2;
@@ -1049,9 +1054,9 @@
 }
 
 void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
-#ifdef BN_LLONG
+#if defined(BN_LLONG)
   BN_ULLONG t, tt;
-#else
+#elif !defined(BN_UMULT_LOHI) && !defined(BN_UMULT_HIGH)
   BN_ULONG bl, bh;
 #endif
   BN_ULONG t1, t2;
diff --git a/crypto/bn/internal.h b/crypto/bn/internal.h
index 88ab547..ab09c6e 100644
--- a/crypto/bn/internal.h
+++ b/crypto/bn/internal.h
@@ -138,7 +138,6 @@
 #if defined(OPENSSL_64_BIT)
 
 #define BN_ULLONG	unsigned long long
-#define BN_LONG		long
 #define BN_BITS		128
 #define BN_BYTES	8
 #define BN_BITS4	32
@@ -158,7 +157,6 @@
 
 #define BN_ULLONG	unsigned long long
 #define BN_MASK	(0xffffffffffffffffLL)
-#define BN_LONG		int32_t
 #define BN_BITS		64
 #define BN_BYTES	4
 #define BN_BITS4	16
diff --git a/crypto/bytestring/bytestring_test.c b/crypto/bytestring/bytestring_test.c
index f30179d..ba70bcf 100644
--- a/crypto/bytestring/bytestring_test.c
+++ b/crypto/bytestring/bytestring_test.c
@@ -19,6 +19,7 @@
 #include <openssl/bytestring.h>
 
 #include "internal.h"
+#include "../internal.h"
 
 
 static int test_skip(void) {
@@ -105,8 +106,14 @@
   static const uint8_t kData3[] = {0x30, 0x80};
   static const uint8_t kData4[] = {0x30, 0x81, 1, 1};
   static const uint8_t kData5[] = {0x30, 0x82, 0, 1, 1};
+  static const uint8_t kData6[] = {0xa1, 3, 0x4, 1, 1};
+  static const uint8_t kData7[] = {0xa1, 3, 0x4, 2, 1};
+  static const uint8_t kData8[] = {0xa1, 3, 0x2, 1, 1};
+  static const uint8_t kData9[] = {0xa1, 3, 0x2, 1, 0xff};
 
   CBS data, contents;
+  int present;
+  uint64_t value;
 
   CBS_init(&data, kData1, sizeof(kData1));
   if (CBS_peek_asn1_tag(&data, 0x1) ||
@@ -150,10 +157,106 @@
   }
 
   CBS_init(&data, NULL, 0);
+  /* peek at empty data. */
   if (CBS_peek_asn1_tag(&data, 0x30)) {
     return 0;
   }
 
+  CBS_init(&data, NULL, 0);
+  /* optional elements at empty data. */
+  if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) ||
+      present ||
+      !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) ||
+      present ||
+      CBS_len(&contents) != 0 ||
+      !CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0) ||
+      CBS_len(&contents) != 0 ||
+      !CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) ||
+      value != 42) {
+    return 0;
+  }
+
+  CBS_init(&data, kData6, sizeof(kData6));
+  /* optional element. */
+  if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) ||
+      present ||
+      !CBS_get_optional_asn1(&data, &contents, &present, 0xa1) ||
+      !present ||
+      CBS_len(&contents) != 3 ||
+      memcmp(CBS_data(&contents), "\x04\x01\x01", 3) != 0) {
+    return 0;
+  }
+
+  CBS_init(&data, kData6, sizeof(kData6));
+  /* optional octet string. */
+  if (!CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) ||
+      present ||
+      CBS_len(&contents) != 0 ||
+      !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1) ||
+      !present ||
+      CBS_len(&contents) != 1 ||
+      CBS_data(&contents)[0] != 1) {
+    return 0;
+  }
+
+  CBS_init(&data, kData7, sizeof(kData7));
+  /* invalid optional octet string. */
+  if (CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)) {
+    return 0;
+  }
+
+  CBS_init(&data, kData8, sizeof(kData8));
+  /* optional octet string. */
+  if (!CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) ||
+      value != 42 ||
+      !CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42) ||
+      value != 1) {
+    return 0;
+  }
+
+  CBS_init(&data, kData9, sizeof(kData9));
+  /* invalid optional integer. */
+  if (CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)) {
+    return 0;
+  }
+
+  return 1;
+}
+
+static int test_get_optional_asn1_bool(void) {
+  CBS data;
+  int val;
+
+  static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff};
+  static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00};
+  static const uint8_t kInvalid[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x01};
+
+  CBS_init(&data, NULL, 0);
+  val = 2;
+  if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) ||
+      val != 0) {
+    return 0;
+  }
+
+  CBS_init(&data, kTrue, sizeof(kTrue));
+  val = 2;
+  if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) ||
+      val != 1) {
+    return 0;
+  }
+
+  CBS_init(&data, kFalse, sizeof(kFalse));
+  val = 2;
+  if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1) ||
+      val != 0) {
+    return 0;
+  }
+
+  CBS_init(&data, kInvalid, sizeof(kInvalid));
+  if (CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1)) {
+    return 0;
+  }
+
   return 1;
 }
 
@@ -443,6 +546,89 @@
                         sizeof(kNSSBER));
 }
 
+typedef struct {
+  uint64_t value;
+  const char *encoding;
+  size_t encoding_len;
+} ASN1_UINT64_TEST;
+
+static const ASN1_UINT64_TEST kAsn1Uint64Tests[] = {
+  {0, "\x02\x01\x00", 3},
+  {1, "\x02\x01\x01", 3},
+  {127, "\x02\x01\x7f", 3},
+  {128, "\x02\x02\x00\x80", 4},
+  {0xdeadbeef, "\x02\x05\x00\xde\xad\xbe\xef", 7},
+  {OPENSSL_U64(0x0102030405060708),
+   "\x02\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10},
+  {OPENSSL_U64(0xffffffffffffffff),
+    "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11},
+};
+
+typedef struct {
+  const char *encoding;
+  size_t encoding_len;
+} ASN1_INVALID_UINT64_TEST;
+
+static const ASN1_INVALID_UINT64_TEST kAsn1InvalidUint64Tests[] = {
+  /* Bad tag. */
+  {"\x03\x01\x00", 3},
+  /* Empty contents. */
+  {"\x02\x00", 2},
+  /* Negative number. */
+  {"\x02\x01\x80", 3},
+  /* Overflow */
+  {"\x02\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
+};
+
+static int test_asn1_uint64(void) {
+  size_t i;
+
+  for (i = 0; i < sizeof(kAsn1Uint64Tests) / sizeof(kAsn1Uint64Tests[0]); i++) {
+    const ASN1_UINT64_TEST *test = &kAsn1Uint64Tests[i];
+    CBS cbs;
+    uint64_t value;
+    CBB cbb;
+    uint8_t *out;
+    size_t len;
+
+    CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len);
+    if (!CBS_get_asn1_uint64(&cbs, &value) ||
+        CBS_len(&cbs) != 0 ||
+        value != test->value) {
+      return 0;
+    }
+
+    if (!CBB_init(&cbb, 0)) {
+      return 0;
+    }
+    if (!CBB_add_asn1_uint64(&cbb, test->value) ||
+        !CBB_finish(&cbb, &out, &len)) {
+      CBB_cleanup(&cbb);
+      return 0;
+    }
+    if (len != test->encoding_len || memcmp(out, test->encoding, len) != 0) {
+      free(out);
+      return 0;
+    }
+    free(out);
+  }
+
+  for (i = 0;
+       i < sizeof(kAsn1InvalidUint64Tests) / sizeof(kAsn1InvalidUint64Tests[0]);
+       i++) {
+    const ASN1_INVALID_UINT64_TEST *test = &kAsn1InvalidUint64Tests[i];
+    CBS cbs;
+    uint64_t value;
+
+    CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len);
+    if (CBS_get_asn1_uint64(&cbs, &value)) {
+      return 0;
+    }
+  }
+
+  return 1;
+}
+
 int main(void) {
   CRYPTO_library_init();
 
@@ -457,7 +643,9 @@
       !test_cbb_misuse() ||
       !test_cbb_prefixed() ||
       !test_cbb_asn1() ||
-      !test_ber_convert()) {
+      !test_ber_convert() ||
+      !test_asn1_uint64() ||
+      !test_get_optional_asn1_bool()) {
     return 1;
   }
 
diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c
index 6767b9d..f8e1070 100644
--- a/crypto/bytestring/cbb.c
+++ b/crypto/bytestring/cbb.c
@@ -336,3 +336,39 @@
 
   return cbb_buffer_add_u(cbb->base, value, 3);
 }
+
+int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) {
+  CBB child;
+  size_t i;
+  int started = 0;
+
+  if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) {
+    return 0;
+  }
+
+  for (i = 0; i < 8; i++) {
+    uint8_t byte = (value >> 8*(7-i)) & 0xff;
+    if (!started) {
+      if (byte == 0) {
+        /* Don't encode leading zeros. */
+        continue;
+      }
+      /* If the high bit is set, add a padding byte to make it
+       * unsigned. */
+      if ((byte & 0x80) && !CBB_add_u8(&child, 0)) {
+        return 0;
+      }
+      started = 1;
+    }
+    if (!CBB_add_u8(&child, byte)) {
+      return 0;
+    }
+  }
+
+  /* 0 is encoded as a single 0, not the empty string. */
+  if (!started && !CBB_add_u8(&child, 0)) {
+    return 0;
+  }
+
+  return CBB_flush(cbb);
+}
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
index 07cc126..b417716 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -284,7 +284,12 @@
   data = CBS_data(&bytes);
   len = CBS_len(&bytes);
 
-  if (len > 0 && (data[0] & 0x80) != 0) {
+  if (len == 0) {
+    /* An INTEGER is encoded with at least one octet. */
+    return 0;
+  }
+
+  if ((data[0] & 0x80) != 0) {
     /* negative number */
     return 0;
   }
@@ -300,3 +305,84 @@
 
   return 1;
 }
+
+int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
+  if (CBS_peek_asn1_tag(cbs, tag)) {
+    if (!CBS_get_asn1(cbs, out, tag)) {
+      return 0;
+    }
+    *out_present = 1;
+  } else {
+    *out_present = 0;
+  }
+  return 1;
+}
+
+int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
+                                       unsigned tag) {
+  CBS child;
+  int present;
+  if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
+    return 0;
+  }
+  if (present) {
+    if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
+        CBS_len(&child) != 0) {
+      return 0;
+    }
+  } else {
+    CBS_init(out, NULL, 0);
+  }
+  if (out_present) {
+    *out_present = present;
+  }
+  return 1;
+}
+
+int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag,
+                                 uint64_t default_value) {
+  CBS child;
+  int present;
+  if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
+    return 0;
+  }
+  if (present) {
+    if (!CBS_get_asn1_uint64(&child, out) ||
+        CBS_len(&child) != 0) {
+      return 0;
+    }
+  } else {
+    *out = default_value;
+  }
+  return 1;
+}
+
+int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
+                               int default_value) {
+  CBS child, child2;
+  int present;
+  if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
+    return 0;
+  }
+  if (present) {
+    uint8_t boolean;
+
+    if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
+        CBS_len(&child2) != 1 ||
+        CBS_len(&child) != 0) {
+      return 0;
+    }
+
+    boolean = CBS_data(&child2)[0];
+    if (boolean == 0) {
+      *out = 0;
+    } else if (boolean == 0xff) {
+      *out = 1;
+    } else {
+      return 0;
+    }
+  } else {
+    *out = default_value;
+  }
+  return 1;
+}
diff --git a/crypto/err/err.c b/crypto/err/err.c
index 3c5ea99..d0425d8 100644
--- a/crypto/err/err.c
+++ b/crypto/err/err.c
@@ -645,7 +645,6 @@
     "PKCS7 routines",                             /* ERR_LIB_PKCS7 */
     "PKCS8 routines",                             /* ERR_LIB_PKCS8 */
     "X509 V3 routines",                           /* ERR_LIB_X509V3 */
-    "PKCS12 routines",                            /* ERR_LIB_PKCS12 */
     "random number generator",                    /* ERR_LIB_RAND */
     "ENGINE routines",                            /* ERR_LIB_ENGINE */
     "OCSP routines",                              /* ERR_LIB_OCSP */
diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt
index 43e351a..dc1734c 100644
--- a/crypto/evp/CMakeLists.txt
+++ b/crypto/evp/CMakeLists.txt
@@ -23,9 +23,9 @@
 
 
 add_executable(
-	example_sign
+	evp_test
 
-	example_sign.c
+	evp_test.c
 )
 
-target_link_libraries(example_sign crypto)
+target_link_libraries(evp_test crypto)
diff --git a/crypto/evp/asn1.c b/crypto/evp/asn1.c
index 50bdb06..27ae017 100644
--- a/crypto/evp/asn1.c
+++ b/crypto/evp/asn1.c
@@ -128,9 +128,6 @@
   } else if (sk_ASN1_TYPE_num(inkey) == 4) {
     keytype = EVP_PKEY_EC;
   } else if (sk_ASN1_TYPE_num(inkey) == 3) {
-    OPENSSL_PUT_ERROR(EVP, d2i_AutoPrivateKey, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
-    return 0;
-
     /* This seems to be PKCS8, not traditional format */
     PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len);
     EVP_PKEY *ret;
diff --git a/crypto/evp/digestsign.c b/crypto/evp/digestsign.c
index 08968ed..c86b805 100644
--- a/crypto/evp/digestsign.c
+++ b/crypto/evp/digestsign.c
@@ -168,22 +168,15 @@
     if (has_signctx || !r) {
       return r;
     }
-    if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen) <= 0) {
-      return 0;
-    }
+    return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen);
   } else {
     if (has_signctx) {
-      if (ctx->pctx->pmeth->signctx(ctx->pctx, out_sig, out_sig_len, ctx) <= 0) {
-        return 0;
-      }
+      return ctx->pctx->pmeth->signctx(ctx->pctx, out_sig, out_sig_len, ctx);
     } else {
       size_t s = EVP_MD_size(ctx->digest);
-      if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s) <= 0) {
-        return 0;
-      }
+      return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s);
     }
   }
-  return 1;
 }
 
 int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
@@ -196,7 +189,7 @@
 
   EVP_MD_CTX_init(&tmp_ctx);
   if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) {
-    return -1;
+    return 0;
   }
   if (has_verifyctx) {
     r = tmp_ctx.pctx->pmeth->verifyctx(tmp_ctx.pctx, sig, sig_len, &tmp_ctx);
diff --git a/crypto/evp/example_sign.c b/crypto/evp/evp_test.c
similarity index 65%
rename from crypto/evp/example_sign.c
rename to crypto/evp/evp_test.c
index 42a19ec..670df37 100644
--- a/crypto/evp/example_sign.c
+++ b/crypto/evp/evp_test.c
@@ -155,6 +155,80 @@
     0x8c, 0x16,
 };
 
+/* kExampleRSAKeyPKCS8 is kExampleRSAKeyDER encoded in a PKCS #8
+ * PrivateKeyInfo. */
+static const uint8_t kExampleRSAKeyPKCS8[] = {
+    0x30, 0x82, 0x02, 0x76, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+    0x02, 0x60, 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
+    0x00, 0xf8, 0xb8, 0x6c, 0x83, 0xb4, 0xbc, 0xd9, 0xa8, 0x57, 0xc0, 0xa5,
+    0xb4, 0x59, 0x76, 0x8c, 0x54, 0x1d, 0x79, 0xeb, 0x22, 0x52, 0x04, 0x7e,
+    0xd3, 0x37, 0xeb, 0x41, 0xfd, 0x83, 0xf9, 0xf0, 0xa6, 0x85, 0x15, 0x34,
+    0x75, 0x71, 0x5a, 0x84, 0xa8, 0x3c, 0xd2, 0xef, 0x5a, 0x4e, 0xd3, 0xde,
+    0x97, 0x8a, 0xdd, 0xff, 0xbb, 0xcf, 0x0a, 0xaa, 0x86, 0x92, 0xbe, 0xb8,
+    0x50, 0xe4, 0xcd, 0x6f, 0x80, 0x33, 0x30, 0x76, 0x13, 0x8f, 0xca, 0x7b,
+    0xdc, 0xec, 0x5a, 0xca, 0x63, 0xc7, 0x03, 0x25, 0xef, 0xa8, 0x8a, 0x83,
+    0x58, 0x76, 0x20, 0xfa, 0x16, 0x77, 0xd7, 0x79, 0x92, 0x63, 0x01, 0x48,
+    0x1a, 0xd8, 0x7b, 0x67, 0xf1, 0x52, 0x55, 0x49, 0x4e, 0xd6, 0x6e, 0x4a,
+    0x5c, 0xd7, 0x7a, 0x37, 0x36, 0x0c, 0xde, 0xdd, 0x8f, 0x44, 0xe8, 0xc2,
+    0xa7, 0x2c, 0x2b, 0xb5, 0xaf, 0x64, 0x4b, 0x61, 0x07, 0x02, 0x03, 0x01,
+    0x00, 0x01, 0x02, 0x81, 0x80, 0x74, 0x88, 0x64, 0x3f, 0x69, 0x45, 0x3a,
+    0x6d, 0xc7, 0x7f, 0xb9, 0xa3, 0xc0, 0x6e, 0xec, 0xdc, 0xd4, 0x5a, 0xb5,
+    0x32, 0x85, 0x5f, 0x19, 0xd4, 0xf8, 0xd4, 0x3f, 0x3c, 0xfa, 0xc2, 0xf6,
+    0x5f, 0xee, 0xe6, 0xba, 0x87, 0x74, 0x2e, 0xc7, 0x0c, 0xd4, 0x42, 0xb8,
+    0x66, 0x85, 0x9c, 0x7b, 0x24, 0x61, 0xaa, 0x16, 0x11, 0xf6, 0xb5, 0xb6,
+    0xa4, 0x0a, 0xc9, 0x55, 0x2e, 0x81, 0xa5, 0x47, 0x61, 0xcb, 0x25, 0x8f,
+    0xc2, 0x15, 0x7b, 0x0e, 0x7c, 0x36, 0x9f, 0x3a, 0xda, 0x58, 0x86, 0x1c,
+    0x5b, 0x83, 0x79, 0xe6, 0x2b, 0xcc, 0xe6, 0xfa, 0x2c, 0x61, 0xf2, 0x78,
+    0x80, 0x1b, 0xe2, 0xf3, 0x9d, 0x39, 0x2b, 0x65, 0x57, 0x91, 0x3d, 0x71,
+    0x99, 0x73, 0xa5, 0xc2, 0x79, 0x20, 0x8c, 0x07, 0x4f, 0xe5, 0xb4, 0x60,
+    0x1f, 0x99, 0xa2, 0xb1, 0x4f, 0x0c, 0xef, 0xbc, 0x59, 0x53, 0x00, 0x7d,
+    0xb1, 0x02, 0x41, 0x00, 0xfc, 0x7e, 0x23, 0x65, 0x70, 0xf8, 0xce, 0xd3,
+    0x40, 0x41, 0x80, 0x6a, 0x1d, 0x01, 0xd6, 0x01, 0xff, 0xb6, 0x1b, 0x3d,
+    0x3d, 0x59, 0x09, 0x33, 0x79, 0xc0, 0x4f, 0xde, 0x96, 0x27, 0x4b, 0x18,
+    0xc6, 0xd9, 0x78, 0xf1, 0xf4, 0x35, 0x46, 0xe9, 0x7c, 0x42, 0x7a, 0x5d,
+    0x9f, 0xef, 0x54, 0xb8, 0xf7, 0x9f, 0xc4, 0x33, 0x6c, 0xf3, 0x8c, 0x32,
+    0x46, 0x87, 0x67, 0x30, 0x7b, 0xa7, 0xac, 0xe3, 0x02, 0x41, 0x00, 0xfc,
+    0x2c, 0xdf, 0x0c, 0x0d, 0x88, 0xf5, 0xb1, 0x92, 0xa8, 0x93, 0x47, 0x63,
+    0x55, 0xf5, 0xca, 0x58, 0x43, 0xba, 0x1c, 0xe5, 0x9e, 0xb6, 0x95, 0x05,
+    0xcd, 0xb5, 0x82, 0xdf, 0xeb, 0x04, 0x53, 0x9d, 0xbd, 0xc2, 0x38, 0x16,
+    0xb3, 0x62, 0xdd, 0xa1, 0x46, 0xdb, 0x6d, 0x97, 0x93, 0x9f, 0x8a, 0xc3,
+    0x9b, 0x64, 0x7e, 0x42, 0xe3, 0x32, 0x57, 0x19, 0x1b, 0xd5, 0x6e, 0x85,
+    0xfa, 0xb8, 0x8d, 0x02, 0x41, 0x00, 0xbc, 0x3d, 0xde, 0x6d, 0xd6, 0x97,
+    0xe8, 0xba, 0x9e, 0x81, 0x37, 0x17, 0xe5, 0xa0, 0x64, 0xc9, 0x00, 0xb7,
+    0xe7, 0xfe, 0xf4, 0x29, 0xd9, 0x2e, 0x43, 0x6b, 0x19, 0x20, 0xbd, 0x99,
+    0x75, 0xe7, 0x76, 0xf8, 0xd3, 0xae, 0xaf, 0x7e, 0xb8, 0xeb, 0x81, 0xf4,
+    0x9d, 0xfe, 0x07, 0x2b, 0x0b, 0x63, 0x0b, 0x5a, 0x55, 0x90, 0x71, 0x7d,
+    0xf1, 0xdb, 0xd9, 0xb1, 0x41, 0x41, 0x68, 0x2f, 0x4e, 0x39, 0x02, 0x40,
+    0x5a, 0x34, 0x66, 0xd8, 0xf5, 0xe2, 0x7f, 0x18, 0xb5, 0x00, 0x6e, 0x26,
+    0x84, 0x27, 0x14, 0x93, 0xfb, 0xfc, 0xc6, 0x0f, 0x5e, 0x27, 0xe6, 0xe1,
+    0xe9, 0xc0, 0x8a, 0xe4, 0x34, 0xda, 0xe9, 0xa2, 0x4b, 0x73, 0xbc, 0x8c,
+    0xb9, 0xba, 0x13, 0x6c, 0x7a, 0x2b, 0x51, 0x84, 0xa3, 0x4a, 0xe0, 0x30,
+    0x10, 0x06, 0x7e, 0xed, 0x17, 0x5a, 0x14, 0x00, 0xc9, 0xef, 0x85, 0xea,
+    0x52, 0x2c, 0xbc, 0x65, 0x02, 0x40, 0x51, 0xe3, 0xf2, 0x83, 0x19, 0x9b,
+    0xc4, 0x1e, 0x2f, 0x50, 0x3d, 0xdf, 0x5a, 0xa2, 0x18, 0xca, 0x5f, 0x2e,
+    0x49, 0xaf, 0x6f, 0xcc, 0xfa, 0x65, 0x77, 0x94, 0xb5, 0xa1, 0x0a, 0xa9,
+    0xd1, 0x8a, 0x39, 0x37, 0xf4, 0x0b, 0xa0, 0xd7, 0x82, 0x27, 0x5e, 0xae,
+    0x17, 0x17, 0xa1, 0x1e, 0x54, 0x34, 0xbf, 0x6e, 0xc4, 0x8e, 0x99, 0x5d,
+    0x08, 0xf1, 0x2d, 0x86, 0x9d, 0xa5, 0x20, 0x1b, 0xe5, 0xdf,
+};
+
+/* kExampleECKeyDER is a sample EC private key encoded as an ECPrivateKey
+ * structure. */
+static const uint8_t kExampleECKeyDER[] = {
+    0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x07, 0x0f, 0x08, 0x72, 0x7a,
+    0xd4, 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9, 0x4d, 0x89, 0x68, 0x77, 0x08,
+    0xb5, 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e, 0xe8, 0xd1, 0xc9, 0xce, 0x0a,
+    0x8b, 0xb4, 0x6a, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+    0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xe6, 0x2b, 0x69,
+    0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, 0x0d, 0x94, 0x8a, 0x4c,
+    0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9,
+    0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18,
+    0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16,
+    0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22,
+    0xc1,
+};
+
 static EVP_PKEY *load_example_rsa_key(void) {
   EVP_PKEY *ret = NULL;
   const uint8_t *derp = kExampleRSAKeyDER;
@@ -184,7 +258,7 @@
   return ret;
 }
 
-static int example_EVP_DigestSignInit(void) {
+static int test_EVP_DigestSignInit(void) {
   int ret = 0;
   EVP_PKEY *pkey = NULL;
   uint8_t *sig = NULL;
@@ -196,12 +270,12 @@
 
   pkey = load_example_rsa_key();
   if (pkey == NULL ||
-      EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 ||
-      EVP_DigestSignUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1) {
+      !EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) ||
+      !EVP_DigestSignUpdate(&md_ctx, kMsg, sizeof(kMsg))) {
     goto out;
   }
   /* Determine the size of the signature. */
-  if (EVP_DigestSignFinal(&md_ctx, NULL, &sig_len) != 1) {
+  if (!EVP_DigestSignFinal(&md_ctx, NULL, &sig_len)) {
     goto out;
   }
   /* Sanity check for testing. */
@@ -211,14 +285,14 @@
   }
 
   sig = malloc(sig_len);
-  if (sig == NULL || EVP_DigestSignFinal(&md_ctx, sig, &sig_len) != 1) {
+  if (sig == NULL || !EVP_DigestSignFinal(&md_ctx, sig, &sig_len)) {
     goto out;
   }
 
   /* Ensure that the signature round-trips. */
-  if (EVP_DigestVerifyInit(&md_ctx_verify, NULL, EVP_sha256(), NULL, pkey) != 1 ||
-      EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) != 1 ||
-      EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len) != 1) {
+  if (!EVP_DigestVerifyInit(&md_ctx_verify, NULL, EVP_sha256(), NULL, pkey) ||
+      !EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) ||
+      !EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len)) {
     goto out;
   }
 
@@ -241,7 +315,7 @@
   return ret;
 }
 
-static int example_EVP_DigestVerifyInit(void) {
+static int test_EVP_DigestVerifyInit(void) {
   int ret = 0;
   EVP_PKEY *pkey = NULL;
   EVP_MD_CTX md_ctx;
@@ -250,9 +324,9 @@
 
   pkey = load_example_rsa_key();
   if (pkey == NULL ||
-      EVP_DigestVerifyInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 ||
-      EVP_DigestVerifyUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1 ||
-      EVP_DigestVerifyFinal(&md_ctx, kSignature, sizeof(kSignature)) != 1) {
+      !EVP_DigestVerifyInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) ||
+      !EVP_DigestVerifyUpdate(&md_ctx, kMsg, sizeof(kMsg)) ||
+      !EVP_DigestVerifyFinal(&md_ctx, kSignature, sizeof(kSignature))) {
     goto out;
   }
   ret = 1;
@@ -282,7 +356,7 @@
 
   EVP_MD_CTX_init(&md_ctx_verify);
 
-  if (EVP_DigestSignUpdate(md_ctx, kMsg, sizeof(kMsg)) != 1) {
+  if (!EVP_DigestSignUpdate(md_ctx, kMsg, sizeof(kMsg))) {
     goto out;
   }
 
@@ -293,7 +367,7 @@
   }
 
   /* Determine the size of the signature. */
-  if (EVP_DigestSignFinal(md_ctx, NULL, &sig_len) != 1) {
+  if (!EVP_DigestSignFinal(md_ctx, NULL, &sig_len)) {
     goto out;
   }
   /* Sanity check for testing. */
@@ -303,14 +377,14 @@
   }
 
   sig = malloc(sig_len);
-  if (sig == NULL || EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) {
+  if (sig == NULL || !EVP_DigestSignFinal(md_ctx, sig, &sig_len)) {
     goto out;
   }
 
   /* Ensure that the signature round-trips. */
-  if (EVP_DigestVerifyInitFromAlgorithm(&md_ctx_verify, algor, pkey) != 1 ||
-      EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) != 1 ||
-      EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len) != 1) {
+  if (!EVP_DigestVerifyInitFromAlgorithm(&md_ctx_verify, algor, pkey) ||
+      !EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) ||
+      !EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len)) {
     goto out;
   }
 
@@ -342,7 +416,7 @@
   }
 
   /* Test a simple AlgorithmIdentifier. */
-  if (EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) != 1 ||
+  if (!EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) ||
       !test_algorithm_roundtrip(&md_ctx, pkey)) {
     fprintf(stderr, "RSA with SHA-256 failed\n");
     goto out;
@@ -352,7 +426,7 @@
   EVP_MD_CTX_init(&md_ctx);
 
   /* Test RSA-PSS with custom parameters. */
-  if (EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) != 1 ||
+  if (!EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) ||
       EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1 ||
       EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha512()) != 1 ||
       !test_algorithm_roundtrip(&md_ctx, pkey)) {
@@ -375,7 +449,7 @@
   return ret;
 }
 
-static int example_EVP_DigestVerifyInitFromAlgorithm(void) {
+static int test_EVP_DigestVerifyInitFromAlgorithm(void) {
   int ret = 0;
   CBS cert, cert_body, tbs_cert, algorithm, signature;
   uint8_t padding;
@@ -412,11 +486,11 @@
 
   pkey = load_example_rsa_key();
   if (pkey == NULL ||
-      EVP_DigestVerifyInitFromAlgorithm(&md_ctx, algor, pkey) != 1||
-      EVP_DigestVerifyUpdate(&md_ctx, CBS_data(&tbs_cert),
-                             CBS_len(&tbs_cert)) != 1 ||
-      EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature),
-                            CBS_len(&signature)) != 1) {
+      !EVP_DigestVerifyInitFromAlgorithm(&md_ctx, algor, pkey) ||
+      !EVP_DigestVerifyUpdate(&md_ctx, CBS_data(&tbs_cert),
+                              CBS_len(&tbs_cert)) ||
+      !EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature),
+                             CBS_len(&signature))) {
     goto out;
   }
   ret = 1;
@@ -434,16 +508,47 @@
   return ret;
 }
 
+static int test_d2i_AutoPrivateKey(const uint8_t *input, size_t input_len,
+                                   int expected_id) {
+  int ret = 0;
+  const uint8_t *p;
+  EVP_PKEY *pkey = NULL;
+
+  p = input;
+  pkey = d2i_AutoPrivateKey(NULL, &p, input_len);
+  if (pkey == NULL || p != input + input_len) {
+    fprintf(stderr, "d2i_AutoPrivateKey failed\n");
+    goto done;
+  }
+
+  if (EVP_PKEY_id(pkey) != expected_id) {
+    fprintf(stderr, "Did not decode expected type\n");
+    goto done;
+  }
+
+  ret = 1;
+
+done:
+  if (!ret) {
+    BIO_print_errors_fp(stderr);
+  }
+
+  if (pkey != NULL) {
+    EVP_PKEY_free(pkey);
+  }
+  return ret;
+}
+
 int main(void) {
   CRYPTO_library_init();
   ERR_load_crypto_strings();
 
-  if (!example_EVP_DigestSignInit()) {
+  if (!test_EVP_DigestSignInit()) {
     fprintf(stderr, "EVP_DigestSignInit failed\n");
     return 1;
   }
 
-  if (!example_EVP_DigestVerifyInit()) {
+  if (!test_EVP_DigestVerifyInit()) {
     fprintf(stderr, "EVP_DigestVerifyInit failed\n");
     return 1;
   }
@@ -453,11 +558,29 @@
     return 1;
   }
 
-  if (!example_EVP_DigestVerifyInitFromAlgorithm()) {
+  if (!test_EVP_DigestVerifyInitFromAlgorithm()) {
     fprintf(stderr, "EVP_DigestVerifyInitFromAlgorithm failed\n");
     return 1;
   }
 
+  if (!test_d2i_AutoPrivateKey(kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER),
+                               EVP_PKEY_RSA)) {
+    fprintf(stderr, "d2i_AutoPrivateKey(kExampleRSAKeyDER) failed\n");
+    return 1;
+  }
+
+  if (!test_d2i_AutoPrivateKey(kExampleRSAKeyPKCS8, sizeof(kExampleRSAKeyPKCS8),
+                               EVP_PKEY_RSA)) {
+    fprintf(stderr, "d2i_AutoPrivateKey(kExampleRSAKeyPKCS8) failed\n");
+    return 1;
+  }
+
+  if (!test_d2i_AutoPrivateKey(kExampleECKeyDER, sizeof(kExampleECKeyDER),
+                               EVP_PKEY_EC)) {
+    fprintf(stderr, "d2i_AutoPrivateKey(kExampleECKeyDER) failed\n");
+    return 1;
+  }
+
   printf("PASS\n");
   return 0;
 }
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index d92c9e5..0e9dfb2 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -65,13 +65,11 @@
 
 
 /* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */
-#define ASN1_PKEY_ALIAS 0x1
-#define ASN1_PKEY_DYNAMIC 0x2
 
 /* ASN1_PKEY_SIGPARAM_NULL controls whether the default behavior of
  * EVP_DigestSignAlgorithm writes an explicit NULL parameter in the
  * AlgorithmIdentifier. */
-#define ASN1_PKEY_SIGPARAM_NULL 0x4
+#define ASN1_PKEY_SIGPARAM_NULL 0x1
 
 /* evp_digest_sign_algorithm_result_t is the return value of the
  * digest_sign_algorithm function in EVP_PKEY_ASN1_METHOD. */
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index 40012b3..179d96b 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -717,9 +717,3 @@
   rsa_digest_verify_init_from_algorithm,
   rsa_digest_sign_algorithm,
 };
-
-const EVP_PKEY_ASN1_METHOD rsa_asn1_meth_2 = {
-  EVP_PKEY_RSA2,
-  EVP_PKEY_RSA,
-  ASN1_PKEY_ALIAS,
-};
diff --git a/crypto/evp/sign.c b/crypto/evp/sign.c
index c32e5ce..1faf7c6 100644
--- a/crypto/evp/sign.c
+++ b/crypto/evp/sign.c
@@ -91,12 +91,6 @@
   }
   EVP_MD_CTX_cleanup(&tmp_ctx);
 
-/* TODO(fork): this used to be used only with SHA-family hashes. Now we've
- * removed the flag completely. Why was it added for just those hashes? */
-#if 0
-    if (ctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) {
-#endif
-
   pkctx = EVP_PKEY_CTX_new(pkey, NULL);
   if (!pkctx || EVP_PKEY_sign_init(pkctx) <= 0 ||
       EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) <= 0 ||
@@ -142,11 +136,6 @@
   }
   EVP_MD_CTX_cleanup(&tmp_ctx);
 
-/* TODO(fork): this used to be used only with SHA-family hashes. Now we've
- * removed the flag completely. Why was it added for just those hashes? */
-#if 0
-    if (ctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) {
-#endif
   pkctx = EVP_PKEY_CTX_new(pkey, NULL);
   if (!pkctx ||
       EVP_PKEY_verify_init(pkctx) <= 0 ||
diff --git a/crypto/perlasm/x86asm.pl b/crypto/perlasm/x86asm.pl
index bab15e7..3c7be40 100644
--- a/crypto/perlasm/x86asm.pl
+++ b/crypto/perlasm/x86asm.pl
@@ -235,9 +235,9 @@
 
 sub ::asm_finish
 {   &file_end();
-    print "#if defined(__i386__)\n";
+    print "#if defined(__i386__)\n" unless $win32;
     print @out;
-    print "#endif\n";
+    print "#endif\n" unless $win32;
 }
 
 sub ::asm_init
diff --git a/crypto/perlasm/x86masm.pl b/crypto/perlasm/x86masm.pl
index 1741342..a491529 100644
--- a/crypto/perlasm/x86masm.pl
+++ b/crypto/perlasm/x86masm.pl
@@ -82,7 +82,7 @@
 IF \@Version LT 800
 ECHO MASM version 8.00 or later is strongly recommended.
 ENDIF
-.486
+.686
 .MODEL	FLAT
 OPTION	DOTNAME
 IF \@Version LT 800
@@ -166,7 +166,10 @@
 {   push(@out,("DW\t").join(',',@_)."\n");	}
 
 sub ::data_word
-{   push(@out,("DD\t").join(',',@_)."\n");	}
+{   # MASM can't handle long lines, so emit one word at a time.
+    foreach(@_)
+    {	push(@out,"DD\t$_\n");	}
+}
 
 sub ::align
 {   push(@out,"ALIGN\t$_[0]\n");	}
diff --git a/crypto/perlasm/x86nasm.pl b/crypto/perlasm/x86nasm.pl
index 5d92f60..f8332bb 100644
--- a/crypto/perlasm/x86nasm.pl
+++ b/crypto/perlasm/x86nasm.pl
@@ -83,7 +83,15 @@
 %ifidn __OUTPUT_FORMAT__,obj
 section	code	use32 class=code align=64
 %elifidn __OUTPUT_FORMAT__,win32
+%ifdef __YASM_VERSION_ID__
+%if __YASM_VERSION_ID__ < 01010000h
+%error yasm version 1.1.0 or later needed.
+%endif
+; Yasm automatically includes @feat.00 and complains about redefining it.
+; https://www.tortall.net/projects/yasm/manual/html/objfmt-win32-safeseh.html
+%else
 \$\@feat.00 equ 1
+%endif
 section	.text	code align=64
 %else
 section	.text	code
diff --git a/crypto/rand/windows.c b/crypto/rand/windows.c
index 967dd9b..ed6e5e9 100644
--- a/crypto/rand/windows.c
+++ b/crypto/rand/windows.c
@@ -14,57 +14,36 @@
 
 #include <openssl/rand.h>
 
-#include <openssl/thread.h>
-
-
 #if defined(OPENSSL_WINDOWS)
 
+#include <limits.h>
 #include <stdlib.h>
 #include <Windows.h>
-#include <Wincrypt.h>
 
-static char global_provider_init;
-static HCRYPTPROV global_provider;
+/* #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036.  See the
+ * "Community Additions" comment on MSDN here:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */
+#define SystemFunction036 NTAPI SystemFunction036
+#include <NTSecAPI.h>
+#undef SystemFunction036
+
 
 void RAND_cleanup(void) {
-  CRYPTO_w_lock(CRYPTO_LOCK_RAND);
-  CryptReleaseContext(global_provider, 0);
-  global_provider_init = 0;
-  CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
 }
 
 int RAND_bytes(uint8_t *out, size_t requested) {
-  HCRYPTPROV provider = 0;
-  int ok;
-
-  CRYPTO_r_lock(CRYPTO_LOCK_RAND);
-  if (!global_provider_init) {
-    CRYPTO_r_unlock(CRYPTO_LOCK_RAND);
-    CRYPTO_w_lock(CRYPTO_LOCK_RAND);
-    if (!global_provider_init) {
-      if (CryptAcquireContext(&global_provider, NULL, NULL, PROV_RSA_FULL,
-                              CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
-        global_provider_init = 1;
-      }
+  while (requested > 0) {
+    ULONG output_bytes_this_pass = ULONG_MAX;
+    if (requested < output_bytes_this_pass) {
+      output_bytes_this_pass = requested;
     }
-    CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
-    CRYPTO_r_lock(CRYPTO_LOCK_RAND);
+    if (RtlGenRandom(out, output_bytes_this_pass) == FALSE) {
+      abort();
+      return 0;
+    }
+    requested -= output_bytes_this_pass;
+    out += output_bytes_this_pass;
   }
-
-  ok = global_provider_init;
-  provider = global_provider;
-  CRYPTO_r_unlock(CRYPTO_LOCK_RAND);
-
-  if (!ok) {
-    abort();
-    return ok;
-  }
-
-  if (TRUE != CryptGenRandom(provider, requested, out)) {
-    abort();
-    return 0;
-  }
-
   return 1;
 }
 
diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c
index 21785dc..8e64f76 100644
--- a/crypto/x509/x_crl.c
+++ b/crypto/x509/x_crl.c
@@ -64,8 +64,24 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
-#include "../asn1/asn1_locl.h"
+/* Method to handle CRL access.
+ * In general a CRL could be very large (several Mb) and can consume large
+ * amounts of resources if stored in memory by multiple processes.
+ * This method allows general CRL operations to be redirected to more
+ * efficient callbacks: for example a CRL entry database.
+ */
 
+#define X509_CRL_METHOD_DYNAMIC		1
+
+struct x509_crl_method_st
+	{
+	int flags;
+	int (*crl_init)(X509_CRL *crl);
+	int (*crl_free)(X509_CRL *crl);
+	int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret,
+				ASN1_INTEGER *ser, X509_NAME *issuer);
+	int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk);
+	};
 
 static int X509_REVOKED_cmp(const X509_REVOKED **a,
 				const X509_REVOKED **b);
diff --git a/crypto/x509v3/v3nametest.c b/crypto/x509v3/v3nametest.c
index 6a2ea85..b2e9c09 100644
--- a/crypto/x509v3/v3nametest.c
+++ b/crypto/x509v3/v3nametest.c
@@ -53,9 +53,9 @@
  * Hudson (tjh@cryptsoft.com). */
 
 #include <string.h>
-#include <strings.h>
 
 #include <openssl/crypto.h>
+#include <openssl/mem.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
@@ -326,7 +326,7 @@
 	const char *const *pname = names;
 	while (*pname)
 		{
-		int samename = strcasecmp(nameincert, *pname) == 0;
+		int samename = OPENSSL_strcasecmp(nameincert, *pname) == 0;
 		size_t namelen = strlen(*pname);
 		char *name = malloc(namelen);
 		int match, ret;
diff --git a/include/openssl/base.h b/include/openssl/base.h
index 52cb1e9..6207c54 100644
--- a/include/openssl/base.h
+++ b/include/openssl/base.h
@@ -159,7 +159,6 @@
 typedef struct X509_POLICY_TREE_st X509_POLICY_TREE;
 typedef struct X509_algor_st X509_ALGOR;
 typedef struct X509_crl_st X509_CRL;
-typedef struct X509_name_st X509_NAME;
 typedef struct X509_pubkey_st X509_PUBKEY;
 typedef struct bignum_ctx BN_CTX;
 typedef struct bignum_st BIGNUM;
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index acaba8e..d5e6cf9 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -166,6 +166,41 @@
  * in 64 bits. */
 OPENSSL_EXPORT int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out);
 
+/* CBS_get_optional_asn1 gets an optional explicitly-tagged element
+ * from |cbs| tagged with |tag| and sets |*out| to its contents. If
+ * present, it sets |*out_present| to one, otherwise zero. It returns
+ * one on success, whether or not the element was present, and zero on
+ * decode failure. */
+OPENSSL_EXPORT int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present,
+                                         unsigned tag);
+
+/* CBS_get_optional_asn1_octet_string gets an optional
+ * explicitly-tagged OCTET STRING from |cbs|. If present, it sets
+ * |*out| to the string and |*out_present| to one. Otherwise, it sets
+ * |*out| to empty and |*out_present| to zero. |out_present| may be
+ * NULL. It returns one on success, whether or not the element was
+ * present, and zero on decode failure. */
+OPENSSL_EXPORT int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out,
+                                                      int *out_present,
+                                                      unsigned tag);
+
+/* CBS_get_optional_asn1_uint64 gets an optional explicitly-tagged
+ * INTEGER from |cbs|. If present, it sets |*out| to the
+ * value. Otherwise, it sets |*out| to |default_value|. It returns one
+ * on success, whether or not the element was present, and zero on
+ * decode failure. */
+OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out,
+                                                unsigned tag,
+                                                uint64_t default_value);
+
+/* CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from
+ * |cbs|. If present, it sets |*out| to either zero or one, based on the
+ * boolean. Otherwise, it sets |*out| to |default_value|. It returns one on
+ * success, whether or not the element was present, and zero on decode
+ * failure. */
+OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
+                                              int default_value);
+
 
 /* CRYPTO ByteBuilder.
  *
@@ -277,6 +312,10 @@
  * returns one on success and zero otherwise. */
 OPENSSL_EXPORT int CBB_add_u24(CBB *cbb, uint32_t value);
 
+/* CBB_add_asn1_uint64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1|
+ * and writes |value| in its contents. It returns one on success and zero on
+ * error. */
+OPENSSL_EXPORT int CBB_add_asn1_uint64(CBB *cbb, uint64_t value);
 
 #if defined(__cplusplus)
 }  /* extern C */
diff --git a/include/openssl/dtls1.h b/include/openssl/dtls1.h
index 5aef0c4..a9e3ada 100644
--- a/include/openssl/dtls1.h
+++ b/include/openssl/dtls1.h
@@ -72,11 +72,6 @@
 /* Special value for method supporting multiple versions */
 #define DTLS_ANY_VERSION		0x1FFFF
 
-#if 0
-/* this alert description is not specified anywhere... */
-#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE    110
-#endif
-
 /* lengths of messages */
 #define DTLS1_COOKIE_LENGTH                     256
 
@@ -89,11 +84,7 @@
 
 #define DTLS1_CCS_HEADER_LENGTH                  1
 
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
-#define DTLS1_AL_HEADER_LENGTH                   7
-#else
 #define DTLS1_AL_HEADER_LENGTH                   2
-#endif
 
 #ifndef OPENSSL_NO_SSL_INTERN
 
diff --git a/include/openssl/err.h b/include/openssl/err.h
index a7f30c7..b9c48c3 100644
--- a/include/openssl/err.h
+++ b/include/openssl/err.h
@@ -392,7 +392,6 @@
   ERR_LIB_PKCS7,
   ERR_LIB_PKCS8,
   ERR_LIB_X509V3,
-  ERR_LIB_PKCS12,
   ERR_LIB_RAND,
   ERR_LIB_ENGINE,
   ERR_LIB_OCSP,
@@ -426,7 +425,6 @@
 #define ERR_R_PKCS7_LIB ERR_LIB_PKCS7
 #define ERR_R_PKCS8_LIB ERR_LIB_PKCS8
 #define ERR_R_X509V3_LIB ERR_LIB_X509V3
-#define ERR_R_PKCS12_LIB ERR_LIB_PKCS12
 #define ERR_R_RAND_LIB ERR_LIB_RAND
 #define ERR_R_DSO_LIB ERR_LIB_DSO
 #define ERR_R_ENGINE_LIB ERR_LIB_ENGINE
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index e3922a3..1f60145 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -290,10 +290,7 @@
 
 /* EVP_DigestVerifyFinal verifies that |sig_len| bytes of |sig| are a valid
  * signature for the data that has been included by one or more calls to
- * |EVP_DigestVerifyUpdate|.
- *
- * It returns one on success and <= 0 on error. WARNING: this differs from the
- * usual return value convention. */
+ * |EVP_DigestVerifyUpdate|. It returns one on success and zero otherwise. */
 OPENSSL_EXPORT int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
                                          size_t sig_len);
 
@@ -462,8 +459,8 @@
  * space available at |sig|. If sufficient, the signature will be written to
  * |sig| and |*sig_len| updated with the true length.
  *
- * WARNING: Setting |out| to NULL only gives the maximum size of the
- * plaintext. The actual plaintext may be smaller.
+ * WARNING: Setting |sig| to NULL only gives the maximum size of the
+ * signature. The actual signature may be smaller.
  *
  * It returns one on success or zero on error. (Note: this differs from
  * OpenSSL, which can also return negative values to indicate an error. ) */
diff --git a/include/openssl/srtp.h b/include/openssl/srtp.h
index c11608e..860362b 100644
--- a/include/openssl/srtp.h
+++ b/include/openssl/srtp.h
@@ -115,14 +115,15 @@
   Copyright (C) 2011, RTFM, Inc.
 */
 
-#ifndef HEADER_D1_SRTP_H
-#define HEADER_D1_SRTP_H
+#ifndef OPENSSL_HEADER_SRTP_H
+#define OPENSSL_HEADER_SRTP_H
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
-     
+
+/* Constants for SRTP profiles */
 #define SRTP_AES128_CM_SHA1_80 0x0001
 #define SRTP_AES128_CM_SHA1_32 0x0002
 #define SRTP_AES128_F8_SHA1_80 0x0003
@@ -130,32 +131,47 @@
 #define SRTP_NULL_SHA1_80      0x0005
 #define SRTP_NULL_SHA1_32      0x0006
 
-/* SSL_CTX_set_tlsext_use_srtp enables SRTP for all SSL objects
- * created from |ctx|. |profile| contains a colon-separated list of
- * profile names. It returns zero on success and one on failure.
+/* SSL_CTX_set_srtp_profiles enables SRTP for all SSL objects created from
+ * |ctx|. |profile| contains a colon-separated list of profile names. It returns
+ * one on success and zero on failure. */
+OPENSSL_EXPORT int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx,
+                                             const char *profiles);
+
+/* SSL_set_srtp_profiles enables SRTP for |ssl|.  |profile| contains a
+ * colon-separated list of profile names. It returns one on success and zero on
+ * failure. */
+OPENSSL_EXPORT int SSL_set_srtp_profiles(SSL *ctx, const char *profiles);
+
+/* SSL_get_srtp_profiles returns the SRTP profiles supported by |ssl|. */
+OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(
+    SSL *ssl);
+
+/* SSL_get_selected_srtp_profile returns the selected SRTP profile, or NULL if
+ * SRTP was not negotiated. */
+OPENSSL_EXPORT SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
+
+
+/* Deprecated functions */
+
+/* SSL_CTX_set_tlsext_use_srtp calls SSL_CTX_set_srtp_profiles. It returns zero
+ * on success and one on failure.
  *
- * WARNING: this function is dangerous because it breaks the usual
- * return value convention. */
+ * WARNING: this function is dangerous because it breaks the usual return value
+ * convention. Use SSL_CTX_set_srtp_profiles instead. */
 OPENSSL_EXPORT int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx,
                                                const char *profiles);
 
-/* SSL_set_tlsext_use_srtp enables SRTP for |ssl| with a profile list.
- * |profile| contains a colon-separated list of profile names. It
- * returns zero on success and one on failure.
+/* SSL_set_tlsext_use_srtp calls SSL_set_srtp_profiles. It returns zero on
+ * success and one on failure.
  *
- * WARNING: this function is dangerous because it breaks the usual
- * return value convention. */
+ * WARNING: this function is dangerous because it breaks the usual return value
+ * convention. Use SSL_set_srtp_profiles instead. */
 OPENSSL_EXPORT int SSL_set_tlsext_use_srtp(SSL *ctx, const char *profiles);
 
-OPENSSL_EXPORT SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
-
-OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) *
-    SSL_get_srtp_profiles(SSL *ssl);
-OPENSSL_EXPORT SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s);
 
 #ifdef  __cplusplus
-}
+}  /* extern C */
 #endif
 
-#endif
+#endif  /* OPENSSL_HEADER_SRTP_H */
 
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 2168613..31ff5db 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -359,34 +359,8 @@
 	long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void));
 	};
 
-/* Lets make this into an ASN.1 type structure as follows
- * SSL_SESSION_ID ::= SEQUENCE {
- *	version 		INTEGER,	-- structure version number
- *	SSLversion 		INTEGER,	-- SSL version number
- *	Cipher 			OCTET STRING,	-- the 3 byte cipher ID
- *	Session_ID 		OCTET STRING,	-- the Session ID
- *	Master_key 		OCTET STRING,	-- the master key
- *	Key_Arg [ 0 ] IMPLICIT	OCTET STRING,	-- the optional Key argument
- *	Time [ 1 ] EXPLICIT	INTEGER,	-- optional Start Time
- *	Timeout [ 2 ] EXPLICIT	INTEGER,	-- optional Timeout ins seconds
- *	Peer [ 3 ] EXPLICIT	X509,		-- optional Peer Certificate
- *	Session_ID_context [ 4 ] EXPLICIT OCTET STRING,   -- the Session ID context
- *	Verify_result [ 5 ] EXPLICIT INTEGER,   -- X509_V_... code for `Peer'
- *	HostName [ 6 ] EXPLICIT OCTET STRING,   -- optional HostName from servername TLS extension 
- *	PSK_identity_hint [ 7 ] EXPLICIT OCTET STRING, -- optional PSK identity hint
- *	PSK_identity [ 8 ] EXPLICIT OCTET STRING,  -- optional PSK identity
- *	Ticket_lifetime_hint [9] EXPLICIT INTEGER, -- server's lifetime hint for session ticket
- *	Ticket [10]             EXPLICIT OCTET STRING, -- session ticket (clients only)
- *	Compression_meth [11]   EXPLICIT OCTET STRING, -- optional compression method
- *	SRP_username [ 12 ] EXPLICIT OCTET STRING -- optional SRP username
- *	Peer SHA256 [13]        EXPLICIT OCTET STRING, -- optional SHA256 hash of Peer certifiate
- *	original handshake hash [14] EXPLICIT OCTET STRING, -- optional original handshake hash
- *	tlsext_signed_cert_timestamp_list [15] EXPLICIT OCTET STRING, -- optional signed cert timestamp list extension
- *	ocsp_response [16] EXPLICIT OCTET STRING, -- optional saved OCSP response from the server
- *	}
- * Look in ssl/ssl_asn1.c for more details
- * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-).
- */
+/* An SSL_SESSION represents an SSL session that may be resumed in an
+ * abbreviated handshake. */
 struct ssl_session_st
 	{
 	int ssl_version;	/* what ssl version session info is
@@ -458,6 +432,11 @@
 	 * resumption. */
 	unsigned char original_handshake_hash[EVP_MAX_MD_SIZE];
 	unsigned int original_handshake_hash_len;
+
+	/* extended_master_secret is true if the master secret in this session
+	 * was generated using EMS and thus isn't vulnerable to the Triple
+	 * Handshake attack. */
+	char extended_master_secret;
 	};
 
 #endif
@@ -529,9 +508,6 @@
  * the misconception that non-blocking SSL_write() behaves like
  * non-blocking write(): */
 #define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L
-/* Never bother the application with retries if the transport
- * is blocking: */
-#define SSL_MODE_AUTO_RETRY 0x00000004L
 /* Don't attempt to automatically build certificate chain */
 #define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
 /* Save RAM by releasing read and write buffers when they're empty. (SSL3 and
@@ -539,6 +515,10 @@
  * just freed (depending on the context's setting for freelist_max_len). */
 #define SSL_MODE_RELEASE_BUFFERS 0x00000010L
 
+/* The following flags do nothing and are included only to make it easier to
+ * compile code with BoringSSL. */
+#define SSL_MODE_AUTO_RETRY 0
+
 /* Send the current time in the Random fields of the ClientHello and
  * ServerHello records for compatibility with hypothetical implementations
  * that require it.
@@ -1978,18 +1958,52 @@
 OPENSSL_EXPORT int	SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses);
 #endif
 OPENSSL_EXPORT void	SSL_SESSION_free(SSL_SESSION *ses);
-OPENSSL_EXPORT int	i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp);
 OPENSSL_EXPORT int	SSL_set_session(SSL *to, SSL_SESSION *session);
 OPENSSL_EXPORT int	SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c);
 OPENSSL_EXPORT int	SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c);
 OPENSSL_EXPORT int	SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB);
 OPENSSL_EXPORT int	SSL_set_generate_session_id(SSL *, GEN_SESSION_CB);
 OPENSSL_EXPORT int	SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, unsigned int id_len);
-OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp, long length);
 
-#ifdef HEADER_X509_H
+/* SSL_SESSION_to_bytes serializes |in| into a newly allocated buffer
+ * and sets |*out_data| to that buffer and |*out_len| to its
+ * length. The caller takes ownership of the buffer and must call
+ * |OPENSSL_free| when done. It returns one on success and zero on
+ * error. */
+OPENSSL_EXPORT int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data,
+                                        size_t *out_len);
+
+/* SSL_SESSION_to_bytes_for_ticket serializes |in|, but excludes the
+ * session ID which is not necessary in a session ticket. */
+OPENSSL_EXPORT int SSL_SESSION_to_bytes_for_ticket(SSL_SESSION *in,
+                                                   uint8_t **out_data,
+                                                   size_t *out_len);
+
+/* Deprecated: i2d_SSL_SESSION serializes |in| to the bytes pointed to
+ * by |*pp|. On success, it returns the number of bytes written and
+ * advances |*pp| by that many bytes. On failure, it returns -1. If
+ * |pp| is NULL, no bytes are written and only the length is
+ * returned.
+ *
+ * Use SSL_SESSION_to_bytes instead. */
+OPENSSL_EXPORT int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp);
+
+/* d2i_SSL_SESSION deserializes a serialized buffer contained in the
+ * |length| bytes pointed to by |*pp|. It returns the new SSL_SESSION
+ * and advances |*pp| by the number of bytes consumed on success and
+ * NULL on failure. If |a| is NULL, the caller takes ownership of the
+ * new session and must call |SSL_SESSION_free| when done.
+ *
+ * If |a| and |*a| are not NULL, the SSL_SESSION at |*a| is overridden
+ * with the deserialized session rather than allocating a new one. In
+ * addition, |a| is not NULL, but |*a| is, |*a| is set to the new
+ * SSL_SESSION.
+ *
+ * Passing a value other than NULL to |a| is deprecated. */
+OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp,
+                                            long length);
+
 OPENSSL_EXPORT X509 *	SSL_get_peer_certificate(const SSL *s);
-#endif
 
 OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s);
 
@@ -2461,6 +2475,12 @@
 #define SSL_F_ssl3_cert_verify_hash 284
 #define SSL_F_ssl_ctx_log_rsa_client_key_exchange 285
 #define SSL_F_ssl_ctx_log_master_secret 286
+#define SSL_F_d2i_SSL_SESSION 287
+#define SSL_F_i2d_SSL_SESSION 288
+#define SSL_F_d2i_SSL_SESSION_get_octet_string 289
+#define SSL_F_d2i_SSL_SESSION_get_string 290
+#define SSL_F_ssl3_send_new_session_ticket 291
+#define SSL_F_SSL_SESSION_to_bytes_full 292
 #define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 100
 #define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 101
 #define SSL_R_INVALID_NULL_CMD_NAME 102
@@ -2774,6 +2794,7 @@
 #define SSL_R_UNPROCESSED_HANDSHAKE_DATA 440
 #define SSL_R_HANDSHAKE_RECORD_BEFORE_CCS 441
 #define SSL_R_SESSION_MAY_NOT_BE_CREATED 442
+#define SSL_R_INVALID_SSL_SESSION 443
 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index 2a201aa..3d62763 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -485,6 +485,15 @@
 		 * this extension to the client. */
 		uint16_t *peer_ellipticcurvelist;
 		size_t peer_ellipticcurvelist_length;
+
+		/* extended_master_secret indicates whether the extended master
+		 * secret computation is used in this handshake. Note that this
+		 * is different from whether it was used for the current
+		 * session. If this is a resumption handshake then EMS might be
+		 * negotiated in the client and server hello messages, but it
+		 * doesn't matter if the session that's being resumed didn't
+		 * use it to create the master secret initially. */
+		char extended_master_secret;
 		} tmp;
 
         /* Connection binding to prevent renegotiation attacks */
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 08ad8e8..d2682dd 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -240,6 +240,9 @@
  */
 #define TLSEXT_TYPE_padding	21
 
+/* https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 */
+#define TLSEXT_TYPE_extended_master_secret	23
+
 /* ExtensionType value from RFC4507 */
 #define TLSEXT_TYPE_session_ticket		35
 
@@ -704,6 +707,8 @@
 #define TLS_MD_IV_BLOCK_CONST_SIZE		8
 #define TLS_MD_MASTER_SECRET_CONST		"master secret"
 #define TLS_MD_MASTER_SECRET_CONST_SIZE		13
+#define TLS_MD_EXTENDED_MASTER_SECRET_CONST	"extended master secret"
+#define TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE	22
 
 
 /* TLS Session Ticket extension struct */
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 398bec7..9766f74 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -143,7 +143,7 @@
 DECLARE_ASN1_SET_OF(X509_NAME_ENTRY)
 
 /* we always keep X509_NAMEs in 2 forms. */
-struct X509_name_st
+typedef struct X509_name_st
 	{
 	STACK_OF(X509_NAME_ENTRY) *entries;
 	int modified;	/* true if 'bytes' needs to be built */
@@ -155,7 +155,7 @@
 /*	unsigned long hash; Keep the hash around for lookups */
 	unsigned char *canon_enc;
 	int canon_enclen;
-	} /* X509_NAME */;
+	} X509_NAME;
 
 DECLARE_STACK_OF(X509_NAME)
 
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 2d944d8..82d4a86 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -229,7 +229,7 @@
 	}
 
 /* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
-int dtls1_do_write(SSL *s, int type)
+int dtls1_do_write(SSL *s, int type, enum should_add_to_finished_hash should_add_to_finished_hash)
 	{
 	int ret;
 	int curr_mtu;
@@ -365,7 +365,8 @@
 			 * message got sent.  but why would this happen? */
 			assert(len == (unsigned int)ret);
 
-			if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
+			if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting &&
+			    should_add_to_finished_hash == add_to_finished_hash)
 				{
 				/* should not be done for 'Hello Request's, but in that case
 				 * we'll ignore the result anyway */
@@ -967,7 +968,7 @@
 		}
 
 	/* SSL3_ST_CW_CHANGE_B */
-	return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
+	return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC, dont_add_to_finished_hash));
 	}
 
 int dtls1_read_failed(SSL *s, int code)
@@ -991,21 +992,6 @@
 		return code;
 		}
 
-#if 0 /* for now, each alert contains only one record number */
-	item = pqueue_peek(state->rcvd_records);
-	if ( item )
-		{
-		/* send an alert immediately for all the missing records */
-		}
-	else
-#endif
-
-#if 0  /* no more alert sending, just retransmit the last set of messages */
-	if ( state->timeout.read_timeouts >= DTLS1_TMO_READ_COUNT)
-		ssl3_send_alert(s,SSL3_AL_WARNING,
-			DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
-#endif
-
 	return dtls1_handle_timeout(s);
 	}
 
@@ -1181,7 +1167,7 @@
 	}
 	
 	ret = dtls1_do_write(s, frag->msg_header.is_ccs ? 
-						 SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
+						 SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE, add_to_finished_hash);
 	
 	/* restore current state */
 	s->enc_write_ctx = saved_state.enc_write_ctx;
diff --git a/ssl/d1_enc.c b/ssl/d1_enc.c
index dec0ea5..11d06cb 100644
--- a/ssl/d1_enc.c
+++ b/ssl/d1_enc.c
@@ -179,10 +179,6 @@
 			enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
 		}
 
-#ifdef KSSL_DEBUG
-	printf("dtls1_enc(%d)\n", send);
-#endif    /* KSSL_DEBUG */
-
 	if ((s->session == NULL) || (ds == NULL) ||
 		(enc == NULL))
 		{
@@ -208,24 +204,6 @@
 			rec->length+=i;
 			}
 
-#ifdef KSSL_DEBUG
-		{
-                unsigned long ui;
-		printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n",
-                        ds,rec->data,rec->input,l);
-		printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n",
-                        ds->buf_len, ds->cipher->key_len,
-                        DES_KEY_SZ, DES_SCHEDULE_SZ,
-                        ds->cipher->iv_len);
-		printf("\t\tIV: ");
-		for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]);
-		printf("\n");
-		printf("\trec->input=");
-		for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]);
-		printf("\n");
-		}
-#endif	/* KSSL_DEBUG */
-
 		if (!send)
 			{
 			if (l == 0 || l%bs != 0)
@@ -234,15 +212,6 @@
 		
 		EVP_Cipher(ds,rec->data,rec->input,l);
 
-#ifdef KSSL_DEBUG
-		{
-                unsigned long i;
-                printf("\trec->data=");
-		for (i=0; i<l; i++)
-                        printf(" %02x", rec->data[i]);  printf("\n");
-                }
-#endif	/* KSSL_DEBUG */
-
 		if ((bs != 1) && !send)
 			return tls1_cbc_remove_padding(s, rec, bs, mac_size);
 		}
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index 96ce496..650d8e7 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -74,8 +74,9 @@
 static void get_current_time(OPENSSL_timeval *t);
 static OPENSSL_timeval* dtls1_get_timeout(SSL *s, OPENSSL_timeval* timeleft);
 static void dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
-static int dtls1_handshake_write(SSL *s);
+static int dtls1_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash);
 int dtls1_listen(SSL *s, struct sockaddr *client);
+static void dtls1_add_to_finished_hash(SSL *s);
 
 SSL3_ENC_METHOD DTLSv1_enc_data={
     	tls1_enc,
@@ -93,7 +94,8 @@
 	SSL_ENC_FLAG_DTLS|SSL_ENC_FLAG_EXPLICIT_IV,
 	DTLS1_HM_HEADER_LENGTH,
 	dtls1_set_handshake_header,
-	dtls1_handshake_write	
+	dtls1_handshake_write,
+	dtls1_add_to_finished_hash,
 	};
 
 SSL3_ENC_METHOD DTLSv1_2_enc_data={
@@ -113,7 +115,8 @@
 		|SSL_ENC_FLAG_SHA256_PRF|SSL_ENC_FLAG_TLS1_2_CIPHERS,
 	DTLS1_HM_HEADER_LENGTH,
 	dtls1_set_handshake_header,
-	dtls1_handshake_write	
+	dtls1_handshake_write,
+	dtls1_add_to_finished_hash,
 	};
 
 int dtls1_new(SSL *s)
@@ -502,7 +505,25 @@
 	dtls1_buffer_message(s, 0);
 	}
 
-static int dtls1_handshake_write(SSL *s)
+static int dtls1_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash)
 	{
-	return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
+	return dtls1_do_write(s, SSL3_RT_HANDSHAKE, should_add_to_finished_hash);
+	}
+
+static void dtls1_add_to_finished_hash(SSL *s)
+	{
+	uint8_t *record = (uint8_t *) &s->init_buf->data[s->init_off];
+	const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+	uint8_t serialised_header[DTLS1_HM_HEADER_LENGTH];
+	uint8_t *p = serialised_header;
+
+	/* Construct the message header as if it were a single fragment. */
+	*p++ = msg_hdr->type;
+	l2n3(msg_hdr->msg_len, p);
+	s2n (msg_hdr->seq, p);
+	l2n3(0, p);
+	l2n3(msg_hdr->msg_len, p);
+	ssl3_finish_mac(s, serialised_header, sizeof(serialised_header));
+	ssl3_finish_mac(s, record + DTLS1_HM_HEADER_LENGTH,
+			s->init_num - DTLS1_HM_HEADER_LENGTH);
 	}
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index e2855b8..0ecbb2e 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -918,14 +918,6 @@
              *  may be fragmented--don't always expect dest_maxlen bytes */
 			if ( rr->length < dest_maxlen)
 				{
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
-				/*
-				 * for normal alerts rr->length is 2, while
-				 * dest_maxlen is 7 if we were to handle this
-				 * non-existing alert...
-				 */
-				FIX ME
-#endif
 				s->rstate=SSL_ST_READ_HEADER;
 				rr->length = 0;
 				goto start;
@@ -984,23 +976,6 @@
 					OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
 					return(-1);
 					}
-
-				if (!(s->mode & SSL_MODE_AUTO_RETRY))
-					{
-					if (s->s3->rbuf.left == 0) /* no read-ahead left? */
-						{
-						BIO *bio;
-						/* In the case where we try to read application data,
-						 * but we trigger an SSL handshake, we return -1 with
-						 * the retry option set.  Otherwise renegotiation may
-						 * cause nasty problems in the blocking world */
-						s->rwstate=SSL_READING;
-						bio=SSL_get_rbio(s);
-						BIO_clear_retry_flags(bio);
-						BIO_set_retry_read(bio);
-						return(-1);
-						}
-					}
 				}
 			}
 		/* we either finished a handshake or ignored the request,
@@ -1038,31 +1013,6 @@
 				s->shutdown |= SSL_RECEIVED_SHUTDOWN;
 				return(0);
 				}
-#if 0
-            /* XXX: this is a possible improvement in the future */
-			/* now check if it's a missing record */
-			if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
-				{
-				unsigned short seq;
-				unsigned int frag_off;
-				unsigned char *p = &(s->d1->alert_fragment[2]);
-
-				n2s(p, seq);
-				n2l3(p, frag_off);
-
-				dtls1_retransmit_message(s,
-										 dtls1_get_queue_priority(frag->msg_header.seq, 0),
-										 frag_off, &found);
-				if ( ! found  && SSL_in_init(s))
-					{
-					/* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */
-					/* requested a message not yet sent, 
-					   send an alert ourselves */
-					ssl3_send_alert(s,SSL3_AL_WARNING,
-						DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
-					}
-				}
-#endif
 			}
 		else if (alert_level == 2) /* fatal */
 			{
@@ -1188,22 +1138,6 @@
 			return(-1);
 			}
 
-		if (!(s->mode & SSL_MODE_AUTO_RETRY))
-			{
-			if (s->s3->rbuf.left == 0) /* no read-ahead left? */
-				{
-				BIO *bio;
-				/* In the case where we try to read application data,
-				 * but we trigger an SSL handshake, we return -1 with
-				 * the retry option set.  Otherwise renegotiation may
-				 * cause nasty problems in the blocking world */
-				s->rwstate=SSL_READING;
-				bio=SSL_get_rbio(s);
-				BIO_clear_retry_flags(bio);
-				BIO_set_retry_read(bio);
-				return(-1);
-				}
-			}
 		goto start;
 		}
 
@@ -1577,24 +1511,6 @@
 	*ptr++ = s->s3->send_alert[0];
 	*ptr++ = s->s3->send_alert[1];
 
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
-	if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
-		{	
-		s2n(s->d1->handshake_read_seq, ptr);
-#if 0
-		if ( s->d1->r_msg_hdr.frag_off == 0)  /* waiting for a new msg */
-
-		else
-			s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */
-#endif
-
-#if 0
-		fprintf(stderr, "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n",s->d1->handshake_read_seq,s->d1->r_msg_hdr.seq);
-#endif
-		l2n3(s->d1->r_msg_hdr.frag_off, ptr);
-		}
-#endif
-
 	i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf));
 	if (i <= 0)
 		{
@@ -1603,11 +1519,7 @@
 		}
 	else
 		{
-		if (s->s3->send_alert[0] == SSL3_AL_FATAL
-#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
-		    || s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE
-#endif
-		    )
+		if (s->s3->send_alert[0] == SSL3_AL_FATAL)
 			(void)BIO_flush(s->wbio);
 
 		if (s->msg_callback)
diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c
index bc278c3..69b11ad 100644
--- a/ssl/d1_srtp.c
+++ b/ssl/d1_srtp.c
@@ -114,8 +114,6 @@
   Copyright (C) 2011, RTFM, Inc.
 */
 
-#ifndef OPENSSL_NO_SRTP
-
 #include <stdio.h>
 
 #include <openssl/bytestring.h>
@@ -226,20 +224,17 @@
     
 	return 1;
 	}
-    
-int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx,const char *profiles)
+
+int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, const char *profiles)
 	{
-	/* This API inverts its return value. */
-	return !ssl_ctx_make_profiles(profiles,&ctx->srtp_profiles);
+	return ssl_ctx_make_profiles(profiles, &ctx->srtp_profiles);
 	}
 
-int SSL_set_tlsext_use_srtp(SSL *s,const char *profiles)
+int SSL_set_srtp_profiles(SSL *s, const char *profiles)
 	{
-	/* This API inverts its return value. */
-	return !ssl_ctx_make_profiles(profiles,&s->srtp_profiles);
+	return ssl_ctx_make_profiles(profiles, &s->srtp_profiles);
 	}
 
-
 STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *s)
 	{
 	if(s != NULL)
@@ -263,6 +258,18 @@
 	return s->srtp_profile;
 	}
 
+int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles)
+	{
+	/* This API inverts its return value. */
+	return !SSL_CTX_set_srtp_profiles(ctx, profiles);
+	}
+
+int SSL_set_tlsext_use_srtp(SSL *s, const char *profiles)
+	{
+	/* This API inverts its return value. */
+	return !SSL_set_srtp_profiles(s, profiles);
+	}
+
 /* Note: this function returns 0 length if there are no 
    profiles specified */
 int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen)
@@ -464,6 +471,3 @@
 	*out_alert = SSL_AD_ILLEGAL_PARAMETER;
 	return 0;
 	}
-
-
-#endif
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index 79da484..e1c5616 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -687,5 +687,5 @@
 		}
 
 	/* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
-	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE, add_to_finished_hash));
 	}
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 6604fc7..65eb3ba 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -127,17 +127,19 @@
 #include "ssl_locl.h"
 
 /* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
-int ssl3_do_write(SSL *s, int type)
+int ssl3_do_write(SSL *s, int type, enum should_add_to_finished_hash should_add_to_finished_hash)
 	{
 	int ret;
 
 	ret=ssl3_write_bytes(s,type,&s->init_buf->data[s->init_off],
 	                     s->init_num);
 	if (ret < 0) return(-1);
-	if (type == SSL3_RT_HANDSHAKE)
+	if (type == SSL3_RT_HANDSHAKE && should_add_to_finished_hash == add_to_finished_hash)
+		{
 		/* should not be done for 'Hello Request's, but in that case
 		 * we'll ignore the result anyway */
 		ssl3_finish_mac(s,(unsigned char *)&s->init_buf->data[s->init_off],ret);
+		}
 	
 	if (ret == s->init_num)
 		{
@@ -320,7 +322,7 @@
 		}
 
 	/* SSL3_ST_CW_CHANGE_B */
-	return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
+	return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC, dont_add_to_finished_hash));
 	}
 
 unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk)
@@ -417,18 +419,6 @@
 			OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_UNEXPECTED_MESSAGE);
 			goto f_err;
 			}
-		if ((mt < 0) && (*p == SSL3_MT_CLIENT_HELLO) &&
-					(st1 == SSL3_ST_SR_CERT_A) &&
-					(stn == SSL3_ST_SR_CERT_B))
-			{
-			/* At this point we have got an MS SGC second client
-			 * hello (maybe we should always allow the client to
-			 * start a new handshake?). We need to restart the mac.
-			 * Don't increment {num,total}_renegotiations because
-			 * we have not completed the handshake. */
-			ssl3_init_finished_mac(s);
-			}
-
 		s->s3->tmp.message_type= *(p++);
 
 		n2l3(p,l);
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 6574f5a..64bccfa 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -982,7 +982,7 @@
 	/* Don't digest cached records if no sigalgs: we may need them for
 	 * client authentication.
 	 */
-	if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s))
+	if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s, free_handshake_buffer))
 		goto f_err;
 
 	/* Only the NULL compression algorithm is supported. */
@@ -1550,11 +1550,11 @@
 			}
 		else
 			{
-			EVP_VerifyInit_ex(&md_ctx, md, NULL);
-			EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
-			EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
-			EVP_VerifyUpdate(&md_ctx, CBS_data(&parameter), CBS_len(&parameter));
-			if (EVP_VerifyFinal(&md_ctx, CBS_data(&signature), CBS_len(&signature), pkey) <= 0)
+			if (!EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) ||
+				!EVP_DigestVerifyUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) ||
+				!EVP_DigestVerifyUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) ||
+				!EVP_DigestVerifyUpdate(&md_ctx, CBS_data(&parameter), CBS_len(&parameter)) ||
+				!EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature), CBS_len(&signature)))
 				{
 				/* bad signature */
 				al=SSL_AD_DECRYPT_ERROR;
@@ -1637,7 +1637,7 @@
 		 */
 		if (s->s3->handshake_buffer)
 			{
-			if (!ssl3_digest_cached_records(s))
+			if (!ssl3_digest_cached_records(s, free_handshake_buffer))
 				goto err;
 			}
 		return(1);
@@ -1909,6 +1909,8 @@
 	BN_CTX * bn_ctx = NULL;
 	unsigned int psk_len = 0;
 	unsigned char psk[PSK_MAX_PSK_LEN];
+	uint8_t *pms = NULL;
+	size_t pms_len = 0;
 
 	if (s->state == SSL3_ST_CW_KEY_EXCH_A)
 		{
@@ -1917,16 +1919,12 @@
 		alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
 		alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 
+		/* If using a PSK key exchange, prepare the pre-shared key. */
 		if (alg_a & SSL_aPSK)
 			{
 			char identity[PSK_MAX_IDENTITY_LEN + 1];
 			size_t identity_len;
-			unsigned char *t = NULL;
-			unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4];
-			unsigned int pre_ms_len = 0;
-			int psk_err = 1;
 
-			n = 0;
 			if (s->psk_client_callback == NULL)
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_NO_CLIENT_CB);
@@ -1939,40 +1937,19 @@
 			if (psk_len > PSK_MAX_PSK_LEN)
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
-				goto psk_err;
+				goto err;
 				}
 			else if (psk_len == 0)
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_IDENTITY_NOT_FOUND);
-				goto psk_err;
+				ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+				goto err;
 				}
 			identity_len = OPENSSL_strnlen(identity, sizeof(identity));
 			if (identity_len > PSK_MAX_IDENTITY_LEN)
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
-				goto psk_err;
-				}
-
-			if (!(alg_k & SSL_kEECDH))
-				{
-				/* Create the shared secret now if we're not using ECDHE-PSK.
-				 * TODO(davidben): Refactor this logic similarly
-				 * to ssl3_get_client_key_exchange. */
-				pre_ms_len = 2+psk_len+2+psk_len;
-				t = pre_ms;
-				s2n(psk_len, t);
-				memset(t, 0, psk_len);
-				t+=psk_len;
-				s2n(psk_len, t);
-				memcpy(t, psk, psk_len);
-
-				s->session->master_key_length =
-					s->method->ssl3_enc->generate_master_secret(s,
-						s->session->master_key,
-						pre_ms, pre_ms_len);
-				s2n(identity_len, p);
-				memcpy(p, identity, identity_len);
-				n = 2 + identity_len;
+				goto err;
 				}
 
 			if (s->session->psk_identity != NULL)
@@ -1981,23 +1958,30 @@
 			if (s->session->psk_identity == NULL)
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
-				goto psk_err;
-				}
-			psk_err = 0;
-		psk_err:
-			OPENSSL_cleanse(identity, sizeof(identity));
-			OPENSSL_cleanse(pre_ms, sizeof(pre_ms));
-			if (psk_err != 0)
-				{
-				ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
 				goto err;
 				}
+
+			/* Write out psk_identity. */
+			s2n(identity_len, p);
+			memcpy(p, identity, identity_len);
+			p += identity_len;
+			n = 2 + identity_len;
 			}
 
+		/* Depending on the key exchange method, compute |pms|
+		 * and |pms_len|. */
 		if (alg_k & SSL_kRSA)
 			{
 			RSA *rsa;
-			unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+			size_t enc_pms_len;
+
+			pms_len = SSL_MAX_MASTER_KEY_LENGTH;
+			pms = OPENSSL_malloc(pms_len);
+			if (pms == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
 
 			if (s->session->sess_cert == NULL)
 				{
@@ -2022,49 +2006,47 @@
 				EVP_PKEY_free(pkey);
 				}
 				
-			tmp_buf[0]=s->client_version>>8;
-			tmp_buf[1]=s->client_version&0xff;
-			if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
+			pms[0]=s->client_version>>8;
+			pms[1]=s->client_version&0xff;
+			if (RAND_bytes(&pms[2],SSL_MAX_MASTER_KEY_LENGTH-2) <= 0)
 					goto err;
 
-			s->session->master_key_length=sizeof tmp_buf;
+			s->session->master_key_length=SSL_MAX_MASTER_KEY_LENGTH;
 
 			q=p;
-			/* Fix buf for TLS and beyond */
+			/* In TLS and beyond, reserve space for the length prefix. */
 			if (s->version > SSL3_VERSION)
-				p+=2;
-			n=RSA_public_encrypt(sizeof tmp_buf,
-				tmp_buf,p,rsa,RSA_PKCS1_PADDING);
-			if (n <= 0)
+				{
+				p += 2;
+				n += 2;
+				}
+			if (!RSA_encrypt(rsa, &enc_pms_len, p, RSA_size(rsa),
+					pms, pms_len, RSA_PKCS1_PADDING))
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_BAD_RSA_ENCRYPT);
 				goto err;
 				}
+			n += enc_pms_len;
 
 			/* Log the premaster secret, if logging is enabled. */
 			if (!ssl_ctx_log_rsa_client_key_exchange(s->ctx,
-					p, n, tmp_buf, sizeof(tmp_buf)))
+					p, enc_pms_len, pms, pms_len))
 				{
 				goto err;
 				}
 
-			/* Fix buf for TLS and beyond */
+			/* Fill in the length prefix. */
 			if (s->version > SSL3_VERSION)
 				{
-				s2n(n,q);
-				n+=2;
+				s2n(enc_pms_len, q);
 				}
-
-			s->session->master_key_length=
-				s->method->ssl3_enc->generate_master_secret(s,
-					s->session->master_key,
-					tmp_buf,sizeof tmp_buf);
-			OPENSSL_cleanse(tmp_buf,sizeof tmp_buf);
 			}
 		else if (alg_k & SSL_kEDH)
 			{
-			DH *dh_srvr,*dh_clnt;
+			DH *dh_srvr, *dh_clnt;
 			SESS_CERT *scert = s->session->sess_cert;
+			int dh_len;
+			size_t pub_len;
 
 			if (scert == NULL) 
 				{
@@ -2093,44 +2075,38 @@
 				goto err;
 				}
 
-			/* use the 'p' output buffer for the DH key, but
-			 * make sure to clear it out afterwards */
+			pms_len = DH_size(dh_clnt);
+			pms = OPENSSL_malloc(pms_len);
+			if (pms == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				DH_free(dh_clnt);
+				goto err;
+				}
 
-			n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
-			if (n <= 0)
+			dh_len = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
+			if (dh_len <= 0)
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB);
 				DH_free(dh_clnt);
 				goto err;
 				}
-
-			/* generate master key from the result */
-			s->session->master_key_length=
-				s->method->ssl3_enc->generate_master_secret(s,
-					s->session->master_key,p,n);
-			/* clean up */
-			memset(p,0,n);
+			pms_len = dh_len;
 
 			/* send off the data */
-			n=BN_num_bytes(dh_clnt->pub_key);
-			s2n(n,p);
-			BN_bn2bin(dh_clnt->pub_key,p);
-			n+=2;
+			pub_len = BN_num_bytes(dh_clnt->pub_key);
+			s2n(pub_len, p);
+			BN_bn2bin(dh_clnt->pub_key, p);
+			n += 2 + pub_len;
 
 			DH_free(dh_clnt);
-
-			/* perhaps clean things up a bit EAY EAY EAY EAY*/
 			}
 
 		else if (alg_k & SSL_kEECDH)
 			{
 			const EC_GROUP *srvr_group = NULL;
 			EC_KEY *tkey;
-			int field_size = 0;
-			unsigned char *pre_ms;
-			unsigned char *t;
-			unsigned int pre_ms_len;
-			unsigned int i;
+			int field_size = 0, ecdh_len;
 
 			if (s->session->sess_cert == NULL) 
 				{
@@ -2173,54 +2149,28 @@
 				goto err;
 				}
 
-			/* use the 'p' output buffer for the ECDH key, but
-			 * make sure to clear it out afterwards
-			 */
-
 			field_size = EC_GROUP_get_degree(srvr_group);
 			if (field_size <= 0)
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
 				goto err;
 				}
-			n=ECDH_compute_key(p, (field_size+7)/8, srvr_ecpoint, clnt_ecdh, NULL);
-			if (n <= 0)
+
+			pms_len = (field_size + 7) / 8;
+			pms = OPENSSL_malloc(pms_len);
+			if (pms == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+
+			ecdh_len = ECDH_compute_key(pms, pms_len, srvr_ecpoint, clnt_ecdh, NULL);
+			if (ecdh_len <= 0)
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
 				goto err;
 				}
-
-			/* ECDHE PSK ciphersuites from RFC 5489 */
-			if ((alg_a & SSL_aPSK) && psk_len != 0)
-				{
-				pre_ms_len = 2+psk_len+2+n;
-				pre_ms = OPENSSL_malloc(pre_ms_len);
-				if (pre_ms == NULL)
-					{
-					OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
-					goto err;
-					}
-				memset(pre_ms, 0, pre_ms_len);
-				t = pre_ms;
-				s2n(psk_len, t);
-				memcpy(t, psk, psk_len);
-				t += psk_len;
-				s2n(n, t);
-				memcpy(t, p, n);
-				s->session->master_key_length = s->method->ssl3_enc \
-					-> generate_master_secret(s,
-						s->session->master_key, pre_ms, pre_ms_len);
-				OPENSSL_cleanse(pre_ms, pre_ms_len);
-				OPENSSL_free(pre_ms);
-				}
-			if (!(alg_a & SSL_aPSK))
-				{
-				/* generate master key from the result */
-				s->session->master_key_length = s->method->ssl3_enc \
-					-> generate_master_secret(s,
-						s->session->master_key, p, n);
-				}
-			memset(p, 0, n); /* clean up */
+			pms_len = ecdh_len;
 
 			/* First check the size of encoding and
 			 * allocate memory accordingly.
@@ -2248,32 +2198,39 @@
 				POINT_CONVERSION_UNCOMPRESSED,
 				encodedPoint, encoded_pt_len, bn_ctx);
 
-			n = 0;
-			if ((alg_a & SSL_aPSK) && psk_len != 0)
-				{
-				i = strlen(s->session->psk_identity);
-				s2n(i, p);
-				memcpy(p, s->session->psk_identity, i);
-				p += i;
-				n = i + 2;
-				}
-
 			*p = encoded_pt_len; /* length of encoded point */
 			/* Encoded point will be copied here */
 			p += 1;
 			n += 1;
 			/* copy the point */
-			memcpy((unsigned char *)p, encodedPoint, encoded_pt_len);
+			memcpy(p, encodedPoint, encoded_pt_len);
 			/* increment n to account for length field */
 			n += encoded_pt_len;
 
 			/* Free allocated memory */
 			BN_CTX_free(bn_ctx);
+			bn_ctx = NULL;
 			OPENSSL_free(encodedPoint);
+			encodedPoint = NULL;
 			EC_KEY_free(clnt_ecdh);
+			clnt_ecdh = NULL;
 			EVP_PKEY_free(srvr_pub_pkey);
+			srvr_pub_pkey = NULL;
 			}
-		else if (!(alg_k & SSL_kPSK) || ((alg_k & SSL_kPSK) && !(alg_a & SSL_aPSK)))
+		else if (alg_k & SSL_kPSK)
+			{
+			/* For plain PSK, other_secret is a block of 0s with the same
+			 * length as the pre-shared key. */
+			pms_len = psk_len;
+			pms = OPENSSL_malloc(pms_len);
+			if (pms == NULL)
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			memset(pms, 0, pms_len);
+			}
+		else
 			{
 			ssl3_send_alert(s, SSL3_AL_FATAL,
 			    SSL_AD_HANDSHAKE_FAILURE);
@@ -2281,19 +2238,71 @@
 			goto err;
 			}
 
+		/* For a PSK cipher suite, other_secret is combined
+		 * with the pre-shared key. */
+		if ((alg_a & SSL_aPSK) && psk_len != 0)
+			{
+			CBB cbb, child;
+			uint8_t *new_pms;
+			size_t new_pms_len;
+
+			if (!CBB_init(&cbb, 2 + psk_len + 2 + pms_len))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+				goto err;
+				}
+			if (!CBB_add_u16_length_prefixed(&cbb, &child) ||
+				!CBB_add_bytes(&child, pms, pms_len) ||
+				!CBB_add_u16_length_prefixed(&cbb, &child) ||
+				!CBB_add_bytes(&child, psk, psk_len) ||
+				!CBB_finish(&cbb, &new_pms, &new_pms_len))
+				{
+				CBB_cleanup(&cbb);
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+			OPENSSL_cleanse(pms, pms_len);
+			OPENSSL_free(pms);
+			pms = new_pms;
+			pms_len = new_pms_len;
+			}
+
 		ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n);
 		s->state=SSL3_ST_CW_KEY_EXCH_B;
+
+		/* The message must be added to the finished hash before
+		 * calculating the master secret. */
+		s->method->ssl3_enc->add_to_finished_hash(s);
+
+		s->session->master_key_length =
+			s->method->ssl3_enc->generate_master_secret(s,
+				s->session->master_key,
+				pms, pms_len);
+		if (s->session->master_key_length == 0)
+			{
+			goto err;
+			}
+		s->session->extended_master_secret = s->s3->tmp.extended_master_secret;
+		OPENSSL_cleanse(pms, pms_len);
+		OPENSSL_free(pms);
 		}
 
 	/* SSL3_ST_CW_KEY_EXCH_B */
-	return ssl_do_write(s);
+	/* The message has already been added to the finished hash. */
+	return s->method->ssl3_enc->do_write(s, dont_add_to_finished_hash);
+
 err:
 	BN_CTX_free(bn_ctx);
 	if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
 	if (clnt_ecdh != NULL) 
 		EC_KEY_free(clnt_ecdh);
 	EVP_PKEY_free(srvr_pub_pkey);
-	return(-1);
+	if (pms)
+		{
+		OPENSSL_cleanse(pms, pms_len);
+		OPENSSL_free(pms);
+		}
+	return -1;
 	}
 
 int ssl3_send_cert_verify(SSL *s)
@@ -2332,7 +2341,7 @@
 			goto err;
 
 		/* The handshake buffer is no longer necessary. */
-		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
 			goto err;
 
 		/* Sign the digest. */
@@ -2583,7 +2592,7 @@
 		s->init_off = 0;
 		}
 
-	return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+	return ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
 }
 
 
@@ -2597,7 +2606,7 @@
 	unsigned char *public_key = NULL, *derp, *der_sig = NULL;
 
 	if (s->state != SSL3_ST_CW_CHANNEL_ID_A)
-		return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+		return ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
 
 	if (!s->tlsext_channel_id_private && s->ctx->channel_id_cb)
 		{
@@ -2700,7 +2709,7 @@
 	s->init_num = 4 + 2 + 2 + TLSEXT_CHANNEL_ID_SIZE;
 	s->init_off = 0;
 
-	ret = ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+	ret = ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
 
 err:
 	EVP_MD_CTX_cleanup(&md_ctx);
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index b0ca507..fc94a94 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -510,7 +510,7 @@
 		}	
 	}
 
-int ssl3_digest_cached_records(SSL *s)
+int ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t should_free_handshake_buffer)
 	{
 	int i;
 	long mask;
@@ -542,9 +542,13 @@
 			s->s3->handshake_dgst[i]=NULL;
 			}
 		}
-	/* Free handshake_buffer BIO */
-	BIO_free(s->s3->handshake_buffer);
-	s->s3->handshake_buffer = NULL;
+
+	if (should_free_handshake_buffer == free_handshake_buffer)
+		{
+		/* Free handshake_buffer BIO */
+		BIO_free(s->s3->handshake_buffer);
+		s->s3->handshake_buffer = NULL;
+		}
 
 	return 1;
 	}
@@ -581,7 +585,7 @@
 	EVP_MD_CTX ctx,*d=NULL;
 
 	if (s->s3->handshake_buffer) 
-		if (!ssl3_digest_cached_records(s))
+		if (!ssl3_digest_cached_records(s, free_handshake_buffer))
 			return 0;
 
 	/* Search for digest of specified type in the handshake_dgst
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 215b3f6..3060684 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -942,7 +942,8 @@
 	0,
 	SSL3_HM_HEADER_LENGTH,
 	ssl3_set_handshake_header,
-	ssl3_handshake_write
+	ssl3_handshake_write,
+	ssl3_add_to_finished_hash,
 	};
 
 int ssl3_num_ciphers(void)
@@ -975,9 +976,14 @@
 	s->init_off = 0;
 	}
 
-int ssl3_handshake_write(SSL *s)
+int ssl3_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash)
 	{
-	return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+	return ssl3_do_write(s, SSL3_RT_HANDSHAKE, should_add_to_finished_hash);
+	}
+
+void ssl3_add_to_finished_hash(SSL *s)
+	{
+	ssl3_finish_mac(s, (uint8_t*) s->init_buf->data, s->init_num);
 	}
 
 int ssl3_new(SSL *s)
@@ -1385,9 +1391,9 @@
 			}
 	case SSL_CTRL_GET_EC_POINT_FORMATS:
 		{
+		const uint8_t **pformat = parg;
 		if (!s->s3->tmp.peer_ecpointformatlist)
 			return 0;
-		const uint8_t **pformat = parg;
 		*pformat = s->s3->tmp.peer_ecpointformatlist;
 		return (int)s->s3->tmp.peer_ecpointformatlist_length;
 		}
@@ -1850,10 +1856,6 @@
 		ssl_set_cert_masks(cert,c);
 		mask_k = cert->mask_k;
 		mask_a = cert->mask_a;
-			
-#ifdef KSSL_DEBUG
-/*		printf("ssl3_choose_cipher %d alg= %lx\n", i,c->algorithms);*/
-#endif    /* KSSL_DEBUG */
 
 		alg_k=c->algorithm_mkey;
 		alg_a=c->algorithm_auth;
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index 0df6a3c..d0e1856 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -1151,23 +1151,6 @@
 					OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE);
 					return(-1);
 					}
-
-				if (!(s->mode & SSL_MODE_AUTO_RETRY))
-					{
-					if (s->s3->rbuf.left == 0) /* no read-ahead left? */
-						{
-						BIO *bio;
-						/* In the case where we try to read application data,
-						 * but we trigger an SSL handshake, we return -1 with
-						 * the retry option set.  Otherwise renegotiation may
-						 * cause nasty problems in the blocking world */
-						s->rwstate=SSL_READING;
-						bio=SSL_get_rbio(s);
-						BIO_clear_retry_flags(bio);
-						BIO_set_retry_read(bio);
-						return(-1);
-						}
-					}
 				}
 			}
 		/* we either finished a handshake or ignored the request,
@@ -1237,10 +1220,6 @@
 				OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION);
 				goto f_err;
 				}
-#ifdef SSL_AD_MISSING_SRP_USERNAME
-			else if (alert_descr == SSL_AD_MISSING_SRP_USERNAME)
-				return(0);
-#endif
 			}
 		else if (alert_level == 2) /* fatal */
 			{
@@ -1339,22 +1318,6 @@
 			return(-1);
 			}
 
-		if (!(s->mode & SSL_MODE_AUTO_RETRY))
-			{
-			if (s->s3->rbuf.left == 0) /* no read-ahead left? */
-				{
-				BIO *bio;
-				/* In the case where we try to read application data,
-				 * but we trigger an SSL handshake, we return -1 with
-				 * the retry option set.  Otherwise renegotiation may
-				 * cause nasty problems in the blocking world */
-				s->rwstate=SSL_READING;
-				bio=SSL_get_rbio(s);
-				BIO_clear_retry_flags(bio);
-				BIO_set_retry_read(bio);
-				return(-1);
-				}
-			}
 		goto start;
 		}
 
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 149d9e7..29448db 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -444,7 +444,7 @@
 				s->s3->tmp.cert_request=0;
 				s->state=SSL3_ST_SW_SRVR_DONE_A;
 				if (s->s3->handshake_buffer)
-					if (!ssl3_digest_cached_records(s))
+					if (!ssl3_digest_cached_records(s, free_handshake_buffer))
 						return -1;
 				}
 			else
@@ -993,7 +993,8 @@
 		goto f_err;
 		}
 
-	if (ssl_bytes_to_cipher_list(s, &cipher_suites, &ciphers) == NULL)
+	ciphers = ssl_bytes_to_cipher_list(s, &cipher_suites);
+	if (ciphers == NULL)
 		{
 		goto err;
 		}
@@ -1143,7 +1144,7 @@
 
 	if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER))
 		{
-		if (!ssl3_digest_cached_records(s))
+		if (!ssl3_digest_cached_records(s, free_handshake_buffer))
 			goto f_err;
 		}
 	
@@ -1608,6 +1609,8 @@
 			else
 			if (md)
 				{
+				size_t sig_len = EVP_PKEY_size(pkey);
+
 				/* send signature algorithm */
 				if (SSL_USE_SIGALGS(s))
 					{
@@ -1620,24 +1623,19 @@
 						}
 					p+=2;
 					}
-#ifdef SSL_DEBUG
-				fprintf(stderr, "Using hash %s\n",
-							EVP_MD_name(md));
-#endif
-				EVP_SignInit_ex(&md_ctx, md, NULL);
-				EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
-				EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
-				EVP_SignUpdate(&md_ctx,d,n);
-				if (!EVP_SignFinal(&md_ctx,&(p[2]),
-					(unsigned int *)&i,pkey))
+				if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey) ||
+					!EVP_DigestSignUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) ||
+					!EVP_DigestSignUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) ||
+					!EVP_DigestSignUpdate(&md_ctx, d, n) ||
+					!EVP_DigestSignFinal(&md_ctx, &p[2], &sig_len))
 					{
 					OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_EVP);
 					goto err;
 					}
-				s2n(i,p);
-				n+=i+2;
+				s2n(sig_len, p);
+				n += sig_len + 2;
 				if (SSL_USE_SIGALGS(s))
-					n+= 2;
+					n += 2;
 				}
 			else
 				{
@@ -2140,9 +2138,13 @@
 			}
 
 		EVP_PKEY_free(clnt_pub_pkey);
+		clnt_pub_pkey = NULL;
 		EC_POINT_free(clnt_ecpoint);
+		clnt_ecpoint = NULL;
 		EC_KEY_free(srvr_ecdh);
+		srvr_ecdh = NULL;
 		BN_CTX_free(bn_ctx);
+		bn_ctx = NULL;
 		EC_KEY_free(s->s3->tmp.ecdh);
 		s->s3->tmp.ecdh = NULL;
 
@@ -2202,6 +2204,9 @@
 	s->session->master_key_length = s->method->ssl3_enc
 		->generate_master_secret(s,
 			s->session->master_key, premaster_secret, premaster_secret_len);
+	if (s->session->master_key_length == 0)
+		goto err;
+	s->session->extended_master_secret = s->s3->tmp.extended_master_secret;
 
 	OPENSSL_cleanse(premaster_secret, premaster_secret_len);
 	OPENSSL_free(premaster_secret);
@@ -2242,7 +2247,7 @@
 	 * client certificate. */
 	if (peer == NULL)
 		{
-		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
 			return -1;
 		return 1;
 		}
@@ -2283,7 +2288,7 @@
 
 	/* The handshake buffer is no longer necessary, and we may hash the
 	 * current message.*/
-	if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+	if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
 		goto err;
 	ssl3_hash_current_message(s);
 
@@ -2452,7 +2457,7 @@
 			goto f_err;
 			}
 		/* No client certificate so digest cached records */
-		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
 			{
 			al=SSL_AD_INTERNAL_ERROR;
 			goto f_err;
@@ -2531,61 +2536,62 @@
 	{
 	if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
 		{
-		unsigned char *p, *senc, *macstart;
-		const unsigned char *const_p;
-		int len, slen_full, slen;
-		SSL_SESSION *sess;
+		uint8_t *session;
+		size_t session_len;
+		uint8_t *p, *macstart;
+		int len;
 		unsigned int hlen;
 		EVP_CIPHER_CTX ctx;
 		HMAC_CTX hctx;
 		SSL_CTX *tctx = s->initial_ctx;
 		unsigned char iv[EVP_MAX_IV_LENGTH];
 		unsigned char key_name[16];
+		/* The maximum overhead of encrypting the session is 16 (key
+		 * name) + IV + one block of encryption overhead + HMAC.  */
+		const size_t max_ticket_overhead = 16 + EVP_MAX_IV_LENGTH +
+			EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE;
 
-		/* get session encoding length */
-		slen_full = i2d_SSL_SESSION(s->session, NULL);
-		/* Some length values are 16 bits, so forget it if session is
- 		 * too long
- 		 */
-		if (slen_full > 0xFF00)
-			return -1;
-		senc = OPENSSL_malloc(slen_full);
-		if (!senc)
-			return -1;
-		p = senc;
-		i2d_SSL_SESSION(s->session, &p);
-
-		/* create a fresh copy (not shared with other threads) to clean up */
-		const_p = senc;
-		sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
-		if (sess == NULL)
+		/* Serialize the SSL_SESSION to be encoded into the ticket. */
+		if (!SSL_SESSION_to_bytes_for_ticket(s->session, &session,
+				&session_len))
 			{
-			OPENSSL_free(senc);
 			return -1;
 			}
-		sess->session_id_length = 0; /* ID is irrelevant for the ticket */
 
-		slen = i2d_SSL_SESSION(sess, NULL);
-		if (slen > slen_full) /* shouldn't ever happen */
+		/* If the session is too long, emit a dummy value rather than
+		 * abort the connection. */
+		if (session_len > 0xFFFF - max_ticket_overhead)
 			{
-			OPENSSL_free(senc);
-			return -1;
+			const char kTicketPlaceholder[] = "TICKET TOO LARGE";
+			size_t placeholder_len = strlen(kTicketPlaceholder);
+
+			OPENSSL_free(session);
+
+			p = ssl_handshake_start(s);
+			/* Emit ticket_lifetime_hint. */
+			l2n(0, p);
+			/* Emit ticket. */
+			s2n(placeholder_len, p);
+			memcpy(p, kTicketPlaceholder, placeholder_len);
+			p += placeholder_len;
+
+			len = p - ssl_handshake_start(s);
+			ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len);
+			s->state = SSL3_ST_SW_SESSION_TICKET_B;
+			return ssl_do_write(s);
 			}
-		p = senc;
-		i2d_SSL_SESSION(sess, &p);
-		SSL_SESSION_free(sess);
 
 		/* Grow buffer if need be: the length calculation is as
- 		 * follows handshake_header_length +
+		 * follows: handshake_header_length +
  		 * 4 (ticket lifetime hint) + 2 (ticket length) +
- 		 * 16 (key name) + max_iv_len (iv length) +
- 		 * session_length + max_enc_block_size (max encrypted session
- 		 * length) + max_md_size (HMAC).
- 		 */
+		 * max_ticket_overhead + * session_length */
 		if (!BUF_MEM_grow(s->init_buf,
-			SSL_HM_HEADER_LENGTH(s) + 22 + EVP_MAX_IV_LENGTH +
-			EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
+				SSL_HM_HEADER_LENGTH(s) + 6 +
+				max_ticket_overhead + session_len))
+			{
+			OPENSSL_free(session);
 			return -1;
+			}
 		p = ssl_handshake_start(s);
 		EVP_CIPHER_CTX_init(&ctx);
 		HMAC_CTX_init(&hctx);
@@ -2598,7 +2604,7 @@
 			if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
 							 &hctx, 1) < 0)
 				{
-				OPENSSL_free(senc);
+				OPENSSL_free(session);
 				return -1;
 				}
 			}
@@ -2628,7 +2634,7 @@
 		memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
 		p += EVP_CIPHER_CTX_iv_length(&ctx);
 		/* Encrypt session data */
-		EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
+		EVP_EncryptUpdate(&ctx, p, &len, session, session_len);
 		p += len;
 		EVP_EncryptFinal_ex(&ctx, p, &len);
 		p += len;
@@ -2647,7 +2653,7 @@
 		p = ssl_handshake_start(s) + 4;
 		s2n(len - 6, p);
 		s->state=SSL3_ST_SW_SESSION_TICKET_B;
-		OPENSSL_free(senc);
+		OPENSSL_free(session);
 		}
 
 	/* SSL3_ST_SW_SESSION_TICKET_B */
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 5e86017..ef7ebdc 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -80,538 +80,530 @@
  * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
  * OTHERWISE. */
 
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
 
-#include <openssl/asn1.h>
-#include <openssl/asn1_mac.h>
+#include <openssl/bytestring.h>
 #include <openssl/err.h>
-#include <openssl/mem.h>
-#include <openssl/obj.h>
 #include <openssl/x509.h>
 
 #include "ssl_locl.h"
 
-OPENSSL_DECLARE_ERROR_REASON(SSL, CIPHER_CODE_WRONG_LENGTH);
-OPENSSL_DECLARE_ERROR_REASON(SSL, UNKNOWN_SSL_VERSION);
-OPENSSL_DECLARE_ERROR_REASON(SSL, BAD_LENGTH);
-OPENSSL_DECLARE_ERROR_FUNCTION(SSL, D2I_SSL_SESSION);
 
+/* An SSL_SESSION is serialized as the following ASN.1 structure:
+ *
+ * SSLSession ::= SEQUENCE {
+ *     version                     INTEGER (1),  -- ignored
+ *     sslVersion                  INTEGER,      -- protocol version number
+ *     cipher                      OCTET STRING, -- two bytes long
+ *     sessionID                   OCTET STRING,
+ *     masterKey                   OCTET STRING,
+ *     time                    [1] INTEGER OPTIONAL, -- seconds since UNIX epoch
+ *     timeout                 [2] INTEGER OPTIONAL, -- in seconds
+ *     peer                    [3] Certificate OPTIONAL,
+ *     sessionIDContext        [4] OCTET STRING OPTIONAL,
+ *     verifyResult            [5] INTEGER OPTIONAL,  -- one of X509_V_* codes
+ *     hostName                [6] OCTET STRING OPTIONAL,
+ *                                 -- from server_name extension
+ *     pskIdentityHint         [7] OCTET STRING OPTIONAL,
+ *     pskIdentity             [8] OCTET STRING OPTIONAL,
+ *     ticketLifetimeHint      [9] INTEGER OPTIONAL,       -- client-only
+ *     ticket                  [10] OCTET STRING OPTIONAL, -- client-only
+ *     peerSHA256              [13] OCTET STRING OPTIONAL,
+ *     originalHandshakeHash   [14] OCTET STRING OPTIONAL,
+ *     signedCertTimestampList [15] OCTET STRING OPTIONAL,
+ *                                  -- contents of SCT extension
+ *     ocspResponse            [16] OCTET STRING OPTIONAL,
+ *                                   -- stapled OCSP response from the server
+ *     extendedMasterSecret    [17] BOOLEAN OPTIONAL,
+ * }
+ *
+ * Note: When the relevant features were #ifdef'd out, support for
+ * parsing compressionMethod [11] and srpUsername [12] was lost. */
 
-typedef struct ssl_session_asn1_st
-	{
-	ASN1_INTEGER version;
-	ASN1_INTEGER ssl_version;
-	ASN1_OCTET_STRING cipher;
-	ASN1_OCTET_STRING comp_id;
-	ASN1_OCTET_STRING master_key;
-	ASN1_OCTET_STRING session_id;
-	ASN1_OCTET_STRING session_id_context;
-	ASN1_INTEGER time;
-	ASN1_INTEGER timeout;
-	ASN1_INTEGER verify_result;
-	ASN1_OCTET_STRING tlsext_hostname;
-	ASN1_INTEGER tlsext_tick_lifetime;
-	ASN1_OCTET_STRING tlsext_tick;
-	ASN1_OCTET_STRING psk_identity_hint;
-	ASN1_OCTET_STRING psk_identity;
-	ASN1_OCTET_STRING peer_sha256;
-	ASN1_OCTET_STRING original_handshake_hash;
-	ASN1_OCTET_STRING tlsext_signed_cert_timestamp_list;
-	ASN1_OCTET_STRING ocsp_response;
-	} SSL_SESSION_ASN1;
+static const int kTimeTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
+static const int kTimeoutTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2;
+static const int kPeerTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3;
+ static const int kSessionIDContextTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 4;
+static const int kVerifyResultTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 5;
+static const int kHostNameTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 6;
+static const int kPSKIdentityHintTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 7;
+static const int kPSKIdentityTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 8;
+static const int kTicketLifetimeHintTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 9;
+static const int kTicketTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 10;
+static const int kPeerSHA256Tag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 13;
+static const int kOriginalHandshakeHashTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 14;
+static const int kSignedCertTimestampListTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 15;
+static const int kOCSPResponseTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 16;
+static const int kExtendedMasterSecretTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17;
 
-int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
-	{
-#define LSIZE2 (sizeof(long)*2)
-	int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0,v13=0,v14=0,v15=0,v16=0;
-	unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
-	unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
-	int v6=0,v9=0,v10=0;
-	unsigned char ibuf6[LSIZE2];
-	long l;
-	SSL_SESSION_ASN1 a;
-	M_ASN1_I2D_vars(in);
+static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data,
+                                     size_t *out_len, int for_ticket) {
+  CBB cbb, session, child, child2;
+  uint16_t cipher_id;
 
-	if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0)))
-		return(0);
+  if (in == NULL || (in->cipher == NULL && in->cipher_id == 0)) {
+    return 0;
+  }
 
-	/* Note that I cheat in the following 2 assignments.  I know
-	 * that if the ASN1_INTEGER passed to ASN1_INTEGER_set
-	 * is > sizeof(long)+1, the buffer will not be re-OPENSSL_malloc()ed.
-	 * This is a bit evil but makes things simple, no dynamic allocation
-	 * to clean up :-) */
-	a.version.length=LSIZE2;
-	a.version.type=V_ASN1_INTEGER;
-	a.version.data=ibuf1;
-	ASN1_INTEGER_set(&(a.version),SSL_SESSION_ASN1_VERSION);
+  if (!CBB_init(&cbb, 0)) {
+    return 0;
+  }
 
-	a.ssl_version.length=LSIZE2;
-	a.ssl_version.type=V_ASN1_INTEGER;
-	a.ssl_version.data=ibuf2;
-	ASN1_INTEGER_set(&(a.ssl_version),in->ssl_version);
+  if (in->cipher == NULL) {
+    cipher_id = in->cipher_id & 0xffff;
+  } else {
+    cipher_id = in->cipher->id & 0xffff;
+  }
 
-	a.cipher.type=V_ASN1_OCTET_STRING;
-	a.cipher.data=buf;
+  if (!CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) ||
+      !CBB_add_asn1_uint64(&session, SSL_SESSION_ASN1_VERSION) ||
+      !CBB_add_asn1_uint64(&session, in->ssl_version) ||
+      !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
+      !CBB_add_u16(&child, cipher_id) ||
+      !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
+      /* The session ID is irrelevant for a session ticket. */
+      !CBB_add_bytes(&child, in->session_id,
+                     for_ticket ? 0 : in->session_id_length) ||
+      !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
+      !CBB_add_bytes(&child, in->master_key, in->master_key_length)) {
+    OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
 
-	if (in->cipher == NULL)
-		l=in->cipher_id;
-	else
-		l=in->cipher->id;
-	if (in->ssl_version == SSL2_VERSION)
-		{
-		a.cipher.length=3;
-		buf[0]=((unsigned char)(l>>16L))&0xff;
-		buf[1]=((unsigned char)(l>> 8L))&0xff;
-		buf[2]=((unsigned char)(l     ))&0xff;
-		}
-	else
-		{
-		a.cipher.length=2;
-		buf[0]=((unsigned char)(l>>8L))&0xff;
-		buf[1]=((unsigned char)(l    ))&0xff;
-		}
+  if (in->time != 0) {
+    if (!CBB_add_asn1(&session, &child, kTimeTag) ||
+        !CBB_add_asn1_uint64(&child, in->time)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
+  if (in->timeout != 0) {
+    if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
+        !CBB_add_asn1_uint64(&child, in->timeout)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	a.master_key.length=in->master_key_length;
-	a.master_key.type=V_ASN1_OCTET_STRING;
-	a.master_key.data=in->master_key;
+  /* The peer certificate is only serialized if the SHA-256 isn't
+   * serialized instead. */
+  if (in->peer && !in->peer_sha256_valid) {
+    uint8_t *buf;
+    int len = i2d_X509(in->peer, NULL);
+    if (len < 0) {
+      goto err;
+    }
+    if (!CBB_add_asn1(&session, &child, kPeerTag) ||
+        !CBB_add_space(&child, &buf, len)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+    if (buf != NULL && i2d_X509(in->peer, &buf) < 0) {
+      goto err;
+    }
+  }
 
-	a.session_id.length=in->session_id_length;
-	a.session_id.type=V_ASN1_OCTET_STRING;
-	a.session_id.data=in->session_id;
+  /* Although it is OPTIONAL and usually empty, OpenSSL has
+   * historically always encoded the sid_ctx. */
+  if (!CBB_add_asn1(&session, &child, kSessionIDContextTag) ||
+      !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+      !CBB_add_bytes(&child2, in->sid_ctx, in->sid_ctx_length)) {
+    OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
 
-	a.session_id_context.length=in->sid_ctx_length;
-	a.session_id_context.type=V_ASN1_OCTET_STRING;
-	a.session_id_context.data=in->sid_ctx;
+  if (in->verify_result != X509_V_OK) {
+    if (!CBB_add_asn1(&session, &child, kVerifyResultTag) ||
+        !CBB_add_asn1_uint64(&child, in->verify_result)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	if (in->time != 0L)
-		{
-		a.time.length=LSIZE2;
-		a.time.type=V_ASN1_INTEGER;
-		a.time.data=ibuf3;
-		ASN1_INTEGER_set(&(a.time),in->time);
-		}
+  if (in->tlsext_hostname) {
+    if (!CBB_add_asn1(&session, &child, kHostNameTag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+        !CBB_add_bytes(&child2, (const uint8_t *)in->tlsext_hostname,
+                       strlen(in->tlsext_hostname))) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	if (in->timeout != 0L)
-		{
-		a.timeout.length=LSIZE2;
-		a.timeout.type=V_ASN1_INTEGER;
-		a.timeout.data=ibuf4;
-		ASN1_INTEGER_set(&(a.timeout),in->timeout);
-		}
+  if (in->psk_identity_hint) {
+    if (!CBB_add_asn1(&session, &child, kPSKIdentityHintTag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+        !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity_hint,
+                       strlen(in->psk_identity_hint))) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	if (in->verify_result != X509_V_OK)
-		{
-		a.verify_result.length=LSIZE2;
-		a.verify_result.type=V_ASN1_INTEGER;
-		a.verify_result.data=ibuf5;
-		ASN1_INTEGER_set(&a.verify_result,in->verify_result);
-		}
+  if (in->psk_identity) {
+    if (!CBB_add_asn1(&session, &child, kPSKIdentityTag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+        !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity,
+                       strlen(in->psk_identity))) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	if (in->tlsext_hostname)
-                {
-                a.tlsext_hostname.length=strlen(in->tlsext_hostname);
-                a.tlsext_hostname.type=V_ASN1_OCTET_STRING;
-                a.tlsext_hostname.data=(unsigned char *)in->tlsext_hostname;
-                }
-	if (in->tlsext_tick)
-                {
-                a.tlsext_tick.length= in->tlsext_ticklen;
-                a.tlsext_tick.type=V_ASN1_OCTET_STRING;
-                a.tlsext_tick.data=(unsigned char *)in->tlsext_tick;
-                }
-	if (in->tlsext_tick_lifetime_hint > 0)
-		{
-		a.tlsext_tick_lifetime.length=LSIZE2;
-		a.tlsext_tick_lifetime.type=V_ASN1_INTEGER;
-		a.tlsext_tick_lifetime.data=ibuf6;
-		ASN1_INTEGER_set(&a.tlsext_tick_lifetime,in->tlsext_tick_lifetime_hint);
-		}
-	if (in->psk_identity_hint)
-		{
-		a.psk_identity_hint.length=strlen(in->psk_identity_hint);
-		a.psk_identity_hint.type=V_ASN1_OCTET_STRING;
-		a.psk_identity_hint.data=(unsigned char *)(in->psk_identity_hint);
-		}
-	if (in->psk_identity)
-		{
-		a.psk_identity.length=strlen(in->psk_identity);
-		a.psk_identity.type=V_ASN1_OCTET_STRING;
-		a.psk_identity.data=(unsigned char *)(in->psk_identity);
-		}
+  if (in->tlsext_tick_lifetime_hint > 0) {
+    if (!CBB_add_asn1(&session, &child, kTicketLifetimeHintTag) ||
+        !CBB_add_asn1_uint64(&child, in->tlsext_tick_lifetime_hint)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	if (in->peer_sha256_valid)
-		{
-		a.peer_sha256.length = sizeof(in->peer_sha256);
-		a.peer_sha256.type = V_ASN1_OCTET_STRING;
-		a.peer_sha256.data = in->peer_sha256;
-		}
+  if (in->tlsext_tick) {
+    if (!CBB_add_asn1(&session, &child, kTicketTag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+        !CBB_add_bytes(&child2, in->tlsext_tick, in->tlsext_ticklen)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	if (in->original_handshake_hash_len > 0)
-		{
-		a.original_handshake_hash.length = in->original_handshake_hash_len;
-		a.original_handshake_hash.type = V_ASN1_OCTET_STRING;
-		a.original_handshake_hash.data = in->original_handshake_hash;
-		}
+  if (in->peer_sha256_valid) {
+    if (!CBB_add_asn1(&session, &child, kPeerSHA256Tag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+        !CBB_add_bytes(&child2, in->peer_sha256, sizeof(in->peer_sha256))) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	if (in->tlsext_signed_cert_timestamp_list_length > 0)
-		{
-		a.tlsext_signed_cert_timestamp_list.length =
-				in->tlsext_signed_cert_timestamp_list_length;
-		a.tlsext_signed_cert_timestamp_list.type = V_ASN1_OCTET_STRING;
-		a.tlsext_signed_cert_timestamp_list.data =
-				in->tlsext_signed_cert_timestamp_list;
-		}
+  if (in->original_handshake_hash_len > 0) {
+    if (!CBB_add_asn1(&session, &child, kOriginalHandshakeHashTag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+        !CBB_add_bytes(&child2, in->original_handshake_hash,
+                       in->original_handshake_hash_len)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	if (in->ocsp_response_length > 0)
-		{
-		a.ocsp_response.length = in->ocsp_response_length;
-		a.ocsp_response.type = V_ASN1_OCTET_STRING;
-		a.ocsp_response.data = in->ocsp_response;
-		}
+  if (in->tlsext_signed_cert_timestamp_list_length > 0) {
+    if (!CBB_add_asn1(&session, &child, kSignedCertTimestampListTag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+        !CBB_add_bytes(&child2, in->tlsext_signed_cert_timestamp_list,
+                       in->tlsext_signed_cert_timestamp_list_length)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	M_ASN1_I2D_len(&(a.version),		i2d_ASN1_INTEGER);
-	M_ASN1_I2D_len(&(a.ssl_version),	i2d_ASN1_INTEGER);
-	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->time != 0L)
-		M_ASN1_I2D_len_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
-	if (in->timeout != 0L)
-		M_ASN1_I2D_len_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
-	if (in->peer != NULL && in->peer_sha256_valid == 0)
-		M_ASN1_I2D_len_EXP_opt(in->peer,i2d_X509,3,v3);
-	M_ASN1_I2D_len_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,v4);
-	if (in->verify_result != X509_V_OK)
-		M_ASN1_I2D_len_EXP_opt(&(a.verify_result),i2d_ASN1_INTEGER,5,v5);
+  if (in->ocsp_response_length > 0) {
+    if (!CBB_add_asn1(&session, &child, kOCSPResponseTag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+        !CBB_add_bytes(&child2, in->ocsp_response, in->ocsp_response_length)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	if (in->tlsext_tick_lifetime_hint > 0)
-      	 	M_ASN1_I2D_len_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
-	if (in->tlsext_tick)
-        	M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
-	if (in->tlsext_hostname)
-        	M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
-	if (in->psk_identity_hint)
-        	M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
-	if (in->psk_identity)
-        	M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
-	if (in->peer_sha256_valid)
-		M_ASN1_I2D_len_EXP_opt(&(a.peer_sha256),i2d_ASN1_OCTET_STRING,13,v13);
-	if (in->original_handshake_hash_len > 0)
-		M_ASN1_I2D_len_EXP_opt(&(a.original_handshake_hash),i2d_ASN1_OCTET_STRING,14,v14);
-	if (in->tlsext_signed_cert_timestamp_list_length > 0)
-		M_ASN1_I2D_len_EXP_opt(&(a.tlsext_signed_cert_timestamp_list),
-				i2d_ASN1_OCTET_STRING, 15, v15);
-	if (in->ocsp_response_length > 0)
-		M_ASN1_I2D_len_EXP_opt(&(a.ocsp_response), i2d_ASN1_OCTET_STRING, 16, v16);
+  if (in->extended_master_secret) {
+    if (!CBB_add_asn1(&session, &child, kExtendedMasterSecretTag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
+        !CBB_add_u8(&child2, 0xff)) {
+      OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
 
-	M_ASN1_I2D_seq_total();
+  if (!CBB_finish(&cbb, out_data, out_len)) {
+    OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+    goto err;
+  }
+  return 1;
 
-	M_ASN1_I2D_put(&(a.version),		i2d_ASN1_INTEGER);
-	M_ASN1_I2D_put(&(a.ssl_version),	i2d_ASN1_INTEGER);
-	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->time != 0L)
-		M_ASN1_I2D_put_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1);
-	if (in->timeout != 0L)
-		M_ASN1_I2D_put_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2);
-	if (in->peer != NULL && in->peer_sha256_valid == 0)
-		M_ASN1_I2D_put_EXP_opt(in->peer,i2d_X509,3,v3);
-	M_ASN1_I2D_put_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,
-			       v4);
-	if (in->verify_result != X509_V_OK)
-		M_ASN1_I2D_put_EXP_opt(&a.verify_result,i2d_ASN1_INTEGER,5,v5);
-	if (in->tlsext_hostname)
-        	M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
-	if (in->psk_identity_hint)
-		M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7);
-	if (in->psk_identity)
-		M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8);
-	if (in->tlsext_tick_lifetime_hint > 0)
-      	 	M_ASN1_I2D_put_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
-	if (in->tlsext_tick)
-        	M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
-	if (in->peer_sha256_valid)
-		M_ASN1_I2D_put_EXP_opt(&(a.peer_sha256),i2d_ASN1_OCTET_STRING,13,v13);
-	if (in->original_handshake_hash_len > 0)
-		M_ASN1_I2D_put_EXP_opt(&(a.original_handshake_hash),i2d_ASN1_OCTET_STRING,14,v14);
-	if (in->tlsext_signed_cert_timestamp_list_length > 0)
-		M_ASN1_I2D_put_EXP_opt(&(a.tlsext_signed_cert_timestamp_list),
-				i2d_ASN1_OCTET_STRING, 15, v15);
-	if (in->ocsp_response > 0)
-		M_ASN1_I2D_put_EXP_opt(&(a.ocsp_response), i2d_ASN1_OCTET_STRING, 16, v16);
+ err:
+  CBB_cleanup(&cbb);
+  return 0;
+}
 
-	M_ASN1_I2D_finish();
-	}
+int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data, size_t *out_len) {
+  return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0);
+}
 
-SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
-			     long length)
-	{
-	int ssl_version=0,i;
-	long id;
-	ASN1_INTEGER ai,*aip;
-	ASN1_OCTET_STRING os,*osp;
-	M_ASN1_D2I_vars(a,SSL_SESSION *,SSL_SESSION_new);
+int SSL_SESSION_to_bytes_for_ticket(SSL_SESSION *in, uint8_t **out_data,
+                                    size_t *out_len) {
+  return SSL_SESSION_to_bytes_full(in, out_data, out_len, 1);
+}
 
-	aip= &ai;
-	osp= &os;
+int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) {
+  uint8_t *out;
+  size_t len;
 
-	M_ASN1_D2I_Init();
-	M_ASN1_D2I_start_sequence();
+  if (!SSL_SESSION_to_bytes(in, &out, &len)) {
+    return -1;
+  }
 
-	ai.data=NULL; ai.length=0;
-	M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
-	if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
+  if (len > INT_MAX) {
+    OPENSSL_free(out);
+    OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_OVERFLOW);
+    return -1;
+  }
 
-	/* we don't care about the version right now :-) */
-	M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER);
-	ssl_version=(int)ASN1_INTEGER_get(aip);
-	ret->ssl_version=ssl_version;
-	if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; }
+  if (pp) {
+    memcpy(*pp, out, len);
+    *pp += len;
+  }
+  OPENSSL_free(out);
 
-	os.data=NULL; os.length=0;
-	M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
-	if (ssl_version == SSL2_VERSION)
-		{
-		if (os.length != 3)
-			{
-			c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
-			c.line=__LINE__;
-			goto err;
-			}
-		id=0x02000000L|
-			((unsigned long)os.data[0]<<16L)|
-			((unsigned long)os.data[1]<< 8L)|
-			 (unsigned long)os.data[2];
-		}
-	else if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
-		{
-		if (os.length != 2)
-			{
-			c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH;
-			c.line=__LINE__;
-			goto err;
-			}
-		id=0x03000000L|
-			((unsigned long)os.data[0]<<8L)|
-			 (unsigned long)os.data[1];
-		}
-	else
-		{
-		c.error=SSL_R_UNKNOWN_SSL_VERSION;
-		c.line=__LINE__;
-		goto err;
-		}
-	
-	ret->cipher_id=id;
-	ret->cipher = ssl3_get_cipher_by_value(ret->cipher_id & 0xffff);
-	if (ret->cipher == NULL)
-		{
-		c.error=SSL_R_UNSUPPORTED_CIPHER;
-		c.line = __LINE__;
-		goto err;
-		}
+  return len;
+}
 
-	M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
-	if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
-		i=SSL3_MAX_SSL_SESSION_ID_LENGTH;
-	else /* if (ssl_version>>8 == SSL2_VERSION_MAJOR) */
-		i=SSL2_MAX_SSL_SESSION_ID_LENGTH;
+/* d2i_SSL_SESSION_get_string gets an optional ASN.1 OCTET STRING
+ * explicitly tagged with |tag| from |cbs| and saves it in |*out|. On
+ * entry, if |*out| is not NULL, it frees the existing contents. If
+ * the element was not found, it sets |*out| to NULL. It returns one
+ * on success, whether or not the element was found, and zero on
+ * decode error. */
+static int d2i_SSL_SESSION_get_string(CBS *cbs, char **out, unsigned tag) {
+  CBS value;
+  int present;
+  if (!CBS_get_optional_asn1_octet_string(cbs, &value, &present, tag)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    return 0;
+  }
+  if (present) {
+    if (CBS_contains_zero_byte(&value)) {
+      OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+      return 0;
+    }
+    if (!CBS_strdup(&value, out)) {
+      OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+      return 0;
+    }
+  } else if (*out) {
+    OPENSSL_free(*out);
+    *out = NULL;
+  }
+  return 1;
+}
 
-	if (os.length > i)
-		os.length = i;
-	if (os.length > (int)sizeof(ret->session_id)) /* can't happen */
-		os.length = sizeof(ret->session_id);
+/* d2i_SSL_SESSION_get_string gets an optional ASN.1 OCTET STRING
+ * explicitly tagged with |tag| from |cbs| and stows it in |*out_ptr|
+ * and |*out_len|. If |*out_ptr| is not NULL, it frees the existing
+ * contents. On entry, if the element was not found, it sets
+ * |*out_ptr| to NULL. It returns one on success, whether or not the
+ * element was found, and zero on decode error. */
+static int d2i_SSL_SESSION_get_octet_string(CBS *cbs, uint8_t **out_ptr,
+                                            size_t *out_len, unsigned tag) {
+  CBS value;
+  if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    return 0;
+  }
+  if (!CBS_stow(&value, out_ptr, out_len)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+  return 1;
+}
 
-	ret->session_id_length=os.length;
-	assert(os.length <= (int)sizeof(ret->session_id));
-	memcpy(ret->session_id,os.data,os.length);
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) {
+  SSL_SESSION *ret = NULL;
+  CBS cbs, session, cipher, session_id, master_key;
+  CBS peer, sid_ctx, peer_sha256, original_handshake_hash;
+  int has_peer, has_peer_sha256, extended_master_secret;
+  uint64_t version, ssl_version;
+  uint64_t session_time, timeout, verify_result, ticket_lifetime_hint;
 
-	M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
-	if (os.length > SSL_MAX_MASTER_KEY_LENGTH)
-		ret->master_key_length=SSL_MAX_MASTER_KEY_LENGTH;
-	else
-		ret->master_key_length=os.length;
-	memcpy(ret->master_key,os.data,ret->master_key_length);
+  if (a && *a) {
+    ret = *a;
+  } else {
+    ret = SSL_SESSION_new();
+    if (ret == NULL) {
+      goto err;
+    }
+  }
 
-	os.length=0;
+  CBS_init(&cbs, *pp, length);
+  if (!CBS_get_asn1(&cbs, &session, CBS_ASN1_SEQUENCE) ||
+      !CBS_get_asn1_uint64(&session, &version) ||
+      !CBS_get_asn1_uint64(&session, &ssl_version) ||
+      !CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) ||
+      !CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) ||
+      !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) ||
+      !CBS_get_optional_asn1_uint64(&session, &session_time, kTimeTag,
+                                    time(NULL)) ||
+      !CBS_get_optional_asn1_uint64(&session, &timeout, kTimeoutTag, 3) ||
+      !CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) ||
+      !CBS_get_optional_asn1_octet_string(&session, &sid_ctx, NULL,
+                                          kSessionIDContextTag) ||
+      !CBS_get_optional_asn1_uint64(&session, &verify_result, kVerifyResultTag,
+                                    X509_V_OK)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  if (!d2i_SSL_SESSION_get_string(&session, &ret->tlsext_hostname,
+                                  kHostNameTag) ||
+      !d2i_SSL_SESSION_get_string(&session, &ret->psk_identity_hint,
+                                  kPSKIdentityHintTag) ||
+      !d2i_SSL_SESSION_get_string(&session, &ret->psk_identity,
+                                  kPSKIdentityTag)) {
+    goto err;
+  }
+  if (!CBS_get_optional_asn1_uint64(&session, &ticket_lifetime_hint,
+                                    kTicketLifetimeHintTag, 0)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  if (!d2i_SSL_SESSION_get_octet_string(&session, &ret->tlsext_tick,
+                                        &ret->tlsext_ticklen, kTicketTag)) {
+    goto err;
+  }
+  if (!CBS_get_optional_asn1_octet_string(&session, &peer_sha256,
+                                          &has_peer_sha256, kPeerSHA256Tag) ||
+      !CBS_get_optional_asn1_octet_string(&session, &original_handshake_hash,
+                                          NULL, kOriginalHandshakeHashTag)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  if (!d2i_SSL_SESSION_get_octet_string(
+          &session, &ret->tlsext_signed_cert_timestamp_list,
+          &ret->tlsext_signed_cert_timestamp_list_length,
+          kSignedCertTimestampListTag) ||
+      !d2i_SSL_SESSION_get_octet_string(
+          &session, &ret->ocsp_response, &ret->ocsp_response_length,
+          kOCSPResponseTag)) {
+    goto err;
+  }
+  if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret,
+                                  kExtendedMasterSecretTag,
+                                  0 /* default to false */)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  ret->extended_master_secret = extended_master_secret;
 
-	/* [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.data != NULL) OPENSSL_free(os.data);
+  /* Ignore |version|. The structure version number is ignored. */
 
-	ai.length=0;
-	M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,1);
-	if (ai.data != NULL)
-		{
-		ret->time=ASN1_INTEGER_get(aip);
-		OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
-		}
-	else
-		ret->time=(unsigned long)time(NULL);
+  /* Only support SSLv3/TLS and DTLS. */
+  if ((ssl_version >> 8) != SSL3_VERSION_MAJOR &&
+      (ssl_version >> 8) != (DTLS1_VERSION >> 8)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_UNKNOWN_SSL_VERSION);
+    goto err;
+  }
+  ret->ssl_version = ssl_version;
 
-	ai.length=0;
-	M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,2);
-	if (ai.data != NULL)
-		{
-		ret->timeout=ASN1_INTEGER_get(aip);
-		OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
-		}
-	else
-		ret->timeout=3;
+  if (CBS_len(&cipher) != 2) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_CIPHER_CODE_WRONG_LENGTH);
+    goto err;
+  }
+  ret->cipher_id =
+      0x03000000L | (CBS_data(&cipher)[0] << 8L) | CBS_data(&cipher)[1];
+  ret->cipher = ssl3_get_cipher_by_value(ret->cipher_id & 0xffff);
+  if (ret->cipher == NULL) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_UNSUPPORTED_CIPHER);
+    goto err;
+  }
 
-	if (ret->peer != NULL)
-		{
-		X509_free(ret->peer);
-		ret->peer=NULL;
-		}
-	M_ASN1_D2I_get_EXP_opt(ret->peer,d2i_X509,3);
+  if (CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id));
+  ret->session_id_length = CBS_len(&session_id);
 
-	os.length=0;
-	os.data=NULL;
-	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,4);
+  if (CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key));
+  ret->master_key_length = CBS_len(&master_key);
 
-	if(os.data != NULL)
-	    {
-	    if (os.length > SSL_MAX_SID_CTX_LENGTH)
-		{
-		c.error=SSL_R_BAD_LENGTH;
-		c.line=__LINE__;
-		goto err;
-		}
-	    else
-		{
-		ret->sid_ctx_length=os.length;
-		memcpy(ret->sid_ctx,os.data,os.length);
-		}
-	    OPENSSL_free(os.data); os.data=NULL; os.length=0;
-	    }
-	else
-	    ret->sid_ctx_length=0;
+  if (session_time > LONG_MAX ||
+      timeout > LONG_MAX) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  ret->time = session_time;
+  ret->timeout = timeout;
 
-	ai.length=0;
-	M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,5);
-	if (ai.data != NULL)
-		{
-		ret->verify_result=ASN1_INTEGER_get(aip);
-		OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
-		}
-	else
-		ret->verify_result=X509_V_OK;
+  if (ret->peer != NULL) {
+    X509_free(ret->peer);
+    ret->peer = NULL;
+  }
+  if (has_peer) {
+    const uint8_t *ptr;
+    ptr = CBS_data(&peer);
+    ret->peer = d2i_X509(NULL, &ptr, CBS_len(&peer));
+    if (ret->peer == NULL) {
+      goto err;
+    }
+    if (ptr != CBS_data(&peer) + CBS_len(&peer)) {
+      OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+      goto err;
+    }
+  }
 
-	os.length=0;
-	os.data=NULL;
-	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6);
-	if (os.data)
-		{
-		ret->tlsext_hostname = BUF_strndup((char *)os.data, os.length);
-		OPENSSL_free(os.data);
-		os.data = NULL;
-		os.length = 0;
-		}
-	else
-		ret->tlsext_hostname=NULL;
+  if (CBS_len(&sid_ctx) > sizeof(ret->sid_ctx)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  memcpy(ret->sid_ctx, CBS_data(&sid_ctx), CBS_len(&sid_ctx));
+  ret->sid_ctx_length = CBS_len(&sid_ctx);
 
-	os.length=0;
-	os.data=NULL;
-	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7);
-	if (os.data)
-		{
-		ret->psk_identity_hint = BUF_strndup((char *)os.data, os.length);
-		OPENSSL_free(os.data);
-		os.data = NULL;
-		os.length = 0;
-		}
-	else
-		ret->psk_identity_hint=NULL;
+  if (verify_result > LONG_MAX ||
+      ticket_lifetime_hint > 0xffffffff) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  ret->verify_result = verify_result;
+  ret->tlsext_tick_lifetime_hint = ticket_lifetime_hint;
 
-	os.length=0;
-	os.data=NULL;
-	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8);
-	if (os.data)
-		{
-		ret->psk_identity = BUF_strndup((char *)os.data, os.length);
-		OPENSSL_free(os.data);
-		os.data = NULL;
-		os.length = 0;
-		}
-	else
-		ret->psk_identity=NULL;
+  if (has_peer_sha256) {
+    if (CBS_len(&peer_sha256) != sizeof(ret->peer_sha256)) {
+      OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+      goto err;
+    }
+    memcpy(ret->peer_sha256, CBS_data(&peer_sha256), sizeof(ret->peer_sha256));
+    ret->peer_sha256_valid = 1;
+  } else {
+    ret->peer_sha256_valid = 0;
+  }
 
-	ai.length=0;
-	M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,9);
-	if (ai.data != NULL)
-		{
-		ret->tlsext_tick_lifetime_hint=ASN1_INTEGER_get(aip);
-		OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
-		}
-	else if (ret->tlsext_ticklen && ret->session_id_length)
-		ret->tlsext_tick_lifetime_hint = -1;
-	else
-		ret->tlsext_tick_lifetime_hint=0;
-	os.length=0;
-	os.data=NULL;
-	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,10);
-	if (os.data)
-		{
-		ret->tlsext_tick = os.data;
-		ret->tlsext_ticklen = os.length;
-		os.data = NULL;
-		os.length = 0;
-		}
-	else
-		ret->tlsext_tick=NULL;
+  if (CBS_len(&original_handshake_hash) >
+      sizeof(ret->original_handshake_hash)) {
+    OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
+    goto err;
+  }
+  memcpy(ret->original_handshake_hash, CBS_data(&original_handshake_hash),
+         CBS_len(&original_handshake_hash));
+  ret->original_handshake_hash_len = CBS_len(&original_handshake_hash);
 
-	os.length=0;
-	os.data=NULL;
-	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,13);
-	if (os.data && os.length == sizeof(ret->peer_sha256))
-		{
-		memcpy(ret->peer_sha256, os.data, sizeof(ret->peer_sha256));
-		ret->peer_sha256_valid = 1;
-		OPENSSL_free(os.data);
-		os.data = NULL;
-		}
+  if (a) {
+    *a = ret;
+  }
+  *pp = CBS_data(&cbs);
+  return ret;
 
-	os.length=0;
-	os.data=NULL;
-	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,14);
-	if (os.data && os.length < (int)sizeof(ret->original_handshake_hash))
-		{
-		memcpy(ret->original_handshake_hash, os.data, os.length);
-		ret->original_handshake_hash_len = os.length;
-		OPENSSL_free(os.data);
-		os.data = NULL;
-		}
-
-	os.length = 0;
-	os.data = NULL;
-	M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 15);
-	if (os.data)
-		{
-		if (ret->tlsext_signed_cert_timestamp_list)
-			OPENSSL_free(ret->tlsext_signed_cert_timestamp_list);
-		ret->tlsext_signed_cert_timestamp_list = os.data;
-		ret->tlsext_signed_cert_timestamp_list_length = os.length;
-		os.data = NULL;
-		}
-
-	os.length = 0;
-	os.data = NULL;
-	M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 16);
-	if (os.data)
-		{
-		if (ret->ocsp_response)
-			OPENSSL_free(ret->ocsp_response);
-		ret->ocsp_response = os.data;
-		ret->ocsp_response_length = os.length;
-		os.data = NULL;
-		}
-
-
-	M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
-	}
+err:
+  if (a && *a != ret) {
+    SSL_SESSION_free(ret);
+  }
+  return NULL;
+}
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index 040a2db..97169f2 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -447,12 +447,6 @@
 			co_list[co_list_num].active = 0;
 			co_list[co_list_num].in_group = 0;
 			co_list_num++;
-#ifdef KSSL_DEBUG
-			printf("\t%d: %s %lx %lx %lx\n",i,c->name,c->id,c->algorithm_mkey,c->algorithm_auth);
-#endif	/* KSSL_DEBUG */
-			/*
-			if (!sk_push(ca_list,(char *)c)) goto err;
-			*/
 			}
 		}
 
@@ -1023,9 +1017,6 @@
 	 * it is used for allocation.
 	 */
 	num_of_ciphers = ssl_method->num_ciphers();
-#ifdef KSSL_DEBUG
-	printf("ssl_create_cipher_list() for %d ciphers\n", num_of_ciphers);
-#endif    /* KSSL_DEBUG */
 	co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * num_of_ciphers);
 	if (co_list == NULL)
 		{
@@ -1209,11 +1200,7 @@
 	const char *ver;
 	const char *kx,*au,*enc,*mac;
 	unsigned long alg_mkey,alg_auth,alg_enc,alg_mac,alg_ssl;
-#ifdef KSSL_DEBUG
-	static const char *format="%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s AL=%lx/%lx/%lx/%lx/%lx\n";
-#else
 	static const char *format="%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s\n";
-#endif /* KSSL_DEBUG */
 
 	alg_mkey = cipher->algorithm_mkey;
 	alg_auth = cipher->algorithm_auth;
@@ -1324,11 +1311,7 @@
 	else if (len < 128)
 		return("Buffer too small");
 
-#ifdef KSSL_DEBUG
-	BIO_snprintf(buf,len,format,cipher->name,ver,kx,au,enc,mac,alg_mkey,alg_auth,alg_enc,alg_mac,alg_ssl);
-#else
 	BIO_snprintf(buf,len,format,cipher->name,ver,kx,au,enc,mac);
-#endif /* KSSL_DEBUG */
 	return(buf);
 	}
 
diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c
index 0ba125b..b070b5f 100644
--- a/ssl/ssl_error.c
+++ b/ssl/ssl_error.c
@@ -39,6 +39,7 @@
   {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_new, 0), "SSL_SESSION_new"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_print_fp, 0), "SSL_SESSION_print_fp"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_set1_id_context, 0), "SSL_SESSION_set1_id_context"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_to_bytes_full, 0), "SSL_SESSION_to_bytes_full"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_dir_cert_subjects_to_stack, 0), "SSL_add_dir_cert_subjects_to_stack"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_file_cert_subjects_to_stack, 0), "SSL_add_file_cert_subjects_to_stack"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_check_private_key, 0), "SSL_check_private_key"},
@@ -70,6 +71,9 @@
   {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_write, 0), "SSL_write"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_authz_find_data, 0), "authz_find_data"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_check_suiteb_cipher_list, 0), "check_suiteb_cipher_list"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION, 0), "d2i_SSL_SESSION"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION_get_octet_string, 0), "d2i_SSL_SESSION_get_octet_string"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION_get_string, 0), "d2i_SSL_SESSION_get_string"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_do_dtls1_write, 0), "do_dtls1_write"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_do_ssl3_write, 0), "do_ssl3_write"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_accept, 0), "dtls1_accept"},
@@ -87,6 +91,7 @@
   {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_write_app_data_bytes, 0), "dtls1_write_app_data_bytes"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_fclose, 0), "fclose"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_fprintf, 0), "fprintf"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_i2d_SSL_SESSION, 0), "i2d_SSL_SESSION"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_printf, 0), "printf"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_read_authz, 0), "read_authz"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_accept, 0), "ssl23_accept"},
@@ -136,6 +141,7 @@
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_certificate, 0), "ssl3_send_client_certificate"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_hello, 0), "ssl3_send_client_hello"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_key_exchange, 0), "ssl3_send_client_key_exchange"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_new_session_ticket, 0), "ssl3_send_new_session_ticket"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_certificate, 0), "ssl3_send_server_certificate"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_hello, 0), "ssl3_send_server_hello"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_key_exchange, 0), "ssl3_send_server_key_exchange"},
@@ -320,6 +326,7 @@
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_PURPOSE), "INVALID_PURPOSE"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SERVERINFO_DATA), "INVALID_SERVERINFO_DATA"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SRP_USERNAME), "INVALID_SRP_USERNAME"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SSL_SESSION), "INVALID_SSL_SESSION"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_STATUS_RESPONSE), "INVALID_STATUS_RESPONSE"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TICKET_KEYS_LENGTH), "INVALID_TICKET_KEYS_LENGTH"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TRUST), "INVALID_TRUST"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index f7818ed..8357ff9 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1495,8 +1495,7 @@
 	return(p-q);
 	}
 
-STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs,
-					       STACK_OF(SSL_CIPHER) **skp)
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs)
 	{
 	CBS cipher_suites = *cbs;
 	const SSL_CIPHER *c;
@@ -1508,14 +1507,14 @@
 	if (CBS_len(&cipher_suites) % 2 != 0)
 		{
 		OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
-		return(NULL);
+		return NULL;
 		}
-	if ((skp == NULL) || (*skp == NULL))
-		sk=sk_SSL_CIPHER_new_null(); /* change perhaps later */
-	else
+
+	sk = sk_SSL_CIPHER_new_null();
+	if (sk == NULL)
 		{
-		sk= *skp;
-		sk_SSL_CIPHER_zero(sk);
+		OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE);
+		goto err;
 		}
 
 	if (!CBS_stow(&cipher_suites,
@@ -1535,10 +1534,10 @@
 			goto err;
 			}
 
-		/* Check for SCSV */
+		/* Check for SCSV. */
 		if (s->s3 && cipher_suite == (SSL3_CK_SCSV & 0xffff))
 			{
-			/* SCSV fatal if renegotiating */
+			/* SCSV is fatal if renegotiating. */
 			if (s->renegotiate)
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
@@ -1546,25 +1545,25 @@
 				goto err;
 				}
 			s->s3->send_connection_binding = 1;
-#ifdef OPENSSL_RI_DEBUG
-			fprintf(stderr, "SCSV received by server\n");
-#endif
 			continue;
 			}
 
-		/* Check for FALLBACK_SCSV */
-		if (s->s3 && cipher_suite == (SSL3_CK_FALLBACK_SCSV & 0xffff) &&
-			s->version < ssl_get_max_version(s))
+		/* Check for FALLBACK_SCSV. */
+		if (s->s3 && cipher_suite == (SSL3_CK_FALLBACK_SCSV & 0xffff))
 			{
-			OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_INAPPROPRIATE_FALLBACK);
-			ssl3_send_alert(s,SSL3_AL_FATAL,SSL3_AD_INAPPROPRIATE_FALLBACK);
-			goto err;
+			if (s->version < ssl_get_max_version(s))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_INAPPROPRIATE_FALLBACK);
+				ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_INAPPROPRIATE_FALLBACK);
+				goto err;
+				}
+			continue;
 			}
 
 		c = ssl3_get_cipher_by_value(cipher_suite);
 		if (c != NULL)
 			{
-			if (!sk_SSL_CIPHER_push(sk,c))
+			if (!sk_SSL_CIPHER_push(sk, c))
 				{
 				OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE);
 				goto err;
@@ -1572,13 +1571,12 @@
 			}
 		}
 
-	if (skp != NULL)
-		*skp=sk;
-	return(sk);
+	return sk;
+
 err:
-	if ((skp == NULL) || (*skp == NULL))
+	if (sk != NULL)
 		sk_SSL_CIPHER_free(sk);
-	return(NULL);
+	return NULL;
 	}
 
 
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 75c0ba8..c214b91 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -568,6 +568,11 @@
 
 #define FP_ICC  (int (*)(const void *,const void *))
 
+enum should_add_to_finished_hash {
+  add_to_finished_hash,
+  dont_add_to_finished_hash,
+};
+
 /* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff
  * It is a bit of a mess of functions, but hell, think of it as
  * an opaque structure :-) */
@@ -597,7 +602,9 @@
 	/* Set the handshake header */
 	void (*set_handshake_header)(SSL *s, int type, unsigned long len);
 	/* Write out handshake message */
-	int (*do_write)(SSL *s);
+	int (*do_write)(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash);
+	/* Add the current handshake message to the finished hash. */
+	void (*add_to_finished_hash)(SSL *s);
 	} SSL3_ENC_METHOD;
 
 #define SSL_HM_HEADER_LENGTH(s)	s->method->ssl3_enc->hhlen
@@ -605,7 +612,7 @@
 	(((unsigned char *)s->init_buf->data) + s->method->ssl3_enc->hhlen)
 #define ssl_set_handshake_header(s, htype, len) \
 	s->method->ssl3_enc->set_handshake_header(s, htype, len)
-#define ssl_do_write(s)  s->method->ssl3_enc->do_write(s)
+#define ssl_do_write(s)  s->method->ssl3_enc->do_write(s, add_to_finished_hash)
 
 /* Values for enc_flags */
 
@@ -768,8 +775,7 @@
 int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx);
 int ssl_cipher_id_cmp(const void *in_a, const void *in_b);
 int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **ap, const SSL_CIPHER **bp);
-STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs,
-					       STACK_OF(SSL_CIPHER) **skp);
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs);
 int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p);
 STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth,
 					     struct ssl_cipher_preference_list_st **pref,
@@ -824,7 +830,7 @@
 int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
 int ssl3_change_cipher_state(SSL *s,int which);
 void ssl3_cleanup_key_block(SSL *s);
-int ssl3_do_write(SSL *s,int type);
+int ssl3_do_write(SSL *s,int type, enum should_add_to_finished_hash should_add_to_finished_hash);
 int ssl3_send_alert(SSL *s,int level, int desc);
 int ssl3_generate_master_secret(SSL *s, unsigned char *out,
 	unsigned char *p, int len);
@@ -866,7 +872,13 @@
 int	ssl3_setup_write_buffer(SSL *s);
 int	ssl3_release_read_buffer(SSL *s);
 int	ssl3_release_write_buffer(SSL *s);
-int	ssl3_digest_cached_records(SSL *s);
+
+enum should_free_handshake_buffer_t {
+	free_handshake_buffer,
+	dont_free_handshake_buffer,
+};
+int	ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t);
+
 int	ssl3_new(SSL *s);
 void	ssl3_free(SSL *s);
 int	ssl3_accept(SSL *s);
@@ -886,13 +898,14 @@
 int ssl3_do_change_cipher_spec(SSL *ssl);
 
 void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len);
-int ssl3_handshake_write(SSL *s);
+int ssl3_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash);
+void ssl3_add_to_finished_hash(SSL *s);
 
 int ssl23_read(SSL *s, void *buf, int len);
 int ssl23_peek(SSL *s, void *buf, int len);
 int ssl23_write(SSL *s, const void *buf, int len);
 
-int dtls1_do_write(SSL *s,int type);
+int dtls1_do_write(SSL *s,int type, enum should_add_to_finished_hash should_add_to_finished_hash);
 int ssl3_read_n(SSL *s, int n, int max, int extend);
 int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek);
 int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
diff --git a/ssl/ssl_test.c b/ssl/ssl_test.c
index a202273..da9ba4b 100644
--- a/ssl/ssl_test.c
+++ b/ssl/ssl_test.c
@@ -307,20 +307,6 @@
  * 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"
@@ -355,18 +341,16 @@
   return 1;
 }
 
-static int test_ssl_session_asn1(const char *input_b64,
-                                 const char *expected_b64) {
+static int test_ssl_session_asn1(const char *input_b64) {
   int ret = 0, len;
-  size_t input_len, expected_len;
-  uint8_t *input = NULL, *expected = NULL, *encoded = NULL;
+  size_t input_len, encoded_len;
+  uint8_t *input = 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)) {
+  if (!decode_base64(&input, &input_len, input_b64)) {
     goto done;
   }
 
@@ -379,28 +363,41 @@
   }
 
   /* Verify the SSL_SESSION encoding round-trips. */
+  if (!SSL_SESSION_to_bytes(session, &encoded, &encoded_len)) {
+    fprintf(stderr, "SSL_SESSION_to_bytes failed\n");
+    goto done;
+  }
+  if (encoded_len != input_len ||
+      memcmp(input, encoded, input_len) != 0) {
+    fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n");
+    goto done;
+  }
+  OPENSSL_free(encoded);
+  encoded = NULL;
+
+  /* Verify the SSL_SESSION encoding round-trips via the legacy API. */
   len = i2d_SSL_SESSION(session, NULL);
-  if (len < 0 || (size_t)len != expected_len) {
+  if (len < 0 || (size_t)len != input_len) {
     fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n");
     goto done;
   }
 
-  encoded = OPENSSL_malloc(expected_len);
+  encoded = OPENSSL_malloc(input_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) {
+  if (len < 0 || (size_t)len != input_len) {
     fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n");
     goto done;
   }
-  if (ptr != encoded + expected_len) {
+  if (ptr != encoded + input_len) {
     fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n");
     goto done;
   }
-  if (memcmp(expected, encoded, expected_len) != 0) {
+  if (memcmp(input, encoded, input_len) != 0) {
     fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n");
     goto done;
   }
@@ -418,9 +415,6 @@
   if (input) {
     OPENSSL_free(input);
   }
-  if (expected) {
-    OPENSSL_free(expected);
-  }
   if (encoded) {
     OPENSSL_free(encoded);
   }
@@ -431,9 +425,8 @@
   SSL_library_init();
 
   if (!test_cipher_rules() ||
-      !test_ssl_session_asn1(kOpenSSLSession, kOpenSSLSession) ||
-      !test_ssl_session_asn1(kCustomSession, kCustomSession2) ||
-      !test_ssl_session_asn1(kCustomSession2, kCustomSession2)) {
+      !test_ssl_session_asn1(kOpenSSLSession) ||
+      !test_ssl_session_asn1(kCustomSession)) {
     return 1;
   }
 
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index dd00d0a..6803e9b 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -152,8 +152,6 @@
 			const void *seed1, int seed1_len,
 			const void *seed2, int seed2_len,
 			const void *seed3, int seed3_len,
-			const void *seed4, int seed4_len,
-			const void *seed5, int seed5_len,
 			unsigned char *out, int olen)
 	{
 	int chunk;
@@ -182,10 +180,6 @@
 		goto err;
 	if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
 		goto err;
-	if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
-		goto err;
-	if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
-		goto err;
 	A1_len = EVP_MAX_MD_SIZE;
 	if (!EVP_DigestSignFinal(&ctx,A1,&A1_len))
 		goto err;
@@ -205,10 +199,6 @@
 			goto err;
 		if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
 			goto err;
-		if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
-			goto err;
-		if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
-			goto err;
 
 		if (olen > chunk)
 			{
@@ -246,8 +236,6 @@
 		     const void *seed1, int seed1_len,
 		     const void *seed2, int seed2_len,
 		     const void *seed3, int seed3_len,
-		     const void *seed4, int seed4_len,
-		     const void *seed5, int seed5_len,
 		     const unsigned char *sec, int slen,
 		     unsigned char *out1,
 		     unsigned char *out2, int olen)
@@ -275,7 +263,7 @@
 				goto err;				
 			}
 			if (!tls1_P_hash(md ,S1,len+(slen&1),
-					seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
+					seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,
 					out2,olen))
 				goto err;
 			S1+=len;
@@ -298,20 +286,8 @@
 		 TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
 		 s->s3->server_random,SSL3_RANDOM_SIZE,
 		 s->s3->client_random,SSL3_RANDOM_SIZE,
-		 NULL,0,NULL,0,
 		 s->session->master_key,s->session->master_key_length,
 		 km,tmp,num);
-#ifdef KSSL_DEBUG
-	printf("tls1_generate_key_block() ==> %d byte master_key =\n\t",
-                s->session->master_key_length);
-	{
-        int i;
-        for (i=0; i < s->session->master_key_length; i++)
-                {
-                printf("%02X", s->session->master_key[i]);
-                }
-        printf("\n");  }
-#endif    /* KSSL_DEBUG */
 	return ret;
 	}
 
@@ -625,9 +601,6 @@
 	int ret=0;
 	unsigned key_len, iv_len;
 
-#ifdef KSSL_DEBUG
-	printf ("tls1_setup_key_block()\n");
-#endif	/* KSSL_DEBUG */
 
 	if (s->s3->tmp.key_block_length != 0)
 		return(1);
@@ -926,10 +899,6 @@
 			enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
 		}
 
-#ifdef KSSL_DEBUG
-	printf("tls1_enc(%d)\n", send);
-#endif    /* KSSL_DEBUG */
-
 	if ((s->session == NULL) || (ds == NULL) || (enc == NULL))
 		{
 		memmove(rec->data,rec->input,rec->length);
@@ -955,24 +924,6 @@
 			rec->length+=i;
 			}
 
-#ifdef KSSL_DEBUG
-		{
-		unsigned long ui;
-		printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n",
-			ds,rec->data,rec->input,l);
-		printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n",
-			ds->buf_len, ds->cipher->key_len,
-			DES_KEY_SZ, DES_SCHEDULE_SZ,
-			ds->cipher->iv_len);
-		printf("\t\tIV: ");
-		for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]);
-		printf("\n");
-		printf("\trec->input=");
-		for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]);
-		printf("\n");
-		}
-#endif	/* KSSL_DEBUG */
-
 		if (!send)
 			{
 			if (l == 0 || l%bs != 0)
@@ -985,15 +936,6 @@
 						:(i==0))
 			return -1;	/* AEAD can fail to verify MAC */
 
-#ifdef KSSL_DEBUG
-		{
-		unsigned long i;
-		printf("\trec->data=");
-		for (i=0; i<l; i++)
-			printf(" %02x", rec->data[i]);  printf("\n");
-		}
-#endif	/* KSSL_DEBUG */
-
 		ret = 1;
 		if (EVP_MD_CTX_md(s->read_hash) != NULL)
 			mac_size = EVP_MD_CTX_size(s->read_hash);
@@ -1011,8 +953,8 @@
 	EVP_MD_CTX ctx, *d=NULL;
 	int i;
 
-	if (s->s3->handshake_buffer) 
-		if (!ssl3_digest_cached_records(s))
+	if (s->s3->handshake_buffer)
+		if (!ssl3_digest_cached_records(s, free_handshake_buffer))
 			return 0;
 
 	for (i=0;i<SSL_MAX_DIGEST;i++) 
@@ -1093,7 +1035,7 @@
 	int digests_len;
 
 	if (s->s3->handshake_buffer)
-		if (!ssl3_digest_cached_records(s))
+		if (!ssl3_digest_cached_records(s, free_handshake_buffer))
 			return 0;
 
 	digests_len = tls1_handshake_digest(s, buf, sizeof(buf));
@@ -1104,7 +1046,7 @@
 		}
 		
 	if (!tls1_PRF(ssl_get_algorithm2(s),
-			str,slen, buf, digests_len, NULL,0, NULL,0, NULL,0,
+			str,slen, buf, digests_len, NULL,0,
 			s->session->master_key,s->session->master_key_length,
 			out,buf2,sizeof buf2))
 		err = 1;
@@ -1212,22 +1154,53 @@
 	     int len)
 	{
 	unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
-	const void *co = NULL, *so = NULL;
-	int col = 0, sol = 0;
 
+	if (s->s3->tmp.extended_master_secret)
+		{
+		uint8_t digests[2*EVP_MAX_MD_SIZE];
+		int digests_len;
 
-#ifdef KSSL_DEBUG
-	printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
-#endif	/* KSSL_DEBUG */
+		if (s->s3->handshake_buffer)
+			{
+			/* The master secret is based on the handshake hash
+			 * just after sending the ClientKeyExchange. However,
+			 * we might have a client certificate to send, in which
+			 * case we might need different hashes for the
+			 * verification and thus still need the handshake
+			 * buffer around. Keeping both a handshake buffer *and*
+			 * running hashes isn't yet supported so, when it comes
+			 * to calculating the Finished hash, we'll have to hash
+			 * the handshake buffer again. */
+			if (!ssl3_digest_cached_records(s, dont_free_handshake_buffer))
+				return 0;
+			}
 
-	tls1_PRF(ssl_get_algorithm2(s),
-		TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
-		s->s3->client_random,SSL3_RANDOM_SIZE,
-		co, col,
-		s->s3->server_random,SSL3_RANDOM_SIZE,
-		so, sol,
-		p,len,
-		s->session->master_key,buff,sizeof buff);
+		digests_len = tls1_handshake_digest(s, digests, sizeof(digests));
+
+		if (digests_len == -1)
+			{
+			return 0;
+			}
+
+		tls1_PRF(ssl_get_algorithm2(s),
+			TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+			TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE,
+			digests, digests_len,
+			NULL, 0,
+			p, len,
+			s->session->master_key,
+			buff, sizeof(buff));
+		}
+	else
+		{
+		tls1_PRF(ssl_get_algorithm2(s),
+			TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
+			s->s3->client_random,SSL3_RANDOM_SIZE,
+			s->s3->server_random,SSL3_RANDOM_SIZE,
+			p, len,
+			s->session->master_key,buff,sizeof buff);
+		}
+
 #ifdef SSL_DEBUG
 	fprintf(stderr, "Premaster Secret:\n");
 	BIO_dump_fp(stderr, (char *)p, len);
@@ -1257,9 +1230,6 @@
 		}
 #endif
 
-#ifdef KSSL_DEBUG
-	printf ("tls1_generate_master_secret() complete\n");
-#endif	/* KSSL_DEBUG */
 	return(SSL3_MASTER_SECRET_SIZE);
 	}
 
@@ -1272,10 +1242,6 @@
 	size_t vallen, currentvalpos;
 	int rv;
 
-#ifdef KSSL_DEBUG
-	printf ("tls1_export_keying_material(%p,%p,%d,%s,%d,%p,%d)\n", s, out, olen, label, llen, p, plen);
-#endif	/* KSSL_DEBUG */
-
 	buff = OPENSSL_malloc(olen);
 	if (buff == NULL) goto err2;
 
@@ -1330,14 +1296,9 @@
 		      val, vallen,
 		      NULL, 0,
 		      NULL, 0,
-		      NULL, 0,
-		      NULL, 0,
 		      s->session->master_key,s->session->master_key_length,
 		      out,buff,olen);
 
-#ifdef KSSL_DEBUG
-	printf ("tls1_export_keying_material() complete\n");
-#endif	/* KSSL_DEBUG */
 	goto ret;
 err1:
 	OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL);
@@ -1387,10 +1348,6 @@
 	case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(TLS1_AD_BAD_CERTIFICATE_HASH_VALUE);
 	case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY);
 	case SSL_AD_INAPPROPRIATE_FALLBACK:return(SSL3_AD_INAPPROPRIATE_FALLBACK);
-#if 0 /* not appropriate for TLS, not used for DTLS */
-	case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return 
-					  (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
-#endif
 	default:			return(-1);
 		}
 	}
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 4b13cfe..0972515 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -140,7 +140,8 @@
 	0,
 	SSL3_HM_HEADER_LENGTH,
 	ssl3_set_handshake_header,
-	ssl3_handshake_write
+	ssl3_handshake_write,
+	ssl3_add_to_finished_hash,
 	};
 
 SSL3_ENC_METHOD TLSv1_1_enc_data={
@@ -159,7 +160,8 @@
 	SSL_ENC_FLAG_EXPLICIT_IV,
 	SSL3_HM_HEADER_LENGTH,
 	ssl3_set_handshake_header,
-	ssl3_handshake_write
+	ssl3_handshake_write,
+	ssl3_add_to_finished_hash,
 	};
 
 SSL3_ENC_METHOD TLSv1_2_enc_data={
@@ -179,7 +181,8 @@
 		|SSL_ENC_FLAG_TLS1_2_CIPHERS,
 	SSL3_HM_HEADER_LENGTH,
 	ssl3_set_handshake_header,
-	ssl3_handshake_write
+	ssl3_handshake_write,
+	ssl3_add_to_finished_hash,
 	};
 
 static int compare_uint16_t(const void *p1, const void *p2)
@@ -978,6 +981,15 @@
           ret += el;
         }
 
+	/* Add extended master secret. */
+	if (s->version != SSL3_VERSION)
+		{
+		if (limit - ret - 4 < 0)
+			return NULL;
+		s2n(TLSEXT_TYPE_extended_master_secret,ret);
+		s2n(0,ret);
+		}
+
 	if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
 		{
 		int ticklen;
@@ -1246,6 +1258,14 @@
           ret += el;
         }
 
+	if (s->s3->tmp.extended_master_secret)
+		{
+		if ((long)(limit - ret - 4) < 0) return NULL;
+
+		s2n(TLSEXT_TYPE_extended_master_secret,ret);
+		s2n(0,ret);
+		}
+
 	if (using_ecc)
 		{
 		const unsigned char *plist;
@@ -1423,6 +1443,7 @@
 	s->should_ack_sni = 0;
 	s->s3->next_proto_neg_seen = 0;
 	s->s3->tmp.certificate_status_expected = 0;
+	s->s3->tmp.extended_master_secret = 0;
 
 	if (s->s3->alpn_selected)
 		{
@@ -1782,6 +1803,18 @@
 			if (!ssl_parse_clienthello_use_srtp_ext(s, &extension, out_alert))
 				return 0;
                         }
+
+		else if (type == TLSEXT_TYPE_extended_master_secret &&
+			 s->version != SSL3_VERSION)
+			{
+			if (CBS_len(&extension) != 0)
+				{
+				*out_alert = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			s->s3->tmp.extended_master_secret = 1;
+			}
 		}
 
 	ri_check:
@@ -1851,6 +1884,7 @@
 
 	s->tlsext_ticket_expected = 0;
 	s->s3->tmp.certificate_status_expected = 0;
+	s->s3->tmp.extended_master_secret = 0;
 
 	if (s->s3->alpn_selected)
 		{
@@ -2086,6 +2120,20 @@
                         if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert))
                                 return 0;
                         }
+
+		else if (type == TLSEXT_TYPE_extended_master_secret)
+			{
+			if (/* It is invalid for the server to select EMS and
+			       SSLv3. */
+			    s->version == SSL3_VERSION ||
+			    CBS_len(&extension) != 0)
+				{
+				*out_alert = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			s->s3->tmp.extended_master_secret = 1;
+			}
 		}
 
 	if (!s->hit && tlsext_servername == 1)
@@ -2779,7 +2827,7 @@
 	static const char kClientIDMagic[] = "TLS Channel ID signature";
 
 	if (s->s3->handshake_buffer)
-		if (!ssl3_digest_cached_records(s))
+		if (!ssl3_digest_cached_records(s, free_handshake_buffer))
 			return 0;
 
 	EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic));
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 6b27e26..ce2a3da 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -25,6 +25,7 @@
 #include <sys/types.h>
 
 #include <openssl/bio.h>
+#include <openssl/buf.h>
 #include <openssl/bytestring.h>
 #include <openssl/ssl.h>
 
@@ -180,6 +181,48 @@
   return 1;
 }
 
+static unsigned psk_client_callback(SSL *ssl, const char *hint,
+                                    char *out_identity,
+                                    unsigned max_identity_len,
+                                    uint8_t *out_psk, unsigned max_psk_len) {
+  const TestConfig *config = GetConfigPtr(ssl);
+
+  if (strcmp(hint ? hint : "", config->psk_identity.c_str()) != 0) {
+    fprintf(stderr, "Server PSK hint did not match.\n");
+    return 0;
+  }
+
+  // Account for the trailing '\0' for the identity.
+  if (config->psk_identity.size() >= max_identity_len ||
+      config->psk.size() > max_psk_len) {
+    fprintf(stderr, "PSK buffers too small\n");
+    return 0;
+  }
+
+  BUF_strlcpy(out_identity, config->psk_identity.c_str(),
+              max_identity_len);
+  memcpy(out_psk, config->psk.data(), config->psk.size());
+  return config->psk.size();
+}
+
+static unsigned psk_server_callback(SSL *ssl, const char *identity,
+                                    uint8_t *out_psk, unsigned max_psk_len) {
+  const TestConfig *config = GetConfigPtr(ssl);
+
+  if (strcmp(identity, config->psk_identity.c_str()) != 0) {
+    fprintf(stderr, "Client PSK identity did not match.\n");
+    return 0;
+  }
+
+  if (config->psk.size() > max_psk_len) {
+    fprintf(stderr, "PSK buffers too small\n");
+    return 0;
+  }
+
+  memcpy(out_psk, config->psk.data(), config->psk.size());
+  return config->psk.size();
+}
+
 static SSL_CTX *setup_ctx(const TestConfig *config) {
   SSL_CTX *ssl_ctx = NULL;
   DH *dh = NULL;
@@ -369,6 +412,16 @@
     SSL_set_alpn_protos(ssl, (const uint8_t *)config->advertise_alpn.data(),
                         config->advertise_alpn.size());
   }
+  if (!config->psk.empty()) {
+    SSL_set_psk_client_callback(ssl, psk_client_callback);
+    SSL_set_psk_server_callback(ssl, psk_server_callback);
+  }
+  if (!config->psk_identity.empty()) {
+    if (!SSL_use_psk_identity_hint(ssl, config->psk_identity.c_str())) {
+      BIO_print_errors_fp(stdout);
+      return 1;
+    }
+  }
 
   BIO *bio = BIO_new_fd(fd, 1 /* take ownership */);
   if (bio == NULL) {
@@ -482,6 +535,37 @@
     }
   }
 
+  if (config->expect_extended_master_secret) {
+    if (!ssl->session->extended_master_secret) {
+      fprintf(stderr, "No EMS for session when expected");
+      return 2;
+    }
+  }
+
+  if (config->renegotiate) {
+    if (config->async) {
+      fprintf(stderr, "--renegotiate is not supported with --async.\n");
+      return 2;
+    }
+
+    SSL_renegotiate(ssl);
+
+    ret = SSL_do_handshake(ssl);
+    if (ret != 1) {
+      SSL_free(ssl);
+      BIO_print_errors_fp(stdout);
+      return 2;
+    }
+
+    SSL_set_state(ssl, SSL_ST_ACCEPT);
+    ret = SSL_do_handshake(ssl);
+    if (ret != 1) {
+      SSL_free(ssl);
+      BIO_print_errors_fp(stdout);
+      return 2;
+    }
+  }
+
   if (config->write_different_record_sizes) {
     if (config->is_dtls) {
       fprintf(stderr, "write_different_record_sizes not supported for DTLS\n");
diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go
index 6cd0de9..5a3ac80 100644
--- a/ssl/test/runner/cipher_suites.go
+++ b/ssl/test/runner/cipher_suites.go
@@ -57,6 +57,9 @@
 	// suiteNoDTLS indicates that the cipher suite cannot be used
 	// in DTLS.
 	suiteNoDTLS
+	// suitePSK indicates that the cipher suite authenticates with
+	// a pre-shared key rather than a server private key.
+	suitePSK
 )
 
 // A cipherSuite is a specific combination of key agreement, cipher and MAC
@@ -109,6 +112,10 @@
 	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
 	{TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, dheRSAKA, 0, cipher3DES, macSHA1, nil},
 	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
+	{TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdhePSKKA, suiteECDHE | suiteTLS12 | suitePSK, nil, nil, aeadAESGCM},
+	{TLS_PSK_WITH_RC4_128_SHA, 16, 20, 0, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil},
+	{TLS_PSK_WITH_AES_128_CBC_SHA, 16, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil},
+	{TLS_PSK_WITH_AES_256_CBC_SHA, 32, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil},
 }
 
 func cipherRC4(key, iv []byte, isRead bool) interface{} {
@@ -287,7 +294,7 @@
 
 func ecdheECDSAKA(version uint16) keyAgreement {
 	return &ecdheKeyAgreement{
-		signedKeyAgreement: signedKeyAgreement{
+		auth: &signedKeyAgreement{
 			sigType: signatureECDSA,
 			version: version,
 		},
@@ -296,7 +303,7 @@
 
 func ecdheRSAKA(version uint16) keyAgreement {
 	return &ecdheKeyAgreement{
-		signedKeyAgreement: signedKeyAgreement{
+		auth: &signedKeyAgreement{
 			sigType: signatureRSA,
 			version: version,
 		},
@@ -305,13 +312,27 @@
 
 func dheRSAKA(version uint16) keyAgreement {
 	return &dheKeyAgreement{
-		signedKeyAgreement: signedKeyAgreement{
+		auth: &signedKeyAgreement{
 			sigType: signatureRSA,
 			version: version,
 		},
 	}
 }
 
+func pskKA(version uint16) keyAgreement {
+	return &pskKeyAgreement{
+		base: &nilKeyAgreement{},
+	}
+}
+
+func ecdhePSKKA(version uint16) keyAgreement {
+	return &pskKeyAgreement{
+		base: &ecdheKeyAgreement{
+			auth: &nilKeyAgreementAuthentication{},
+		},
+	}
+}
+
 // mutualCipherSuite returns a cipherSuite given a list of supported
 // ciphersuites and the id requested by the peer.
 func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
@@ -343,6 +364,9 @@
 	TLS_RSA_WITH_AES_256_CBC_SHA256         uint16 = 0x003d
 	TLS_DHE_RSA_WITH_AES_128_CBC_SHA256     uint16 = 0x0067
 	TLS_DHE_RSA_WITH_AES_256_CBC_SHA256     uint16 = 0x006b
+	TLS_PSK_WITH_RC4_128_SHA                uint16 = 0x008a
+	TLS_PSK_WITH_AES_128_CBC_SHA            uint16 = 0x008c
+	TLS_PSK_WITH_AES_256_CBC_SHA            uint16 = 0x008d
 	TLS_RSA_WITH_AES_128_GCM_SHA256         uint16 = 0x009c
 	TLS_RSA_WITH_AES_256_GCM_SHA384         uint16 = 0x009d
 	TLS_DHE_RSA_WITH_AES_128_GCM_SHA256     uint16 = 0x009e
@@ -364,3 +388,8 @@
 	TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384   uint16 = 0xc030
 	fallbackSCSV                            uint16 = 0x5600
 )
+
+// Additional cipher suite IDs, not IANA-assigned.
+const (
+	TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0xcafe
+)
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 8b2c750..6f146af 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -48,6 +48,7 @@
 
 // TLS handshake message types.
 const (
+	typeHelloRequest        uint8 = 0
 	typeClientHello         uint8 = 1
 	typeServerHello         uint8 = 2
 	typeHelloVerifyRequest  uint8 = 3
@@ -71,16 +72,17 @@
 
 // TLS extension numbers
 const (
-	extensionServerName          uint16 = 0
-	extensionStatusRequest       uint16 = 5
-	extensionSupportedCurves     uint16 = 10
-	extensionSupportedPoints     uint16 = 11
-	extensionSignatureAlgorithms uint16 = 13
-	extensionALPN                uint16 = 16
-	extensionSessionTicket       uint16 = 35
-	extensionNextProtoNeg        uint16 = 13172 // not IANA assigned
-	extensionRenegotiationInfo   uint16 = 0xff01
-	extensionChannelID           uint16 = 30032 // not IANA assigned
+	extensionServerName           uint16 = 0
+	extensionStatusRequest        uint16 = 5
+	extensionSupportedCurves      uint16 = 10
+	extensionSupportedPoints      uint16 = 11
+	extensionSignatureAlgorithms  uint16 = 13
+	extensionALPN                 uint16 = 16
+	extensionExtendedMasterSecret uint16 = 23
+	extensionSessionTicket        uint16 = 35
+	extensionNextProtoNeg         uint16 = 13172 // not IANA assigned
+	extensionRenegotiationInfo    uint16 = 0xff01
+	extensionChannelID            uint16 = 30032 // not IANA assigned
 )
 
 // TLS signaling cipher suite values
@@ -189,12 +191,13 @@
 // ClientSessionState contains the state needed by clients to resume TLS
 // sessions.
 type ClientSessionState struct {
-	sessionTicket      []uint8             // Encrypted ticket used for session resumption with server
-	vers               uint16              // SSL/TLS version negotiated for the session
-	cipherSuite        uint16              // Ciphersuite negotiated for the session
-	masterSecret       []byte              // MasterSecret generated by client on a full handshake
-	handshakeHash      []byte              // Handshake hash for Channel ID purposes.
-	serverCertificates []*x509.Certificate // Certificate chain presented by the server
+	sessionTicket        []uint8             // Encrypted ticket used for session resumption with server
+	vers                 uint16              // SSL/TLS version negotiated for the session
+	cipherSuite          uint16              // Ciphersuite negotiated for the session
+	masterSecret         []byte              // MasterSecret generated by client on a full handshake
+	handshakeHash        []byte              // Handshake hash for Channel ID purposes.
+	serverCertificates   []*x509.Certificate // Certificate chain presented by the server
+	extendedMasterSecret bool                // Whether an extended master secret was used to generate the session
 }
 
 // ClientSessionCache is a cache of ClientSessionState objects that can be used
@@ -323,6 +326,14 @@
 	// returned in the ConnectionState.
 	RequestChannelID bool
 
+	// PreSharedKey, if not nil, is the pre-shared key to use with
+	// the PSK cipher suites.
+	PreSharedKey []byte
+
+	// PreSharedKeyIdentity, if not empty, is the identity to use
+	// with the PSK cipher suites.
+	PreSharedKeyIdentity string
+
 	// Bugs specifies optional misbehaviour to be used for testing other
 	// implementations.
 	Bugs ProtocolBugs
@@ -472,6 +483,22 @@
 	// OversizedSessionId causes the session id that is sent with a ticket
 	// resumption attempt to be too large (33 bytes).
 	OversizedSessionId bool
+
+	// RequireExtendedMasterSecret, if true, requires that the peer support
+	// the extended master secret option.
+	RequireExtendedMasterSecret bool
+
+	// NoExtendedMasterSecret causes the client and server to behave is if
+	// they didn't support an extended master secret.
+	NoExtendedMasterSecret bool
+
+	// EmptyRenegotiationInfo causes the renegotiation extension to be
+	// empty in a renegotiation handshake.
+	EmptyRenegotiationInfo bool
+
+	// BadRenegotiationInfo causes the renegotiation extension value in a
+	// renegotiation handshake to be incorrect.
+	BadRenegotiationInfo bool
 }
 
 func (c *Config) serverInit() {
@@ -727,9 +754,10 @@
 }
 
 func initDefaultCipherSuites() {
-	varDefaultCipherSuites = make([]uint16, len(cipherSuites))
-	for i, suite := range cipherSuites {
-		varDefaultCipherSuites[i] = suite.id
+	for _, suite := range cipherSuites {
+		if suite.flags&suitePSK == 0 {
+			varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
+		}
 	}
 }
 
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 9f0c328..e76f9d1 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -29,16 +29,17 @@
 	isClient bool
 
 	// constant after handshake; protected by handshakeMutex
-	handshakeMutex    sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
-	handshakeErr      error      // error resulting from handshake
-	vers              uint16     // TLS version
-	haveVers          bool       // version has been negotiated
-	config            *Config    // configuration passed to constructor
-	handshakeComplete bool
-	didResume         bool // whether this connection was a session resumption
-	cipherSuite       uint16
-	ocspResponse      []byte // stapled OCSP response
-	peerCertificates  []*x509.Certificate
+	handshakeMutex       sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+	handshakeErr         error      // error resulting from handshake
+	vers                 uint16     // TLS version
+	haveVers             bool       // version has been negotiated
+	config               *Config    // configuration passed to constructor
+	handshakeComplete    bool
+	didResume            bool // whether this connection was a session resumption
+	extendedMasterSecret bool // whether this session used an extended master secret
+	cipherSuite          uint16
+	ocspResponse         []byte // stapled OCSP response
+	peerCertificates     []*x509.Certificate
 	// verifiedChains contains the certificate chains that we built, as
 	// opposed to the ones presented by the server.
 	verifiedChains [][]*x509.Certificate
@@ -49,6 +50,10 @@
 	clientProtocolFallback bool
 	usedALPN               bool
 
+	// verify_data values for the renegotiation extension.
+	clientVerify []byte
+	serverVerify []byte
+
 	channelID *ecdsa.PublicKey
 
 	// input/output
@@ -128,9 +133,10 @@
 }
 
 func (hc *halfConn) error() error {
-	hc.Lock()
+	// This should be locked, but I've removed it for the renegotiation
+	// tests since we don't concurrently read and write the same tls.Conn
+	// in any case during testing.
 	err := hc.err
-	hc.Unlock()
 	return err
 }
 
@@ -650,7 +656,7 @@
 func (c *Conn) readRecord(want recordType) error {
 	// Caller must be in sync with connection:
 	// handshake data if handshake not yet completed,
-	// else application data.  (We don't support renegotiation.)
+	// else application data.
 	switch want {
 	default:
 		c.sendAlert(alertInternalError)
@@ -724,7 +730,12 @@
 	case recordTypeHandshake:
 		// TODO(rsc): Should at least pick off connection close.
 		if typ != want {
-			return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
+			// A client might need to process a HelloRequest from
+			// the server, thus receiving a handshake message when
+			// application data is expected is ok.
+			if !c.isClient {
+				return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
+			}
 		}
 		c.hand.Write(data)
 	}
@@ -907,6 +918,8 @@
 
 	var m handshakeMessage
 	switch data[0] {
+	case typeHelloRequest:
+		m = new(helloRequestMsg)
 	case typeClientHello:
 		m = &clientHelloMsg{
 			isDTLS: c.isDTLS,
@@ -999,6 +1012,35 @@
 	return n + m, c.out.setErrorLocked(err)
 }
 
+func (c *Conn) handleRenegotiation() error {
+	c.handshakeComplete = false
+	if !c.isClient {
+		panic("renegotiation should only happen for a client")
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	_, ok := msg.(*helloRequestMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return alertUnexpectedMessage
+	}
+
+	return c.Handshake()
+}
+
+func (c *Conn) Renegotiate() error {
+	if !c.isClient {
+		helloReq := new(helloRequestMsg)
+		c.writeRecord(recordTypeHandshake, helloReq.marshal())
+	}
+
+	c.handshakeComplete = false
+	return c.Handshake()
+}
+
 // Read can be made to time out and return a net.Error with Timeout() == true
 // after a fixed time limit; see SetDeadline and SetReadDeadline.
 func (c *Conn) Read(b []byte) (n int, err error) {
@@ -1018,6 +1060,14 @@
 				// Soft error, like EAGAIN
 				return 0, err
 			}
+			if c.hand.Len() > 0 {
+				// We received handshake bytes, indicating the
+				// start of a renegotiation.
+				if err := c.handleRenegotiation(); err != nil {
+					return 0, err
+				}
+				continue
+			}
 		}
 		if err := c.in.err; err != nil {
 			return 0, err
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index f4cadc2..0c5192f 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -56,26 +56,40 @@
 	}
 
 	hello := &clientHelloMsg{
-		isDTLS:              c.isDTLS,
-		vers:                c.config.maxVersion(),
-		compressionMethods:  []uint8{compressionNone},
-		random:              make([]byte, 32),
-		ocspStapling:        true,
-		serverName:          c.config.ServerName,
-		supportedCurves:     c.config.curvePreferences(),
-		supportedPoints:     []uint8{pointFormatUncompressed},
-		nextProtoNeg:        len(c.config.NextProtos) > 0,
-		secureRenegotiation: true,
-		alpnProtocols:       c.config.NextProtos,
-		duplicateExtension:  c.config.Bugs.DuplicateExtension,
-		channelIDSupported:  c.config.ChannelID != nil,
-		npnLast:             c.config.Bugs.SwapNPNAndALPN,
+		isDTLS:               c.isDTLS,
+		vers:                 c.config.maxVersion(),
+		compressionMethods:   []uint8{compressionNone},
+		random:               make([]byte, 32),
+		ocspStapling:         true,
+		serverName:           c.config.ServerName,
+		supportedCurves:      c.config.curvePreferences(),
+		supportedPoints:      []uint8{pointFormatUncompressed},
+		nextProtoNeg:         len(c.config.NextProtos) > 0,
+		secureRenegotiation:  []byte{},
+		alpnProtocols:        c.config.NextProtos,
+		duplicateExtension:   c.config.Bugs.DuplicateExtension,
+		channelIDSupported:   c.config.ChannelID != nil,
+		npnLast:              c.config.Bugs.SwapNPNAndALPN,
+		extendedMasterSecret: c.config.maxVersion() >= VersionTLS10,
 	}
 
 	if c.config.Bugs.SendClientVersion != 0 {
 		hello.vers = c.config.Bugs.SendClientVersion
 	}
 
+	if c.config.Bugs.NoExtendedMasterSecret {
+		hello.extendedMasterSecret = false
+	}
+
+	if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo {
+		if c.config.Bugs.BadRenegotiationInfo {
+			hello.secureRenegotiation = append(hello.secureRenegotiation, c.clientVerify...)
+			hello.secureRenegotiation[0] ^= 0x80
+		} else {
+			hello.secureRenegotiation = c.clientVerify
+		}
+	}
+
 	possibleCipherSuites := c.config.cipherSuites()
 	hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
 
@@ -235,6 +249,16 @@
 		return fmt.Errorf("tls: server selected an unsupported cipher suite")
 	}
 
+	if len(c.clientVerify) > 0 {
+		var expectedRenegInfo []byte
+		expectedRenegInfo = append(expectedRenegInfo, c.clientVerify...)
+		expectedRenegInfo = append(expectedRenegInfo, c.serverVerify...)
+		if !bytes.Equal(serverHello.secureRenegotiation, expectedRenegInfo) {
+			c.sendAlert(alertHandshakeFailure)
+			return fmt.Errorf("tls: renegotiation mismatch")
+		}
+	}
+
 	hs := &clientHandshakeState{
 		c:            c,
 		serverHello:  serverHello,
@@ -303,60 +327,65 @@
 func (hs *clientHandshakeState) doFullHandshake() error {
 	c := hs.c
 
-	msg, err := c.readHandshake()
-	if err != nil {
-		return err
-	}
-	certMsg, ok := msg.(*certificateMsg)
-	if !ok || len(certMsg.certificates) == 0 {
-		c.sendAlert(alertUnexpectedMessage)
-		return unexpectedMessageError(certMsg, msg)
-	}
-	hs.writeServerHash(certMsg.marshal())
-
-	certs := make([]*x509.Certificate, len(certMsg.certificates))
-	for i, asn1Data := range certMsg.certificates {
-		cert, err := x509.ParseCertificate(asn1Data)
+	var leaf *x509.Certificate
+	if hs.suite.flags&suitePSK == 0 {
+		msg, err := c.readHandshake()
 		if err != nil {
-			c.sendAlert(alertBadCertificate)
-			return errors.New("tls: failed to parse certificate from server: " + err.Error())
-		}
-		certs[i] = cert
-	}
-
-	if !c.config.InsecureSkipVerify {
-		opts := x509.VerifyOptions{
-			Roots:         c.config.RootCAs,
-			CurrentTime:   c.config.time(),
-			DNSName:       c.config.ServerName,
-			Intermediates: x509.NewCertPool(),
-		}
-
-		for i, cert := range certs {
-			if i == 0 {
-				continue
-			}
-			opts.Intermediates.AddCert(cert)
-		}
-		c.verifiedChains, err = certs[0].Verify(opts)
-		if err != nil {
-			c.sendAlert(alertBadCertificate)
 			return err
 		}
-	}
 
-	switch certs[0].PublicKey.(type) {
-	case *rsa.PublicKey, *ecdsa.PublicKey:
-		break
-	default:
-		c.sendAlert(alertUnsupportedCertificate)
-		return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
-	}
+		certMsg, ok := msg.(*certificateMsg)
+		if !ok || len(certMsg.certificates) == 0 {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certMsg, msg)
+		}
+		hs.writeServerHash(certMsg.marshal())
 
-	c.peerCertificates = certs
+		certs := make([]*x509.Certificate, len(certMsg.certificates))
+		for i, asn1Data := range certMsg.certificates {
+			cert, err := x509.ParseCertificate(asn1Data)
+			if err != nil {
+				c.sendAlert(alertBadCertificate)
+				return errors.New("tls: failed to parse certificate from server: " + err.Error())
+			}
+			certs[i] = cert
+		}
+		leaf = certs[0]
+
+		if !c.config.InsecureSkipVerify {
+			opts := x509.VerifyOptions{
+				Roots:         c.config.RootCAs,
+				CurrentTime:   c.config.time(),
+				DNSName:       c.config.ServerName,
+				Intermediates: x509.NewCertPool(),
+			}
+
+			for i, cert := range certs {
+				if i == 0 {
+					continue
+				}
+				opts.Intermediates.AddCert(cert)
+			}
+			c.verifiedChains, err = leaf.Verify(opts)
+			if err != nil {
+				c.sendAlert(alertBadCertificate)
+				return err
+			}
+		}
+
+		switch leaf.PublicKey.(type) {
+		case *rsa.PublicKey, *ecdsa.PublicKey:
+			break
+		default:
+			c.sendAlert(alertUnsupportedCertificate)
+			return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", leaf.PublicKey)
+		}
+
+		c.peerCertificates = certs
+	}
 
 	if hs.serverHello.ocspStapling {
-		msg, err = c.readHandshake()
+		msg, err := c.readHandshake()
 		if err != nil {
 			return err
 		}
@@ -372,7 +401,7 @@
 		}
 	}
 
-	msg, err = c.readHandshake()
+	msg, err := c.readHandshake()
 	if err != nil {
 		return err
 	}
@@ -382,7 +411,7 @@
 	skx, ok := msg.(*serverKeyExchangeMsg)
 	if ok {
 		hs.writeServerHash(skx.marshal())
-		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
+		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, leaf, skx)
 		if err != nil {
 			c.sendAlert(alertUnexpectedMessage)
 			return err
@@ -483,7 +512,7 @@
 	// Certificate message, even if it's empty because we don't have a
 	// certificate to send.
 	if certRequested {
-		certMsg = new(certificateMsg)
+		certMsg := new(certificateMsg)
 		if chainToSend != nil {
 			certMsg.certificates = chainToSend.Certificate
 		}
@@ -491,7 +520,7 @@
 		c.writeRecord(recordTypeHandshake, certMsg.marshal())
 	}
 
-	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
+	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, leaf)
 	if err != nil {
 		c.sendAlert(alertInternalError)
 		return err
@@ -503,7 +532,15 @@
 		c.writeRecord(recordTypeHandshake, ckx.marshal())
 	}
 
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+	if hs.serverHello.extendedMasterSecret && c.vers >= VersionTLS10 {
+		hs.masterSecret = extendedMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.finishedHash)
+		c.extendedMasterSecret = true
+	} else {
+		if c.config.Bugs.RequireExtendedMasterSecret {
+			return errors.New("tls: extended master secret required but not supported by peer")
+		}
+		hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+	}
 
 	if chainToSend != nil {
 		var signed []byte
@@ -629,6 +666,7 @@
 		// Restore masterSecret and peerCerts from previous state
 		hs.masterSecret = hs.session.masterSecret
 		c.peerCertificates = hs.session.serverCertificates
+		c.extendedMasterSecret = hs.session.extendedMasterSecret
 		hs.finishedHash.discardHandshakeBuffer()
 		return true, nil
 	}
@@ -661,6 +699,7 @@
 			return errors.New("tls: server's Finished message was incorrect")
 		}
 	}
+	c.serverVerify = append(c.serverVerify[:0], serverFinished.verifyData...)
 	hs.writeServerHash(serverFinished.marshal())
 	return nil
 }
@@ -747,6 +786,7 @@
 	} else {
 		finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
 	}
+	c.clientVerify = append(c.clientVerify[:0], finished.verifyData...)
 	finishedBytes := finished.marshal()
 	hs.writeHash(finishedBytes, seqno)
 	postCCSBytes = append(postCCSBytes, finishedBytes...)
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 136360d..12a9f3d 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -7,27 +7,28 @@
 import "bytes"
 
 type clientHelloMsg struct {
-	raw                 []byte
-	isDTLS              bool
-	vers                uint16
-	random              []byte
-	sessionId           []byte
-	cookie              []byte
-	cipherSuites        []uint16
-	compressionMethods  []uint8
-	nextProtoNeg        bool
-	serverName          string
-	ocspStapling        bool
-	supportedCurves     []CurveID
-	supportedPoints     []uint8
-	ticketSupported     bool
-	sessionTicket       []uint8
-	signatureAndHashes  []signatureAndHash
-	secureRenegotiation bool
-	alpnProtocols       []string
-	duplicateExtension  bool
-	channelIDSupported  bool
-	npnLast             bool
+	raw                  []byte
+	isDTLS               bool
+	vers                 uint16
+	random               []byte
+	sessionId            []byte
+	cookie               []byte
+	cipherSuites         []uint16
+	compressionMethods   []uint8
+	nextProtoNeg         bool
+	serverName           string
+	ocspStapling         bool
+	supportedCurves      []CurveID
+	supportedPoints      []uint8
+	ticketSupported      bool
+	sessionTicket        []uint8
+	signatureAndHashes   []signatureAndHash
+	secureRenegotiation  []byte
+	alpnProtocols        []string
+	duplicateExtension   bool
+	channelIDSupported   bool
+	npnLast              bool
+	extendedMasterSecret bool
 }
 
 func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -52,11 +53,13 @@
 		m.ticketSupported == m1.ticketSupported &&
 		bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
 		eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
-		m.secureRenegotiation == m1.secureRenegotiation &&
+		bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
+		(m.secureRenegotiation == nil) == (m1.secureRenegotiation == nil) &&
 		eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
 		m.duplicateExtension == m1.duplicateExtension &&
 		m.channelIDSupported == m1.channelIDSupported &&
-		m.npnLast == m1.npnLast
+		m.npnLast == m1.npnLast &&
+		m.extendedMasterSecret == m1.extendedMasterSecret
 }
 
 func (m *clientHelloMsg) marshal() []byte {
@@ -97,8 +100,8 @@
 		extensionsLength += 2 + 2*len(m.signatureAndHashes)
 		numExtensions++
 	}
-	if m.secureRenegotiation {
-		extensionsLength += 1
+	if m.secureRenegotiation != nil {
+		extensionsLength += 1 + len(m.secureRenegotiation)
 		numExtensions++
 	}
 	if m.duplicateExtension {
@@ -118,6 +121,9 @@
 		}
 		numExtensions++
 	}
+	if m.extendedMasterSecret {
+		numExtensions++
+	}
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
 		length += 2 + extensionsLength
@@ -274,12 +280,15 @@
 			z = z[2:]
 		}
 	}
-	if m.secureRenegotiation {
+	if m.secureRenegotiation != nil {
 		z[0] = byte(extensionRenegotiationInfo >> 8)
 		z[1] = byte(extensionRenegotiationInfo & 0xff)
 		z[2] = 0
-		z[3] = 1
+		z[3] = byte(1 + len(m.secureRenegotiation))
+		z[4] = byte(len(m.secureRenegotiation))
 		z = z[5:]
+		copy(z, m.secureRenegotiation)
+		z = z[len(m.secureRenegotiation):]
 	}
 	if len(m.alpnProtocols) > 0 {
 		z[0] = byte(extensionALPN >> 8)
@@ -319,6 +328,12 @@
 		z[1] = 0xff
 		z = z[4:]
 	}
+	if m.extendedMasterSecret {
+		// https://tools.ietf.org/html/draft-ietf-tls-session-hash-01
+		z[0] = byte(extensionExtendedMasterSecret >> 8)
+		z[1] = byte(extensionExtendedMasterSecret & 0xff)
+		z = z[4:]
+	}
 
 	m.raw = x
 
@@ -363,7 +378,7 @@
 	for i := 0; i < numCipherSuites; i++ {
 		m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
 		if m.cipherSuites[i] == scsvRenegotiation {
-			m.secureRenegotiation = true
+			m.secureRenegotiation = []byte{}
 		}
 	}
 	data = data[2+cipherSuiteLen:]
@@ -385,6 +400,7 @@
 	m.sessionTicket = nil
 	m.signatureAndHashes = nil
 	m.alpnProtocols = nil
+	m.extendedMasterSecret = false
 
 	if len(data) == 0 {
 		// ClientHello is optionally followed by extension data
@@ -489,11 +505,11 @@
 				m.signatureAndHashes[i].signature = d[1]
 				d = d[2:]
 			}
-		case extensionRenegotiationInfo + 1:
-			if length != 1 || data[0] != 0 {
+		case extensionRenegotiationInfo:
+			if length < 1 || length != int(data[0])+1 {
 				return false
 			}
-			m.secureRenegotiation = true
+			m.secureRenegotiation = data[1:length]
 		case extensionALPN:
 			if length < 2 {
 				return false
@@ -517,6 +533,11 @@
 				return false
 			}
 			m.channelIDSupported = true
+		case extensionExtendedMasterSecret:
+			if length != 0 {
+				return false
+			}
+			m.extendedMasterSecret = true
 		}
 		data = data[length:]
 	}
@@ -525,21 +546,22 @@
 }
 
 type serverHelloMsg struct {
-	raw                 []byte
-	isDTLS              bool
-	vers                uint16
-	random              []byte
-	sessionId           []byte
-	cipherSuite         uint16
-	compressionMethod   uint8
-	nextProtoNeg        bool
-	nextProtos          []string
-	ocspStapling        bool
-	ticketSupported     bool
-	secureRenegotiation bool
-	alpnProtocol        string
-	duplicateExtension  bool
-	channelIDRequested  bool
+	raw                  []byte
+	isDTLS               bool
+	vers                 uint16
+	random               []byte
+	sessionId            []byte
+	cipherSuite          uint16
+	compressionMethod    uint8
+	nextProtoNeg         bool
+	nextProtos           []string
+	ocspStapling         bool
+	ticketSupported      bool
+	secureRenegotiation  []byte
+	alpnProtocol         string
+	duplicateExtension   bool
+	channelIDRequested   bool
+	extendedMasterSecret bool
 }
 
 func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -559,10 +581,12 @@
 		eqStrings(m.nextProtos, m1.nextProtos) &&
 		m.ocspStapling == m1.ocspStapling &&
 		m.ticketSupported == m1.ticketSupported &&
-		m.secureRenegotiation == m1.secureRenegotiation &&
+		bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
+		(m.secureRenegotiation == nil) == (m1.secureRenegotiation == nil) &&
 		m.alpnProtocol == m1.alpnProtocol &&
 		m.duplicateExtension == m1.duplicateExtension &&
-		m.channelIDRequested == m1.channelIDRequested
+		m.channelIDRequested == m1.channelIDRequested &&
+		m.extendedMasterSecret == m1.extendedMasterSecret
 }
 
 func (m *serverHelloMsg) marshal() []byte {
@@ -589,8 +613,8 @@
 	if m.ticketSupported {
 		numExtensions++
 	}
-	if m.secureRenegotiation {
-		extensionsLength += 1
+	if m.secureRenegotiation != nil {
+		extensionsLength += 1 + len(m.secureRenegotiation)
 		numExtensions++
 	}
 	if m.duplicateExtension {
@@ -606,6 +630,9 @@
 		extensionsLength += 2 + 1 + alpnLen
 		numExtensions++
 	}
+	if m.extendedMasterSecret {
+		numExtensions++
+	}
 
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
@@ -667,12 +694,15 @@
 		z[1] = byte(extensionSessionTicket)
 		z = z[4:]
 	}
-	if m.secureRenegotiation {
+	if m.secureRenegotiation != nil {
 		z[0] = byte(extensionRenegotiationInfo >> 8)
 		z[1] = byte(extensionRenegotiationInfo & 0xff)
 		z[2] = 0
-		z[3] = 1
+		z[3] = byte(1 + len(m.secureRenegotiation))
+		z[4] = byte(len(m.secureRenegotiation))
 		z = z[5:]
+		copy(z, m.secureRenegotiation)
+		z = z[len(m.secureRenegotiation):]
 	}
 	if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
 		z[0] = byte(extensionALPN >> 8)
@@ -699,6 +729,11 @@
 		z[1] = 0xff
 		z = z[4:]
 	}
+	if m.extendedMasterSecret {
+		z[0] = byte(extensionExtendedMasterSecret >> 8)
+		z[1] = byte(extensionExtendedMasterSecret & 0xff)
+		z = z[4:]
+	}
 
 	m.raw = x
 
@@ -730,6 +765,7 @@
 	m.ocspStapling = false
 	m.ticketSupported = false
 	m.alpnProtocol = ""
+	m.extendedMasterSecret = false
 
 	if len(data) == 0 {
 		// ServerHello is optionally followed by extension data
@@ -780,10 +816,10 @@
 			}
 			m.ticketSupported = true
 		case extensionRenegotiationInfo:
-			if length != 1 || data[0] != 0 {
+			if length < 1 || length != int(data[0])+1 {
 				return false
 			}
-			m.secureRenegotiation = true
+			m.secureRenegotiation = data[1:length]
 		case extensionALPN:
 			d := data[:length]
 			if len(d) < 3 {
@@ -805,6 +841,11 @@
 				return false
 			}
 			m.channelIDRequested = true
+		case extensionExtendedMasterSecret:
+			if length != 0 {
+				return false
+			}
+			m.extendedMasterSecret = true
 		}
 		data = data[length:]
 	}
@@ -1634,6 +1675,17 @@
 	return true
 }
 
+type helloRequestMsg struct {
+}
+
+func (*helloRequestMsg) marshal() []byte {
+	return []byte{typeHelloRequest, 0, 0, 0}
+}
+
+func (*helloRequestMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}
+
 func eqUint16s(x, y []uint16) bool {
 	if len(x) != len(y) {
 		return false
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 1eb3f11..41d588a 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -214,7 +214,22 @@
 		c.sendAlert(alertInternalError)
 		return false, err
 	}
-	hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
+
+	if !bytes.Equal(c.clientVerify, hs.clientHello.secureRenegotiation) {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: renegotiation mismatch")
+	}
+
+	if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo {
+		hs.hello.secureRenegotiation = append(hs.hello.secureRenegotiation, c.clientVerify...)
+		hs.hello.secureRenegotiation = append(hs.hello.secureRenegotiation, c.serverVerify...)
+		if c.config.Bugs.BadRenegotiationInfo {
+			hs.hello.secureRenegotiation[0] ^= 0x80
+		}
+	} else {
+		hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
+	}
+
 	hs.hello.compressionMethod = compressionNone
 	hs.hello.duplicateExtension = c.config.Bugs.DuplicateExtension
 	if len(hs.clientHello.serverName) > 0 {
@@ -237,6 +252,7 @@
 			hs.hello.nextProtos = config.NextProtos
 		}
 	}
+	hs.hello.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !c.config.Bugs.NoExtendedMasterSecret
 
 	if len(config.Certificates) == 0 {
 		c.sendAlert(alertInternalError)
@@ -373,6 +389,7 @@
 	}
 
 	hs.masterSecret = hs.sessionState.masterSecret
+	c.extendedMasterSecret = hs.sessionState.extendedMasterSecret
 
 	return nil
 }
@@ -381,12 +398,14 @@
 	config := hs.c.config
 	c := hs.c
 
-	if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
+	isPSK := hs.suite.flags&suitePSK != 0
+	if !isPSK && hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
 		hs.hello.ocspStapling = true
 	}
 
 	hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
 	hs.hello.cipherSuite = hs.suite.id
+	c.extendedMasterSecret = hs.hello.extendedMasterSecret
 
 	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
 	hs.writeClientHash(hs.clientHello.marshal())
@@ -394,11 +413,13 @@
 
 	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
 
-	certMsg := new(certificateMsg)
-	certMsg.certificates = hs.cert.Certificate
-	if !config.Bugs.UnauthenticatedECDH {
-		hs.writeServerHash(certMsg.marshal())
-		c.writeRecord(recordTypeHandshake, certMsg.marshal())
+	if !isPSK {
+		certMsg := new(certificateMsg)
+		certMsg.certificates = hs.cert.Certificate
+		if !config.Bugs.UnauthenticatedECDH {
+			hs.writeServerHash(certMsg.marshal())
+			c.writeRecord(recordTypeHandshake, certMsg.marshal())
+		}
 	}
 
 	if hs.hello.ocspStapling {
@@ -463,6 +484,7 @@
 	// If we requested a client certificate, then the client must send a
 	// certificate message, even if it's empty.
 	if config.ClientAuth >= RequestClientCert {
+		var certMsg *certificateMsg
 		if certMsg, ok = msg.(*certificateMsg); !ok {
 			c.sendAlert(alertUnexpectedMessage)
 			return unexpectedMessageError(certMsg, msg)
@@ -502,7 +524,14 @@
 		c.sendAlert(alertHandshakeFailure)
 		return err
 	}
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+	if c.extendedMasterSecret {
+		hs.masterSecret = extendedMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.finishedHash)
+	} else {
+		if c.config.Bugs.RequireExtendedMasterSecret {
+			return errors.New("tls: extended master secret required but not supported by peer")
+		}
+		hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+	}
 
 	// If we received a client cert in response to our certificate request message,
 	// the client will send us a certificateVerifyMsg immediately after the
@@ -679,6 +708,7 @@
 		c.sendAlert(alertHandshakeFailure)
 		return errors.New("tls: client's Finished message is incorrect")
 	}
+	c.clientVerify = append(c.clientVerify[:0], clientFinished.verifyData...)
 
 	hs.writeClientHash(clientFinished.marshal())
 	return nil
@@ -716,6 +746,7 @@
 
 	finished := new(finishedMsg)
 	finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+	c.serverVerify = append(c.serverVerify[:0], finished.verifyData...)
 	postCCSBytes := finished.marshal()
 	hs.writeServerHash(postCCSBytes)
 
diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go
index f8ba1f8..af54a8f 100644
--- a/ssl/test/runner/key_agreement.go
+++ b/ssl/test/runner/key_agreement.go
@@ -187,8 +187,29 @@
 
 }
 
-// signedKeyAgreement implements helper functions for key agreement
-// methods that involve signed parameters in the ServerKeyExchange.
+// keyAgreementAuthentication is a helper interface that specifies how
+// to authenticate the ServerKeyExchange parameters.
+type keyAgreementAuthentication interface {
+	signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error)
+	verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error
+}
+
+// nilKeyAgreementAuthentication does not authenticate the key
+// agreement parameters.
+type nilKeyAgreementAuthentication struct{}
+
+func (ka *nilKeyAgreementAuthentication) signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) {
+	skx := new(serverKeyExchangeMsg)
+	skx.key = params
+	return skx, nil
+}
+
+func (ka *nilKeyAgreementAuthentication) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error {
+	return nil
+}
+
+// signedKeyAgreement signs the ServerKeyExchange parameters with the
+// server's private key.
 type signedKeyAgreement struct {
 	version uint16
 	sigType uint8
@@ -328,7 +349,7 @@
 // pre-master secret is then calculated using ECDH. The signature may
 // either be ECDSA or RSA.
 type ecdheKeyAgreement struct {
-	signedKeyAgreement
+	auth       keyAgreementAuthentication
 	privateKey []byte
 	curve      elliptic.Curve
 	x, y       *big.Int
@@ -394,7 +415,7 @@
 	serverECDHParams[3] = byte(len(ecdhePublic))
 	copy(serverECDHParams[4:], ecdhePublic)
 
-	return ka.signParameters(config, cert, clientHello, hello, serverECDHParams)
+	return ka.auth.signParameters(config, cert, clientHello, hello, serverECDHParams)
 }
 
 func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
@@ -438,7 +459,7 @@
 	serverECDHParams := skx.key[:4+publicLen]
 	sig := skx.key[4+publicLen:]
 
-	return ka.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig)
+	return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig)
 }
 
 func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
@@ -468,7 +489,7 @@
 // an ephemeral Diffie-Hellman public/private key pair and signs it. The
 // pre-master secret is then calculated using Diffie-Hellman.
 type dheKeyAgreement struct {
-	signedKeyAgreement
+	auth    keyAgreementAuthentication
 	p, g    *big.Int
 	yTheirs *big.Int
 	xOurs   *big.Int
@@ -500,7 +521,7 @@
 	serverDHParams = append(serverDHParams, byte(len(yBytes)>>8), byte(len(yBytes)))
 	serverDHParams = append(serverDHParams, yBytes...)
 
-	return ka.signParameters(config, cert, clientHello, hello, serverDHParams)
+	return ka.auth.signParameters(config, cert, clientHello, hello, serverDHParams)
 }
 
 func (ka *dheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
@@ -562,7 +583,7 @@
 	sig := k
 	serverDHParams := skx.key[:len(skx.key)-len(sig)]
 
-	return ka.verifyParameters(config, clientHello, serverHello, cert, serverDHParams, sig)
+	return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverDHParams, sig)
 }
 
 func (ka *dheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
@@ -586,3 +607,164 @@
 
 	return preMasterSecret, ckx, nil
 }
+
+// nilKeyAgreement is a fake key agreement used to implement the plain PSK key
+// exchange.
+type nilKeyAgreement struct{}
+
+func (ka *nilKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	return nil, nil
+}
+
+func (ka *nilKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	if len(ckx.ciphertext) != 0 {
+		return nil, errClientKeyExchange
+	}
+
+	// Although in plain PSK, otherSecret is all zeros, the base key
+	// agreement does not access to the length of the pre-shared
+	// key. pskKeyAgreement instead interprets nil to mean to use all zeros
+	// of the appropriate length.
+	return nil, nil
+}
+
+func (ka *nilKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+	if len(skx.key) != 0 {
+		return errServerKeyExchange
+	}
+	return nil
+}
+
+func (ka *nilKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+	// Although in plain PSK, otherSecret is all zeros, the base key
+	// agreement does not access to the length of the pre-shared
+	// key. pskKeyAgreement instead interprets nil to mean to use all zeros
+	// of the appropriate length.
+	return nil, &clientKeyExchangeMsg{}, nil
+}
+
+// makePSKPremaster formats a PSK pre-master secret based on otherSecret from
+// the base key exchange and psk.
+func makePSKPremaster(otherSecret, psk []byte) []byte {
+	out := make([]byte, 0, 2+len(otherSecret)+2+len(psk))
+	out = append(out, byte(len(otherSecret)>>8), byte(len(otherSecret)))
+	out = append(out, otherSecret...)
+	out = append(out, byte(len(psk)>>8), byte(len(psk)))
+	out = append(out, psk...)
+	return out
+}
+
+// pskKeyAgreement implements the PSK key agreement.
+type pskKeyAgreement struct {
+	base         keyAgreement
+	identityHint string
+}
+
+func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	// Assemble the identity hint.
+	bytes := make([]byte, 2+len(config.PreSharedKeyIdentity))
+	bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8)
+	bytes[1] = byte(len(config.PreSharedKeyIdentity))
+	copy(bytes[2:], []byte(config.PreSharedKeyIdentity))
+
+	// If there is one, append the base key agreement's
+	// ServerKeyExchange.
+	baseSkx, err := ka.base.generateServerKeyExchange(config, cert, clientHello, hello)
+	if err != nil {
+		return nil, err
+	}
+
+	if baseSkx != nil {
+		bytes = append(bytes, baseSkx.key...)
+	} else if config.PreSharedKeyIdentity == "" {
+		// ServerKeyExchange is optional if the identity hint is empty
+		// and there would otherwise be no ServerKeyExchange.
+		return nil, nil
+	}
+
+	skx := new(serverKeyExchangeMsg)
+	skx.key = bytes
+	return skx, nil
+}
+
+func (ka *pskKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	// First, process the PSK identity.
+	if len(ckx.ciphertext) < 2 {
+		return nil, errClientKeyExchange
+	}
+	identityLen := (int(ckx.ciphertext[0]) << 8) | int(ckx.ciphertext[1])
+	if 2+identityLen > len(ckx.ciphertext) {
+		return nil, errClientKeyExchange
+	}
+	identity := string(ckx.ciphertext[2 : 2+identityLen])
+
+	if identity != config.PreSharedKeyIdentity {
+		return nil, errors.New("tls: unexpected identity")
+	}
+
+	if config.PreSharedKey == nil {
+		return nil, errors.New("tls: pre-shared key not configured")
+	}
+
+	// Process the remainder of the ClientKeyExchange to compute the base
+	// pre-master secret.
+	newCkx := new(clientKeyExchangeMsg)
+	newCkx.ciphertext = ckx.ciphertext[2+identityLen:]
+	otherSecret, err := ka.base.processClientKeyExchange(config, cert, newCkx, version)
+	if err != nil {
+		return nil, err
+	}
+
+	if otherSecret == nil {
+		// Special-case for the plain PSK key exchanges.
+		otherSecret = make([]byte, len(config.PreSharedKey))
+	}
+	return makePSKPremaster(otherSecret, config.PreSharedKey), nil
+}
+
+func (ka *pskKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+	if len(skx.key) < 2 {
+		return errServerKeyExchange
+	}
+	identityLen := (int(skx.key[0]) << 8) | int(skx.key[1])
+	if 2+identityLen > len(skx.key) {
+		return errServerKeyExchange
+	}
+	ka.identityHint = string(skx.key[2 : 2+identityLen])
+
+	// Process the remainder of the ServerKeyExchange.
+	newSkx := new(serverKeyExchangeMsg)
+	newSkx.key = skx.key[2+identityLen:]
+	return ka.base.processServerKeyExchange(config, clientHello, serverHello, cert, newSkx)
+}
+
+func (ka *pskKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+	// The server only sends an identity hint but, for purposes of
+	// test code, the server always sends the hint and it is
+	// required to match.
+	if ka.identityHint != config.PreSharedKeyIdentity {
+		return nil, nil, errors.New("tls: unexpected identity")
+	}
+
+	// Serialize the identity.
+	bytes := make([]byte, 2+len(config.PreSharedKeyIdentity))
+	bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8)
+	bytes[1] = byte(len(config.PreSharedKeyIdentity))
+	copy(bytes[2:], []byte(config.PreSharedKeyIdentity))
+
+	// Append the base key exchange's ClientKeyExchange.
+	otherSecret, baseCkx, err := ka.base.generateClientKeyExchange(config, clientHello, cert)
+	if err != nil {
+		return nil, nil, err
+	}
+	ckx := new(clientKeyExchangeMsg)
+	ckx.ciphertext = append(bytes, baseCkx.ciphertext...)
+
+	if config.PreSharedKey == nil {
+		return nil, nil, errors.New("tls: pre-shared key not configured")
+	}
+	if otherSecret == nil {
+		otherSecret = make([]byte, len(config.PreSharedKey))
+	}
+	return makePSKPremaster(otherSecret, config.PreSharedKey), ckx, nil
+}
diff --git a/ssl/test/runner/prf.go b/ssl/test/runner/prf.go
index 6d0db97..d45c080 100644
--- a/ssl/test/runner/prf.go
+++ b/ssl/test/runner/prf.go
@@ -117,6 +117,7 @@
 )
 
 var masterSecretLabel = []byte("master secret")
+var extendedMasterSecretLabel = []byte("extended master secret")
 var keyExpansionLabel = []byte("key expansion")
 var clientFinishedLabel = []byte("client finished")
 var serverFinishedLabel = []byte("server finished")
@@ -150,6 +151,15 @@
 	return masterSecret
 }
 
+// extendedMasterFromPreMasterSecret generates the master secret from the
+// pre-master secret when the Triple Handshake fix is in effect. See
+// https://tools.ietf.org/html/draft-ietf-tls-session-hash-01
+func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, h finishedHash) []byte {
+	masterSecret := make([]byte, masterSecretLength)
+	prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, h.Sum())
+	return masterSecret
+}
+
 // keysFromMasterSecret generates the connection keys from the master
 // secret, given the lengths of the MAC key, cipher key and IV, as defined in
 // RFC 2246, section 6.3.
@@ -221,6 +231,16 @@
 	return len(msg), nil
 }
 
+func (h finishedHash) Sum() []byte {
+	if h.version >= VersionTLS12 {
+		return h.client.Sum(nil)
+	}
+
+	out := make([]byte, 0, md5.Size+sha1.Size)
+	out = h.clientMD5.Sum(out)
+	return h.client.Sum(out)
+}
+
 // finishedSum30 calculates the contents of the verify_data member of a SSLv3
 // Finished message given the MD5 and SHA1 hashes of a set of handshake
 // messages.
@@ -264,15 +284,7 @@
 	}
 
 	out := make([]byte, finishedVerifyLength)
-	if h.version >= VersionTLS12 {
-		seed := h.client.Sum(nil)
-		h.prf(out, masterSecret, clientFinishedLabel, seed)
-	} else {
-		seed := make([]byte, 0, md5.Size+sha1.Size)
-		seed = h.clientMD5.Sum(seed)
-		seed = h.client.Sum(seed)
-		h.prf(out, masterSecret, clientFinishedLabel, seed)
-	}
+	h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
 	return out
 }
 
@@ -284,15 +296,7 @@
 	}
 
 	out := make([]byte, finishedVerifyLength)
-	if h.version >= VersionTLS12 {
-		seed := h.server.Sum(nil)
-		h.prf(out, masterSecret, serverFinishedLabel, seed)
-	} else {
-		seed := make([]byte, 0, md5.Size+sha1.Size)
-		seed = h.serverMD5.Sum(seed)
-		seed = h.server.Sum(seed)
-		h.prf(out, masterSecret, serverFinishedLabel, seed)
-	}
+	h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
 	return out
 }
 
@@ -334,14 +338,10 @@
 		return digest[:], crypto.SHA256, nil
 	}
 	if signatureAndHash.signature == signatureECDSA {
-		digest := h.server.Sum(nil)
-		return digest, crypto.SHA1, nil
+		return h.server.Sum(nil), crypto.SHA1, nil
 	}
 
-	digest := make([]byte, 0, 36)
-	digest = h.serverMD5.Sum(digest)
-	digest = h.server.Sum(digest)
-	return digest, crypto.MD5SHA1, nil
+	return h.Sum(), crypto.MD5SHA1, nil
 }
 
 // hashForChannelID returns the hash to be signed for TLS Channel
diff --git a/ssl/test/runner/recordingconn.go b/ssl/test/runner/recordingconn.go
new file mode 100644
index 0000000..a67fa48
--- /dev/null
+++ b/ssl/test/runner/recordingconn.go
@@ -0,0 +1,130 @@
+package main
+
+import (
+	"bufio"
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+// recordingConn is a net.Conn that records the traffic that passes through it.
+// WriteTo can be used to produce output that can be later be loaded with
+// ParseTestData.
+type recordingConn struct {
+	net.Conn
+	sync.Mutex
+	flows   [][]byte
+	reading bool
+}
+
+func (r *recordingConn) Read(b []byte) (n int, err error) {
+	if n, err = r.Conn.Read(b); n == 0 {
+		return
+	}
+	b = b[:n]
+
+	r.Lock()
+	defer r.Unlock()
+
+	if l := len(r.flows); l == 0 || !r.reading {
+		buf := make([]byte, len(b))
+		copy(buf, b)
+		r.flows = append(r.flows, buf)
+	} else {
+		r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+	}
+	r.reading = true
+	return
+}
+
+func (r *recordingConn) Write(b []byte) (n int, err error) {
+	if n, err = r.Conn.Write(b); n == 0 {
+		return
+	}
+	b = b[:n]
+
+	r.Lock()
+	defer r.Unlock()
+
+	if l := len(r.flows); l == 0 || r.reading {
+		buf := make([]byte, len(b))
+		copy(buf, b)
+		r.flows = append(r.flows, buf)
+	} else {
+		r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+	}
+	r.reading = false
+	return
+}
+
+// WriteTo writes hex dumps to w that contains the recorded traffic.
+func (r *recordingConn) WriteTo(w io.Writer) {
+	// TLS always starts with a client to server flow.
+	clientToServer := true
+
+	for i, flow := range r.flows {
+		source, dest := "client", "server"
+		if !clientToServer {
+			source, dest = dest, source
+		}
+		fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+		dumper := hex.Dumper(w)
+		dumper.Write(flow)
+		dumper.Close()
+		clientToServer = !clientToServer
+	}
+}
+
+func parseTestData(r io.Reader) (flows [][]byte, err error) {
+	var currentFlow []byte
+
+	scanner := bufio.NewScanner(r)
+	for scanner.Scan() {
+		line := scanner.Text()
+		// If the line starts with ">>> " then it marks the beginning
+		// of a new flow.
+		if strings.HasPrefix(line, ">>> ") {
+			if len(currentFlow) > 0 || len(flows) > 0 {
+				flows = append(flows, currentFlow)
+				currentFlow = nil
+			}
+			continue
+		}
+
+		// Otherwise the line is a line of hex dump that looks like:
+		// 00000170  fc f5 06 bf (...)  |.....X{&?......!|
+		// (Some bytes have been omitted from the middle section.)
+
+		if i := strings.IndexByte(line, ' '); i >= 0 {
+			line = line[i:]
+		} else {
+			return nil, errors.New("invalid test data")
+		}
+
+		if i := strings.IndexByte(line, '|'); i >= 0 {
+			line = line[:i]
+		} else {
+			return nil, errors.New("invalid test data")
+		}
+
+		hexBytes := strings.Fields(line)
+		for _, hexByte := range hexBytes {
+			val, err := strconv.ParseUint(hexByte, 16, 8)
+			if err != nil {
+				return nil, errors.New("invalid hex byte in test data: " + err.Error())
+			}
+			currentFlow = append(currentFlow, byte(val))
+		}
+	}
+
+	if len(currentFlow) > 0 {
+		flows = append(flows, currentFlow)
+	}
+
+	return flows, nil
+}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index b4c2e61..4b43481 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -22,6 +22,8 @@
 )
 
 var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
+var useGDB = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb")
+var flagDebug *bool = flag.Bool("debug", false, "Hexdump the contents of the connection")
 
 const (
 	rsaCertificateFile   = "cert.pem"
@@ -148,6 +150,12 @@
 	// shimWritesFirst controls whether the shim sends an initial "hello"
 	// message before doing a roundtrip with the runner.
 	shimWritesFirst bool
+	// renegotiate indicates the the connection should be renegotiated
+	// during the exchange.
+	renegotiate bool
+	// renegotiateCiphers is a list of ciphersuite ids that will be
+	// switched in just before renegotiation.
+	renegotiateCiphers []uint16
 	// flags, if not empty, contains a list of command-line flags that will
 	// be passed to the shim program.
 	flags []string
@@ -563,6 +571,17 @@
 		}
 	}
 
+	if test.renegotiate {
+		if test.renegotiateCiphers != nil {
+			config.CipherSuites = test.renegotiateCiphers
+		}
+		if err := tlsConn.Renegotiate(); err != nil {
+			return err
+		}
+	} else if test.renegotiateCiphers != nil {
+		panic("renegotiateCiphers without renegotiate")
+	}
+
 	if messageLen < 0 {
 		if test.protocol == dtls {
 			return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
@@ -693,10 +712,11 @@
 	var shim *exec.Cmd
 	if *useValgrind {
 		shim = valgrindOf(false, shim_path, flags...)
+	} else if *useGDB {
+		shim = gdbOf(shim_path, flags...)
 	} else {
 		shim = exec.Command(shim_path, flags...)
 	}
-	// shim = gdbOf(shim_path, flags...)
 	shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
 	shim.Stdin = os.Stdin
 	var stdoutBuf, stderrBuf bytes.Buffer
@@ -717,8 +737,19 @@
 		}
 	}
 
+	var connDebug *recordingConn
+	if *flagDebug {
+		connDebug = &recordingConn{Conn: conn}
+		conn = connDebug
+	}
+
 	err := doExchange(test, &config, conn, test.messageLen,
 		false /* not a resumption */)
+
+	if *flagDebug {
+		connDebug.WriteTo(os.Stdout)
+	}
+
 	conn.Close()
 	if err == nil && test.resumeSession {
 		var resumeConfig Config
@@ -814,6 +845,7 @@
 	{"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
 	{"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
 	{"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
+	{"ECDHE-PSK-WITH-AES-128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256},
 	{"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 	{"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
 	{"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
@@ -821,6 +853,9 @@
 	{"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
 	{"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
 	{"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+	{"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
+	{"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
+	{"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA},
 	{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
 	{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
 }
@@ -833,6 +868,9 @@
 
 func addCipherSuiteTests() {
 	for _, suite := range testCipherSuites {
+		const psk = "12345"
+		const pskIdentity = "luggage combo"
+
 		var cert Certificate
 		var certFile string
 		var keyFile string
@@ -846,6 +884,13 @@
 			keyFile = rsaKeyFile
 		}
 
+		var flags []string
+		if strings.HasPrefix(suite.name, "PSK-") || strings.Contains(suite.name, "-PSK-") {
+			flags = append(flags,
+				"-psk", psk,
+				"-psk-identity", pskIdentity)
+		}
+
 		for _, ver := range tlsVersions {
 			if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
 				continue
@@ -860,11 +905,14 @@
 				testType: clientTest,
 				name:     ver.name + "-" + suite.name + "-client",
 				config: Config{
-					MinVersion:   ver.version,
-					MaxVersion:   ver.version,
-					CipherSuites: []uint16{suite.id},
-					Certificates: []Certificate{cert},
+					MinVersion:           ver.version,
+					MaxVersion:           ver.version,
+					CipherSuites:         []uint16{suite.id},
+					Certificates:         []Certificate{cert},
+					PreSharedKey:         []byte(psk),
+					PreSharedKeyIdentity: pskIdentity,
 				},
+				flags:         flags,
 				resumeSession: resumeSession,
 			})
 
@@ -872,13 +920,16 @@
 				testType: serverTest,
 				name:     ver.name + "-" + suite.name + "-server",
 				config: Config{
-					MinVersion:   ver.version,
-					MaxVersion:   ver.version,
-					CipherSuites: []uint16{suite.id},
-					Certificates: []Certificate{cert},
+					MinVersion:           ver.version,
+					MaxVersion:           ver.version,
+					CipherSuites:         []uint16{suite.id},
+					Certificates:         []Certificate{cert},
+					PreSharedKey:         []byte(psk),
+					PreSharedKeyIdentity: pskIdentity,
 				},
 				certFile:      certFile,
 				keyFile:       keyFile,
+				flags:         flags,
 				resumeSession: resumeSession,
 			})
 
@@ -889,11 +940,14 @@
 					protocol: dtls,
 					name:     "D" + ver.name + "-" + suite.name + "-client",
 					config: Config{
-						MinVersion:   ver.version,
-						MaxVersion:   ver.version,
-						CipherSuites: []uint16{suite.id},
-						Certificates: []Certificate{cert},
+						MinVersion:           ver.version,
+						MaxVersion:           ver.version,
+						CipherSuites:         []uint16{suite.id},
+						Certificates:         []Certificate{cert},
+						PreSharedKey:         []byte(psk),
+						PreSharedKeyIdentity: pskIdentity,
 					},
+					flags:         flags,
 					resumeSession: resumeSession,
 				})
 				testCases = append(testCases, testCase{
@@ -901,13 +955,16 @@
 					protocol: dtls,
 					name:     "D" + ver.name + "-" + suite.name + "-server",
 					config: Config{
-						MinVersion:   ver.version,
-						MaxVersion:   ver.version,
-						CipherSuites: []uint16{suite.id},
-						Certificates: []Certificate{cert},
+						MinVersion:           ver.version,
+						MaxVersion:           ver.version,
+						CipherSuites:         []uint16{suite.id},
+						Certificates:         []Certificate{cert},
+						PreSharedKey:         []byte(psk),
+						PreSharedKeyIdentity: pskIdentity,
 					},
 					certFile:      certFile,
 					keyFile:       keyFile,
+					flags:         flags,
 					resumeSession: resumeSession,
 				})
 			}
@@ -1070,6 +1127,62 @@
 	}
 }
 
+func addExtendedMasterSecretTests() {
+	const expectEMSFlag = "-expect-extended-master-secret"
+
+	for _, with := range []bool{false, true} {
+		prefix := "No"
+		var flags []string
+		if with {
+			prefix = ""
+			flags = []string{expectEMSFlag}
+		}
+
+		for _, isClient := range []bool{false, true} {
+			suffix := "-Server"
+			testType := serverTest
+			if isClient {
+				suffix = "-Client"
+				testType = clientTest
+			}
+
+			for _, ver := range tlsVersions {
+				test := testCase{
+					testType: testType,
+					name:     prefix + "ExtendedMasterSecret-" + ver.name + suffix,
+					config: Config{
+						MinVersion: ver.version,
+						MaxVersion: ver.version,
+						Bugs: ProtocolBugs{
+							NoExtendedMasterSecret:      !with,
+							RequireExtendedMasterSecret: with,
+						},
+					},
+					flags:      flags,
+					shouldFail: ver.version == VersionSSL30 && with,
+				}
+				if test.shouldFail {
+					test.expectedLocalError = "extended master secret required but not supported by peer"
+				}
+				testCases = append(testCases, test)
+			}
+		}
+	}
+
+	// When a session is resumed, it should still be aware that its master
+	// secret was generated via EMS and thus it's safe to use tls-unique.
+	testCases = append(testCases, testCase{
+		name: "ExtendedMasterSecret-Resume",
+		config: Config{
+			Bugs: ProtocolBugs{
+				RequireExtendedMasterSecret: true,
+			},
+		},
+		flags:         []string{expectEMSFlag},
+		resumeSession: true,
+	})
+}
+
 // Adds tests that try to cover the range of the handshake state machine, under
 // various conditions. Some of these are redundant with other tests, but they
 // only cover the synchronous case.
@@ -1178,6 +1291,34 @@
 		flags: flags,
 	})
 
+	// Skip ServerKeyExchange in PSK key exchange if there's no
+	// identity hint.
+	testCases = append(testCases, testCase{
+		protocol: protocol,
+		name:     "EmptyPSKHint-Client" + suffix,
+		config: Config{
+			CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
+			PreSharedKey: []byte("secret"),
+			Bugs: ProtocolBugs{
+				MaxHandshakeRecordLength: maxHandshakeRecordLength,
+			},
+		},
+		flags: append(flags, "-psk", "secret"),
+	})
+	testCases = append(testCases, testCase{
+		protocol: protocol,
+		testType: serverTest,
+		name:     "EmptyPSKHint-Server" + suffix,
+		config: Config{
+			CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
+			PreSharedKey: []byte("secret"),
+			Bugs: ProtocolBugs{
+				MaxHandshakeRecordLength: maxHandshakeRecordLength,
+			},
+		},
+		flags: append(flags, "-psk", "secret"),
+	})
+
 	if protocol == tls {
 		// NPN on client and server; results in post-handshake message.
 		testCases = append(testCases, testCase{
@@ -1568,7 +1709,7 @@
 			},
 		},
 		resumeSession: true,
-		shouldFail: true,
+		shouldFail:    true,
 		expectedError: ":DECODE_ERROR:",
 	})
 }
@@ -1635,6 +1776,84 @@
 	}
 }
 
+func addRenegotiationTests() {
+	testCases = append(testCases, testCase{
+		testType:        serverTest,
+		name:            "Renegotiate-Server",
+		flags:           []string{"-renegotiate"},
+		shimWritesFirst: true,
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "Renegotiate-Server-EmptyExt",
+		config: Config{
+			Bugs: ProtocolBugs{
+				EmptyRenegotiationInfo: true,
+			},
+		},
+		flags:           []string{"-renegotiate"},
+		shimWritesFirst: true,
+		shouldFail:      true,
+		expectedError:   ":RENEGOTIATION_MISMATCH:",
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "Renegotiate-Server-BadExt",
+		config: Config{
+			Bugs: ProtocolBugs{
+				BadRenegotiationInfo: true,
+			},
+		},
+		flags:           []string{"-renegotiate"},
+		shimWritesFirst: true,
+		shouldFail:      true,
+		expectedError:   ":RENEGOTIATION_MISMATCH:",
+	})
+	// TODO(agl): test the renegotiation info SCSV.
+	testCases = append(testCases, testCase{
+		name:        "Renegotiate-Client",
+		renegotiate: true,
+	})
+	testCases = append(testCases, testCase{
+		name:        "Renegotiate-Client-EmptyExt",
+		renegotiate: true,
+		config: Config{
+			Bugs: ProtocolBugs{
+				EmptyRenegotiationInfo: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":RENEGOTIATION_MISMATCH:",
+	})
+	testCases = append(testCases, testCase{
+		name:        "Renegotiate-Client-BadExt",
+		renegotiate: true,
+		config: Config{
+			Bugs: ProtocolBugs{
+				BadRenegotiationInfo: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":RENEGOTIATION_MISMATCH:",
+	})
+	testCases = append(testCases, testCase{
+		name:        "Renegotiate-Client-SwitchCiphers",
+		renegotiate: true,
+		config: Config{
+			CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		},
+		renegotiateCiphers: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+	})
+	testCases = append(testCases, testCase{
+		name:        "Renegotiate-Client-SwitchCiphers2",
+		renegotiate: true,
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+		},
+		renegotiateCiphers: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+	})
+}
+
 func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
@@ -1690,6 +1909,8 @@
 	addD5BugTests()
 	addExtensionTests()
 	addResumptionVersionTests()
+	addExtendedMasterSecretTests()
+	addRenegotiationTests()
 	for _, async := range []bool{false, true} {
 		for _, splitHandshake := range []bool{false, true} {
 			for _, protocol := range []protocol{tls, dtls} {
diff --git a/ssl/test/runner/ticket.go b/ssl/test/runner/ticket.go
index 74791d6..8355822 100644
--- a/ssl/test/runner/ticket.go
+++ b/ssl/test/runner/ticket.go
@@ -18,11 +18,12 @@
 // sessionState contains the information that is serialized into a session
 // ticket in order to later resume a connection.
 type sessionState struct {
-	vers          uint16
-	cipherSuite   uint16
-	masterSecret  []byte
-	handshakeHash []byte
-	certificates  [][]byte
+	vers                 uint16
+	cipherSuite          uint16
+	masterSecret         []byte
+	handshakeHash        []byte
+	certificates         [][]byte
+	extendedMasterSecret bool
 }
 
 func (s *sessionState) equal(i interface{}) bool {
@@ -34,7 +35,8 @@
 	if s.vers != s1.vers ||
 		s.cipherSuite != s1.cipherSuite ||
 		!bytes.Equal(s.masterSecret, s1.masterSecret) ||
-		!bytes.Equal(s.handshakeHash, s1.handshakeHash) {
+		!bytes.Equal(s.handshakeHash, s1.handshakeHash) ||
+		s.extendedMasterSecret != s1.extendedMasterSecret {
 		return false
 	}
 
@@ -56,6 +58,7 @@
 	for _, cert := range s.certificates {
 		length += 4 + len(cert)
 	}
+	length++
 
 	ret := make([]byte, length)
 	x := ret
@@ -88,6 +91,11 @@
 		x = x[4+len(cert):]
 	}
 
+	if s.extendedMasterSecret {
+		x[0] = 1
+	}
+	x = x[1:]
+
 	return ret
 }
 
@@ -144,6 +152,16 @@
 		data = data[certLen:]
 	}
 
+	if len(data) < 1 {
+		return false
+	}
+
+	s.extendedMasterSecret = false
+	if data[0] == 1 {
+		s.extendedMasterSecret = true
+	}
+	data = data[1:]
+
 	if len(data) > 0 {
 		return false
 	}
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 270fbfb..b717bd3 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -57,6 +57,9 @@
   { "-shim-writes-first", &TestConfig::shim_writes_first },
   { "-tls-d5-bug", &TestConfig::tls_d5_bug },
   { "-expect-session-miss", &TestConfig::expect_session_miss },
+  { "-expect-extended-master-secret",
+    &TestConfig::expect_extended_master_secret },
+  { "-renegotiate", &TestConfig::renegotiate },
 };
 
 const size_t kNumBoolFlags = sizeof(kBoolFlags) / sizeof(kBoolFlags[0]);
@@ -74,6 +77,8 @@
   { "-expect-alpn", &TestConfig::expected_alpn },
   { "-expect-advertised-alpn", &TestConfig::expected_advertised_alpn },
   { "-select-alpn", &TestConfig::select_alpn },
+  { "-psk", &TestConfig::psk },
+  { "-psk-identity", &TestConfig::psk_identity },
 };
 
 const size_t kNumStringFlags = sizeof(kStringFlags) / sizeof(kStringFlags[0]);
@@ -105,7 +110,9 @@
       cookie_exchange(false),
       shim_writes_first(false),
       tls_d5_bug(false),
-      expect_session_miss(false) {
+      expect_session_miss(false),
+      expect_extended_master_secret(false),
+      renegotiate(false) {
 }
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config) {
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index acce504..2dc4dc1 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -53,6 +53,10 @@
   std::string expected_advertised_alpn;
   std::string select_alpn;
   bool expect_session_miss;
+  bool expect_extended_master_secret;
+  std::string psk;
+  std::string psk_identity;
+  bool renegotiate;
 };
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config);
diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt
index e513c8b..e504838 100644
--- a/tool/CMakeLists.txt
+++ b/tool/CMakeLists.txt
@@ -11,7 +11,7 @@
 	tool.cc
 )
 
-if (APPLE)
+if (APPLE OR WIN32)
 	target_link_libraries(bssl ssl crypto)
 else()
 	target_link_libraries(bssl ssl crypto -lrt)
diff --git a/tool/client.cc b/tool/client.cc
index d7d9e22..21ea8ba 100644
--- a/tool/client.cc
+++ b/tool/client.cc
@@ -14,6 +14,9 @@
 
 #include <openssl/base.h>
 
+// TODO(davidben): bssl client does not work on Windows.
+#if !defined(OPENSSL_WINDOWS)
+
 #include <string>
 #include <vector>
 
@@ -47,6 +50,10 @@
      "The hostname and port of the server to connect to, e.g. foo.com:443",
     },
     {
+     "-cipher", false,
+     "An OpenSSL-style cipher suite string that configures the offered ciphers",
+    },
+    {
      "", false, "",
     },
 };
@@ -265,6 +272,10 @@
     SSL_CTX_set_keylog_bio(ctx, keylog_bio);
   }
 
+  if (args_map.count("-cipher") != 0) {
+    SSL_CTX_set_cipher_list(ctx, args_map["-cipher"].c_str());
+  }
+
   int sock = -1;
   if (!Connect(&sock, args_map["-connect"])) {
     return false;
@@ -291,3 +302,5 @@
   SSL_CTX_free(ctx);
   return ok;
 }
+
+#endif  // !OPENSSL_WINDOWS
\ No newline at end of file
diff --git a/tool/pkcs12.cc b/tool/pkcs12.cc
index d35ba0b..fca8bb2 100644
--- a/tool/pkcs12.cc
+++ b/tool/pkcs12.cc
@@ -12,6 +12,8 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
+#include <openssl/base.h>
+
 #include <memory>
 #include <string>
 #include <vector>
@@ -21,7 +23,11 @@
 #include <stdint.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#if defined(OPENSSL_WINDOWS)
+#include <io.h>
+#else
 #include <unistd.h>
+#endif
 
 #include <openssl/bytestring.h>
 #include <openssl/pem.h>
@@ -31,6 +37,12 @@
 #include "internal.h"
 
 
+#if defined(OPENSSL_WINDOWS)
+typedef int read_result_t;
+#else
+typedef ssize_t read_result_t;
+#endif
+
 static const struct argument kArguments[] = {
     {
      "-dump", false, "Dump the key and contents of the given file to stdout",
@@ -64,7 +76,7 @@
   const size_t size = st.st_size;
 
   std::unique_ptr<uint8_t[]> contents(new uint8_t[size]);
-  ssize_t n;
+  read_result_t n;
   size_t off = 0;
   do {
     n = read(fd, &contents[off], size - off);
diff --git a/tool/tool.cc b/tool/tool.cc
index a0866d7..f35cc7c 100644
--- a/tool/tool.cc
+++ b/tool/tool.cc
@@ -19,7 +19,9 @@
 #include <openssl/ssl.h>
 
 
+#if !defined(OPENSSL_WINDOWS)
 bool Client(const std::vector<std::string> &args);
+#endif
 bool DoPKCS12(const std::vector<std::string> &args);
 bool Speed(const std::vector<std::string> &args);
 
@@ -42,8 +44,10 @@
 
   if (tool == "speed") {
     return !Speed(args);
+#if !defined(OPENSSL_WINDOWS)
   } else if (tool == "s_client" || tool == "client") {
     return !Client(args);
+#endif
   } else if (tool == "pkcs12") {
     return !DoPKCS12(args);
   } else {
diff --git a/util/all_tests.sh b/util/all_tests.sh
index de6800f..f6188d1 100644
--- a/util/all_tests.sh
+++ b/util/all_tests.sh
@@ -36,7 +36,7 @@
 ./crypto/ec/example_mul
 ./crypto/ecdsa/ecdsa_test
 ./crypto/err/err_test
-./crypto/evp/example_sign
+./crypto/evp/evp_test
 ./crypto/hmac/hmac_test
 ./crypto/lhash/lhash_test
 ./crypto/md5/md5_test