Merge from Chromium at DEPS revision 267aeeb8d85c

This commit was generated by merge_to_master.py.

Change-Id: I9b1c013632df72dcd4e450d6a3b7749444191f77
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index cbfcd73..5d656ec 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -71,6 +71,7 @@
 
 # Level 0.2 - depends on nothing but itself
 add_subdirectory(sha)
+add_subdirectory(md4)
 add_subdirectory(md5)
 add_subdirectory(modes)
 add_subdirectory(aes)
@@ -112,6 +113,7 @@
 	crypto
 	STATIC
 
+	crypto.c
 	crypto_error.c
 	mem.c
 	thread.c
@@ -129,6 +131,7 @@
 	$<TARGET_OBJECTS:base64>
 	$<TARGET_OBJECTS:bytestring>
 	$<TARGET_OBJECTS:sha>
+	$<TARGET_OBJECTS:md4>
 	$<TARGET_OBJECTS:md5>
 	$<TARGET_OBJECTS:digest>
 	$<TARGET_OBJECTS:cipher>
diff --git a/crypto/asn1/a_strnid.c b/crypto/asn1/a_strnid.c
index ded339a..e61de70 100644
--- a/crypto/asn1/a_strnid.c
+++ b/crypto/asn1/a_strnid.c
@@ -251,7 +251,8 @@
 
 #ifdef STRING_TABLE_TEST
 
-main()
+int
+main(void)
 {
 	ASN1_STRING_TABLE *tmp;
 	int i, last_nid = -1;
@@ -278,6 +279,7 @@
 			printf("Index %d, NID %d, Name=%s\n", i, tmp->nid,
 							OBJ_nid2ln(tmp->nid));
 
+	return 0;
 }
 
 #endif
diff --git a/crypto/base64/base64.c b/crypto/base64/base64.c
index 2336cf5..5fe23a5 100644
--- a/crypto/base64/base64.c
+++ b/crypto/base64/base64.c
@@ -64,8 +64,6 @@
     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 #define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f])
-/* TODO(davidben): This doesn't error on bytes above 127. */
-#define conv_ascii2bin(a) (data_ascii2bin[(a) & 0x7f])
 
 /* 64 char lines
  * pad input with 0
@@ -91,13 +89,13 @@
 #define B64_ERROR 0xFF
 #define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3)
 
-static const unsigned char data_ascii2bin[128] = {
+static const uint8_t data_ascii2bin[128] = {
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF,
     0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
-    0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
     0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
     0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
@@ -105,6 +103,13 @@
     0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 };
 
+static uint8_t conv_ascii2bin(uint8_t a) {
+  if (a >= 128) {
+    return 0xFF;
+  }
+  return data_ascii2bin[a];
+}
+
 void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) {
   ctx->length = 48;
   ctx->num = 0;
@@ -200,6 +205,62 @@
   return ret;
 }
 
+int EVP_DecodedLength(size_t *out_len, size_t len) {
+  if (len % 4 != 0) {
+    return 0;
+  }
+  *out_len = (len / 4) * 3;
+  return 1;
+}
+
+int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out,
+                     const uint8_t *in, size_t in_len) {
+  uint8_t a, b, c, d;
+  size_t pad_len = 0, len = 0, max_len, i;
+  uint32_t l;
+
+  if (!EVP_DecodedLength(&max_len, in_len) || max_out < max_len) {
+    return 0;
+  }
+
+  for (i = 0; i < in_len; i += 4) {
+    a = conv_ascii2bin(*(in++));
+    b = conv_ascii2bin(*(in++));
+    if (i + 4 == in_len && in[1] == '=') {
+        if (in[0] == '=') {
+          pad_len = 2;
+        } else {
+          pad_len = 1;
+        }
+    }
+    if (pad_len < 2) {
+      c = conv_ascii2bin(*(in++));
+    } else {
+      c = 0;
+    }
+    if (pad_len < 1) {
+      d = conv_ascii2bin(*(in++));
+    } else {
+      d = 0;
+    }
+    if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
+      return 0;
+    }
+    l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) |
+         (((uint32_t)c) << 6L) | (((uint32_t)d)));
+    *(out++) = (uint8_t)(l >> 16L) & 0xff;
+    if (pad_len < 2) {
+      *(out++) = (uint8_t)(l >> 8L) & 0xff;
+    }
+    if (pad_len < 1) {
+      *(out++) = (uint8_t)(l) & 0xff;
+    }
+    len += 3 - pad_len;
+  }
+  *out_len = len;
+  return 1;
+}
+
 void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
   ctx->length = 30;
   ctx->num = 0;
@@ -304,6 +365,7 @@
         exp_nl = 1;
       }
       if (n > 0) {
+        /* TODO(davidben): Switch this to EVP_DecodeBase64. */
         v = EVP_DecodeBlock(out, d, n);
         n = 0;
         if (v < 0) {
@@ -347,6 +409,7 @@
 
   *outl = 0;
   if (ctx->num != 0) {
+    /* TODO(davidben): Switch this to EVP_DecodeBase64. */
     i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num);
     if (i < 0) {
       return -1;
@@ -360,9 +423,7 @@
 }
 
 int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
-  int a, b, c, d;
-  uint32_t l;
-  size_t i, ret = 0;
+  size_t dst_len;
 
   /* trim white space from the start of the line. */
   while (conv_ascii2bin(*src) == B64_WS && src_len > 0) {
@@ -376,31 +437,21 @@
     src_len--;
   }
 
-  if (src_len % 4 != 0) {
+  if (!EVP_DecodedLength(&dst_len, src_len) || dst_len > INT_MAX) {
+    return -1;
+  }
+  if (!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) {
     return -1;
   }
 
-  for (i = 0; i < src_len; i += 4) {
-    a = conv_ascii2bin(*(src++));
-    b = conv_ascii2bin(*(src++));
-    c = conv_ascii2bin(*(src++));
-    d = conv_ascii2bin(*(src++));
-    if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
-      return -1;
-    }
-    l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) |
-         (((uint32_t)c) << 6L) | (((uint32_t)d)));
-    *(dst++) = (uint8_t)(l >> 16L) & 0xff;
-    *(dst++) = (uint8_t)(l >> 8L) & 0xff;
-    *(dst++) = (uint8_t)(l) & 0xff;
-    ret += 3;
+  /* EVP_DecodeBlock does not take padding into account, so put the
+   * NULs back in... so the caller can strip them back out. */
+  while (dst_len % 3 != 0) {
+    dst[dst_len++] = '\0';
   }
+  assert(dst_len <= INT_MAX);
 
-  if (ret > INT_MAX) {
-    return -1;
-  }
-
-  return ret;
+  return dst_len;
 }
 
 int EVP_EncodedLength(size_t *out_len, size_t len) {
diff --git a/crypto/base64/base64_test.c b/crypto/base64/base64_test.c
index 0cd2b6e..e208e81 100644
--- a/crypto/base64/base64_test.c
+++ b/crypto/base64/base64_test.c
@@ -16,6 +16,7 @@
 #include <string.h>
 
 #include <openssl/base64.h>
+#include <openssl/crypto.h>
 #include <openssl/err.h>
 
 
@@ -37,7 +38,7 @@
 
 static const size_t kNumTests = sizeof(test_vectors) / sizeof(test_vectors[0]);
 
-static int test_encode() {
+static int test_encode(void) {
   uint8_t out[9];
   size_t i;
   ssize_t len;
@@ -55,19 +56,19 @@
   return 1;
 }
 
-static int test_decode() {
+static int test_decode(void) {
   uint8_t out[6];
-  size_t i;
-  ssize_t len;
+  size_t i, len;
+  int ret;
 
   for (i = 0; i < kNumTests; i++) {
+    /* Test the normal API. */
     const TEST_VECTOR *t = &test_vectors[i];
     size_t expected_len = strlen(t->decoded);
-    len = EVP_DecodeBlock(out, (const uint8_t*)t->encoded, strlen(t->encoded));
-    /* TODO(davidben): EVP_DecodeBlock doesn't take padding into account. Is
-     * this behavior we can change? */
-    if (expected_len % 3 != 0) {
-      len -= 3 - (expected_len % 3);
+    if (!EVP_DecodeBase64(out, &len, sizeof(out),
+                          (const uint8_t*)t->encoded, strlen(t->encoded))) {
+      fprintf(stderr, "decode(\"%s\") failed\n", t->encoded);
+      return 0;
     }
     if (len != strlen(t->decoded) ||
         memcmp(out, t->decoded, len) != 0) {
@@ -75,14 +76,40 @@
               t->encoded, (int)len, (const char*)out, t->decoded);
       return 0;
     }
+
+    /* Test that the padding behavior of the deprecated API is
+     * preserved. */
+    ret = EVP_DecodeBlock(out, (const uint8_t*)t->encoded, strlen(t->encoded));
+    if (ret < 0) {
+      fprintf(stderr, "decode(\"%s\") failed\n", t->encoded);
+      return 0;
+    }
+    if (ret % 3 != 0) {
+      fprintf(stderr, "EVP_DecodeBlock did not ignore padding\n");
+      return 0;
+    }
+    if (expected_len % 3 != 0) {
+      ret -= 3 - (expected_len % 3);
+    }
+    if (ret != strlen(t->decoded) ||
+        memcmp(out, t->decoded, ret) != 0) {
+      fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
+              t->encoded, ret, (const char*)out, t->decoded);
+      return 0;
+    }
   }
 
-  if (EVP_DecodeBlock(out, (const uint8_t*)"a!bc", 4) >= 0) {
+  if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"a!bc", 4)) {
     fprintf(stderr, "Failed to reject invalid characters in the middle.\n");
     return 0;
   }
 
-  if (EVP_DecodeBlock(out, (const uint8_t*)"abc", 3) >= 0) {
+  if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"a=bc", 4)) {
+    fprintf(stderr, "Failed to reject invalid characters in the middle.\n");
+    return 0;
+  }
+
+  if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"abc", 4)) {
     fprintf(stderr, "Failed to reject invalid input length.\n");
     return 0;
   }
@@ -90,7 +117,8 @@
   return 1;
 }
 
-int main() {
+int main(void) {
+  CRYPTO_library_init();
   ERR_load_crypto_strings();
 
   if (!test_encode()) {
diff --git a/crypto/bio/bio.c b/crypto/bio/bio.c
index a35ff65..7bd2976 100644
--- a/crypto/bio/bio.c
+++ b/crypto/bio/bio.c
@@ -351,6 +351,10 @@
   return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
 }
 
+size_t BIO_ctrl_pending(const BIO *bio) {
+  return BIO_pending(bio);
+}
+
 size_t BIO_wpending(const BIO *bio) {
   return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
 }
diff --git a/crypto/bio/bio_mem.c b/crypto/bio/bio_mem.c
index 457c2e0..6e90db5 100644
--- a/crypto/bio/bio_mem.c
+++ b/crypto/bio/bio_mem.c
@@ -132,13 +132,12 @@
 }
 
 static int mem_read(BIO *bio, char *out, int outl) {
-  int ret = -1;
-  BUF_MEM *b;
+  int ret;
+  BUF_MEM *b = (BUF_MEM*) bio->ptr;
 
-  b = (BUF_MEM *)bio->ptr;
   BIO_clear_retry_flags(bio);
   ret = outl;
-  if (ret > (int)b->length) {
+  if (b->length < INT_MAX && ret > (int)b->length) {
     ret = b->length;
   }
 
diff --git a/crypto/bio/bio_test.c b/crypto/bio/bio_test.c
index f3075b8..beb3849 100644
--- a/crypto/bio/bio_test.c
+++ b/crypto/bio/bio_test.c
@@ -22,10 +22,11 @@
 #include <unistd.h>
 
 #include <openssl/bio.h>
+#include <openssl/crypto.h>
 #include <openssl/err.h>
 
 
-static int test_socket_connect() {
+static int test_socket_connect(void) {
   int listening_sock = socket(AF_INET, SOCK_STREAM, 0);
   int sock;
   struct sockaddr_in sin;
@@ -94,7 +95,7 @@
   return 1;
 }
 
-static int test_printf() {
+static int test_printf(void) {
   /* Test a short output, a very long one, and various sizes around
    * 256 (the size of the buffer) to ensure edge cases are correct. */
   static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
@@ -144,7 +145,8 @@
   return 1;
 }
 
-int main() {
+int main(void) {
+  CRYPTO_library_init();
   ERR_load_crypto_strings();
 
   if (!test_socket_connect()) {
diff --git a/crypto/bio/internal.h b/crypto/bio/internal.h
index dd3d800..ba28839 100644
--- a/crypto/bio/internal.h
+++ b/crypto/bio/internal.h
@@ -92,7 +92,7 @@
 /* BIO_clear_socket_error clears the last system socket error.
  *
  * TODO(fork): remove all callers of this. */
-void bio_clear_socket_error();
+void bio_clear_socket_error(void);
 
 /* BIO_sock_error returns the last socket error on |sock|. */
 int bio_sock_error(int sock);
diff --git a/crypto/bio/socket_helper.c b/crypto/bio/socket_helper.c
index 0d7d21a..ba65a1a 100644
--- a/crypto/bio/socket_helper.c
+++ b/crypto/bio/socket_helper.c
@@ -97,7 +97,7 @@
 #endif
 }
 
-void bio_clear_socket_error() {}
+void bio_clear_socket_error(void) {}
 
 int bio_sock_error(int sock) {
   int error;
diff --git a/crypto/bn/bn_test.c b/crypto/bn/bn_test.c
index 440e1b6..11b3c62 100644
--- a/crypto/bn/bn_test.c
+++ b/crypto/bn/bn_test.c
@@ -71,6 +71,7 @@
 
 #include <openssl/bio.h>
 #include <openssl/bn.h>
+#include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
 
@@ -99,7 +100,7 @@
 int test_mod_exp_mont_consttime(BIO *bp, BN_CTX *ctx);
 int test_exp(BIO *bp, BN_CTX *ctx);
 int test_mod_sqrt(BIO *bp, BN_CTX *ctx);
-static int test_exp_mod_zero();
+static int test_exp_mod_zero(void);
 int test_small_prime(BIO *bp,BN_CTX *ctx);
 int test_mod_exp_mont5(BIO *bp, BN_CTX *ctx);
 int test_sqrt(BIO *bp, BN_CTX *ctx);
@@ -135,6 +136,8 @@
   BIO *out = NULL;
   char *outfile = NULL;
 
+  CRYPTO_library_init();
+
   results = 0;
 
   argc--;
@@ -1129,7 +1132,7 @@
 }
 
 /* test_exp_mod_zero tests that x**0 mod 1 == 0. */
-static int test_exp_mod_zero() {
+static int test_exp_mod_zero(void) {
   BIGNUM a, p, m;
   BIGNUM r;
   BN_CTX *ctx = BN_CTX_new();
diff --git a/crypto/bn/rsaz_exp.h b/crypto/bn/rsaz_exp.h
index 4241a1f..0bb6b0c 100644
--- a/crypto/bn/rsaz_exp.h
+++ b/crypto/bn/rsaz_exp.h
@@ -36,7 +36,7 @@
 void RSAZ_1024_mod_exp_avx2(BN_ULONG result[16],
 	const BN_ULONG base_norm[16], const BN_ULONG exponent[16],
 	const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0);
-int rsaz_avx2_eligible();
+int rsaz_avx2_eligible(void);
 
 void RSAZ_512_mod_exp(BN_ULONG result[8],
 	const BN_ULONG base_norm[8], const BN_ULONG exponent[8],
diff --git a/crypto/bytestring/CMakeLists.txt b/crypto/bytestring/CMakeLists.txt
index 409a0ce..dc48583 100644
--- a/crypto/bytestring/CMakeLists.txt
+++ b/crypto/bytestring/CMakeLists.txt
@@ -5,6 +5,7 @@
 
 	OBJECT
 
+	ber.c
 	cbs.c
 	cbb.c
 )
diff --git a/crypto/bytestring/ber.c b/crypto/bytestring/ber.c
new file mode 100644
index 0000000..c96c200
--- /dev/null
+++ b/crypto/bytestring/ber.c
@@ -0,0 +1,215 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/bytestring.h>
+
+#include "internal.h"
+
+
+/* kMaxDepth is a just a sanity limit. The code should be such that the length
+ * of the input being processes always decreases. None the less, a very large
+ * input could otherwise cause the stack to overflow. */
+static const unsigned kMaxDepth = 2048;
+
+/* cbs_find_ber walks an ASN.1 structure in |orig_in| and sets |*ber_found|
+ * depending on whether an indefinite length element was found. The value of
+ * |in| is not changed. It returns one on success (i.e. |*ber_found| was set)
+ * and zero on error. */
+static int cbs_find_ber(CBS *orig_in, char *ber_found, unsigned depth) {
+  CBS in;
+
+  if (depth > kMaxDepth) {
+    return 0;
+  }
+
+  CBS_init(&in, CBS_data(orig_in), CBS_len(orig_in));
+  *ber_found = 0;
+
+  while (CBS_len(&in) > 0) {
+    CBS contents;
+    unsigned tag;
+    size_t header_len;
+
+    if (!CBS_get_any_asn1_element(&in, &contents, &tag, &header_len)) {
+      return 0;
+    }
+    if (CBS_len(&contents) == header_len &&
+        header_len > 0 &&
+        CBS_data(&contents)[header_len-1] == 0x80) {
+      *ber_found = 1;
+      return 1;
+    }
+    if (tag & CBS_ASN1_CONSTRUCTED) {
+      if (!CBS_skip(&contents, header_len) ||
+          !cbs_find_ber(&contents, ber_found, depth + 1)) {
+        return 0;
+      }
+    }
+  }
+
+  return 1;
+}
+
+/* is_primitive_type returns true if |tag| likely a primitive type. Normally
+ * one can just test the "constructed" bit in the tag but, in BER, even
+ * primitive tags can have the constructed bit if they have indefinite
+ * length. */
+static char is_primitive_type(unsigned tag) {
+  return (tag & 0xc0) == 0 &&
+         (tag & 0x1f) != (CBS_ASN1_SEQUENCE & 0x1f) &&
+         (tag & 0x1f) != (CBS_ASN1_SET & 0x1f);
+}
+
+/* is_eoc returns true if |header_len| and |contents|, as returned by
+ * |CBS_get_any_asn1_element|, indicate an "end of contents" (EOC) value. */
+static char is_eoc(size_t header_len, CBS *contents) {
+  return header_len == 2 && CBS_len(contents) == 2 &&
+         memcmp(CBS_data(contents), "\x00\x00", 2) == 0;
+}
+
+/* cbs_convert_ber reads BER data from |in| and writes DER data to |out|. If
+ * |squash_header| is set then the top-level of elements from |in| will not
+ * have their headers written. This is used when concatenating the fragments of
+ * an indefinite length, primitive value. If |looking_for_eoc| is set then any
+ * EOC elements found will cause the function to return after consuming it.
+ * It returns one on success and zero on error. */
+static int cbs_convert_ber(CBS *in, CBB *out, char squash_header,
+                           char looking_for_eoc, unsigned depth) {
+  if (depth > kMaxDepth) {
+    return 0;
+  }
+
+  while (CBS_len(in) > 0) {
+    CBS contents;
+    unsigned tag;
+    size_t header_len;
+    CBB *out_contents, out_contents_storage;
+
+    if (!CBS_get_any_asn1_element(in, &contents, &tag, &header_len)) {
+      return 0;
+    }
+    out_contents = out;
+
+    if (CBS_len(&contents) == header_len) {
+      if (is_eoc(header_len, &contents)) {
+        return looking_for_eoc;
+      }
+
+      if (header_len > 0 && CBS_data(&contents)[header_len - 1] == 0x80) {
+        /* This is an indefinite length element. If it's a SEQUENCE or SET then
+         * we just need to write the out the contents as normal, but with a
+         * concrete length prefix.
+         *
+         * If it's a something else then the contents will be a series of BER
+         * elements of the same type which need to be concatenated. */
+        const char context_specific = (tag & 0xc0) == 0x80;
+        char squash_child_headers = is_primitive_type(tag);
+
+        /* This is a hack, but it sufficies to handle NSS's output. If we find
+         * an indefinite length, context-specific tag with a definite, primtive
+         * tag inside it, then we assume that the context-specific tag is
+         * implicit and the tags within are fragments of a primitive type that
+         * need to be concatenated. */
+        if (context_specific && (tag & CBS_ASN1_CONSTRUCTED)) {
+          CBS in_copy, contents;
+          unsigned tag;
+          size_t header_len;
+
+          CBS_init(&in_copy, CBS_data(in), CBS_len(in));
+          if (!CBS_get_any_asn1_element(&in_copy, &contents, &tag, &header_len)) {
+            return 0;
+          }
+          if (CBS_len(&contents) > header_len && is_primitive_type(tag)) {
+            squash_child_headers = 1;
+          }
+        }
+
+        if (!squash_header) {
+          unsigned out_tag = tag;
+          if (squash_child_headers) {
+            out_tag &= ~CBS_ASN1_CONSTRUCTED;
+          }
+          if (!CBB_add_asn1(out, &out_contents_storage, out_tag)) {
+            return 0;
+          }
+          out_contents = &out_contents_storage;
+        }
+
+        if (!cbs_convert_ber(in, out_contents,
+                             squash_child_headers,
+                             1 /* looking for eoc */, depth + 1)) {
+          return 0;
+        }
+        if (out_contents != out && !CBB_flush(out)) {
+          return 0;
+        }
+        continue;
+      }
+    }
+
+    if (!squash_header) {
+      if (!CBB_add_asn1(out, &out_contents_storage, tag)) {
+        return 0;
+      }
+      out_contents = &out_contents_storage;
+    }
+
+    if (!CBS_skip(&contents, header_len)) {
+      return 0;
+    }
+
+    if (tag & CBS_ASN1_CONSTRUCTED) {
+      if (!cbs_convert_ber(&contents, out_contents, 0 /* don't squash header */,
+                           0 /* not looking for eoc */, depth + 1)) {
+        return 0;
+      }
+    } else {
+      if (!CBB_add_bytes(out_contents, CBS_data(&contents),
+                         CBS_len(&contents))) {
+        return 0;
+      }
+    }
+
+    if (out_contents != out && !CBB_flush(out)) {
+      return 0;
+    }
+  }
+
+  return looking_for_eoc == 0;
+}
+
+int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len) {
+  CBB cbb;
+
+  /* First, do a quick walk to find any indefinite-length elements. Most of the
+   * time we hope that there aren't any and thus we can quickly return. */
+  char conversion_needed;
+  if (!cbs_find_ber(in, &conversion_needed, 0)) {
+    return 0;
+  }
+
+  if (!conversion_needed) {
+    *out = NULL;
+    *out_len = 0;
+    return 1;
+  }
+
+  CBB_init(&cbb, CBS_len(in));
+  if (!cbs_convert_ber(in, &cbb, 0, 0, 0)) {
+    CBB_cleanup(&cbb);
+    return 0;
+  }
+
+  return CBB_finish(&cbb, out, out_len);
+}
diff --git a/crypto/bytestring/bytestring_test.c b/crypto/bytestring/bytestring_test.c
index 20ce571..e4afccd 100644
--- a/crypto/bytestring/bytestring_test.c
+++ b/crypto/bytestring/bytestring_test.c
@@ -15,10 +15,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <openssl/crypto.h>
 #include <openssl/bytestring.h>
 
+#include "internal.h"
 
-static int test_skip() {
+
+static int test_skip(void) {
   static const uint8_t kData[] = {1, 2, 3};
   CBS data;
 
@@ -31,7 +34,7 @@
       !CBS_skip(&data, 1);
 }
 
-static int test_get_u() {
+static int test_get_u(void) {
   static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
   uint8_t u8;
   uint16_t u16;
@@ -50,7 +53,7 @@
     !CBS_get_u8(&data, &u8);
 }
 
-static int test_get_prefixed() {
+static int test_get_prefixed(void) {
   static const uint8_t kData[] = {1, 2, 0, 2, 3, 4, 0, 0, 3, 3, 2, 1};
   uint8_t u8;
   uint16_t u16;
@@ -72,7 +75,7 @@
     u32 == 0x30201;
 }
 
-static int test_get_prefixed_bad() {
+static int test_get_prefixed_bad(void) {
   static const uint8_t kData1[] = {2, 1};
   static const uint8_t kData2[] = {0, 2, 1};
   static const uint8_t kData3[] = {0, 0, 2, 1};
@@ -96,7 +99,7 @@
   return 1;
 }
 
-static int test_get_asn1() {
+static int test_get_asn1(void) {
   static const uint8_t kData1[] = {0x30, 2, 1, 2};
   static const uint8_t kData2[] = {0x30, 3, 1, 2};
   static const uint8_t kData3[] = {0x30, 0x80};
@@ -145,62 +148,7 @@
   return 1;
 }
 
-static int test_get_indef() {
-  static const uint8_t kData1[] = {0x30, 0x80, 0x00, 0x00};
-  static const uint8_t kDataWithoutEOC[] = {0x30, 0x80, 0x01, 0x00};
-  static const uint8_t kDataWithBadInternalLength[] = {0x30, 0x80, 0x01, 0x01};
-  static const uint8_t kDataNested[] = {0x30, 0x80, 0x30, 0x80, 0x30, 0x80,
-                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-  static const uint8_t kDataPrimitive[] = {0x02, 0x80, 0x00, 0x00};
-
-  CBS data, contents;
-  CBS_init(&data, kData1, sizeof(kData1));
-  if (CBS_get_asn1(&data, &contents, 0x30)) {
-    /* Indefinite lengths should not be supported in DER mode. */
-    fprintf(stderr, "Indefinite length parsed by CBS_get_asn1.\n");
-    return 0;
-  }
-
-  if (!CBS_get_asn1_ber(&data, &contents, 0x30) ||
-      CBS_len(&contents) != 0 ||
-      CBS_len(&data) != 0) {
-    fprintf(stderr, "Simple indefinite length failed.\n");
-    return 0;
-  }
-
-  CBS_init(&data, kDataWithoutEOC, sizeof(kDataWithoutEOC));
-  if (CBS_get_asn1_ber(&data, &contents, 0x30)) {
-    fprintf(stderr, "Parsed without EOC.\n");
-    return 0;
-  }
-
-  CBS_init(&data, kDataWithBadInternalLength,
-           sizeof(kDataWithBadInternalLength));
-  if (CBS_get_asn1_ber(&data, &contents, 0x30)) {
-    fprintf(stderr, "Parsed with internal length.\n");
-    return 0;
-  }
-
-  CBS_init(&data, kDataNested, sizeof(kDataNested));
-  if (!CBS_get_asn1_ber(&data, &contents, 0x30) ||
-      CBS_len(&contents) != 8 ||
-      CBS_len(&data) != 0) {
-    fprintf(stderr, "Nested indefinite lengths failed.\n");
-    return 0;
-  }
-
-  CBS_init(&data, kDataPrimitive, sizeof(kDataPrimitive));
-  if (CBS_get_asn1_ber(&data, &contents, 0x02)) {
-    /* Indefinite lengths should not be supported for non-constructed
-     * elements. */
-    fprintf(stderr, "Parsed non-constructed element with indefinite length\n");
-    return 0;
-  }
-
-  return 1;
-}
-
-static int test_cbb_basic() {
+static int test_cbb_basic(void) {
   static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8};
   uint8_t *buf;
   size_t buf_len;
@@ -226,7 +174,7 @@
   return ok;
 }
 
-static int test_cbb_fixed() {
+static int test_cbb_fixed(void) {
   CBB cbb;
   uint8_t buf[1];
   uint8_t *out_buf;
@@ -253,7 +201,7 @@
   return 1;
 }
 
-static int test_cbb_finish_child() {
+static int test_cbb_finish_child(void) {
   CBB cbb, child;
   uint8_t *out_buf;
   size_t out_size;
@@ -271,7 +219,7 @@
   return 1;
 }
 
-static int test_cbb_prefixed() {
+static int test_cbb_prefixed(void) {
   static const uint8_t kExpected[] = {0, 1, 1, 0, 2, 2, 3, 0, 0, 3,
                                       4, 5, 6, 5, 4, 1, 0, 1, 2};
   uint8_t *buf;
@@ -301,7 +249,7 @@
   return ok;
 }
 
-static int test_cbb_misuse() {
+static int test_cbb_misuse(void) {
   CBB cbb, child, contents;
   uint8_t *buf;
   size_t buf_len;
@@ -337,7 +285,7 @@
   return 1;
 }
 
-static int test_cbb_asn1() {
+static int test_cbb_asn1(void) {
   static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3};
   uint8_t *buf, *test_data;
   size_t buf_len;
@@ -405,19 +353,102 @@
   return 1;
 }
 
-int main() {
+static int do_ber_convert(const char *name,
+                          const uint8_t *der_expected, size_t der_len,
+                          const uint8_t *ber, size_t ber_len) {
+  CBS in;
+  uint8_t *out;
+  size_t out_len;
+
+  CBS_init(&in, ber, ber_len);
+  if (!CBS_asn1_ber_to_der(&in, &out, &out_len)) {
+    fprintf(stderr, "%s: CBS_asn1_ber_to_der failed.\n", name);
+    return 0;
+  }
+
+  if (out == NULL) {
+    if (ber_len != der_len ||
+        memcmp(der_expected, ber, ber_len) != 0) {
+      fprintf(stderr, "%s: incorrect unconverted result.\n", name);
+      return 0;
+    }
+
+    return 1;
+  }
+
+  if (out_len != der_len ||
+      memcmp(out, der_expected, der_len) != 0) {
+    fprintf(stderr, "%s: incorrect converted result.\n", name);
+    return 0;
+  }
+
+  free(out);
+  return 1;
+}
+
+static int test_ber_convert(void) {
+  static const uint8_t kSimpleBER[] = {0x01, 0x01, 0x00};
+
+  /* kIndefBER contains a SEQUENCE with an indefinite length. */
+  static const uint8_t kIndefBER[] = {0x30, 0x80, 0x01, 0x01, 0x02, 0x00, 0x00};
+  static const uint8_t kIndefDER[] = {0x30, 0x03, 0x01, 0x01, 0x02};
+
+  /* kOctetStringBER contains an indefinite length OCTETSTRING with two parts.
+   * These parts need to be concatenated in DER form. */
+  static const uint8_t kOctetStringBER[] = {0x24, 0x80, 0x04, 0x02, 0,    1,
+                                            0x04, 0x02, 2,    3,    0x00, 0x00};
+  static const uint8_t kOctetStringDER[] = {0x04, 0x04, 0, 1, 2, 3};
+
+  /* kNSSBER is part of a PKCS#12 message generated by NSS that uses indefinite
+   * length elements extensively. */
+  static const uint8_t kNSSBER[] = {
+      0x30, 0x80, 0x02, 0x01, 0x03, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48,
+      0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x04,
+      0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39,
+      0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
+      0x00, 0x04, 0x14, 0x84, 0x98, 0xfc, 0x66, 0x33, 0xee, 0xba, 0xe7, 0x90,
+      0xc1, 0xb6, 0xe8, 0x8f, 0xfe, 0x1d, 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04,
+      0x10, 0x38, 0x62, 0xc6, 0x44, 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b,
+      0xf0, 0x6e, 0x10, 0x9b, 0xb8, 0x02, 0x02, 0x07, 0xd0, 0x00, 0x00,
+  };
+
+  static const uint8_t kNSSDER[] = {
+      0x30, 0x53, 0x02, 0x01, 0x03, 0x30, 0x13, 0x06, 0x09, 0x2a, 0x86,
+      0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x06, 0x04, 0x04,
+      0x01, 0x02, 0x03, 0x04, 0x30, 0x39, 0x30, 0x21, 0x30, 0x09, 0x06,
+      0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x84,
+      0x98, 0xfc, 0x66, 0x33, 0xee, 0xba, 0xe7, 0x90, 0xc1, 0xb6, 0xe8,
+      0x8f, 0xfe, 0x1d, 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04, 0x10, 0x38,
+      0x62, 0xc6, 0x44, 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b, 0xf0,
+      0x6e, 0x10, 0x9b, 0xb8, 0x02, 0x02, 0x07, 0xd0,
+  };
+
+  return do_ber_convert("kSimpleBER", kSimpleBER, sizeof(kSimpleBER),
+                        kSimpleBER, sizeof(kSimpleBER)) &&
+         do_ber_convert("kIndefBER", kIndefDER, sizeof(kIndefDER), kIndefBER,
+                        sizeof(kIndefBER)) &&
+         do_ber_convert("kOctetStringBER", kOctetStringDER,
+                        sizeof(kOctetStringDER), kOctetStringBER,
+                        sizeof(kOctetStringBER)) &&
+         do_ber_convert("kNSSBER", kNSSDER, sizeof(kNSSDER), kNSSBER,
+                        sizeof(kNSSBER));
+}
+
+int main(void) {
+  CRYPTO_library_init();
+
   if (!test_skip() ||
       !test_get_u() ||
       !test_get_prefixed() ||
       !test_get_prefixed_bad() ||
       !test_get_asn1() ||
-      !test_get_indef() ||
       !test_cbb_basic() ||
       !test_cbb_fixed() ||
       !test_cbb_finish_child() ||
       !test_cbb_misuse() ||
       !test_cbb_prefixed() ||
-      !test_cbb_asn1()) {
+      !test_cbb_asn1() ||
+      !test_ber_convert()) {
     return 1;
   }
 
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
index 547b5a4..244daba 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -19,6 +19,8 @@
 #include <assert.h>
 #include <string.h>
 
+#include "internal.h"
+
 
 void CBS_init(CBS *cbs, const uint8_t *data, size_t len) {
   cbs->data = data;
@@ -156,52 +158,16 @@
   return cbs_get_length_prefixed(cbs, out, 3);
 }
 
-static int cbs_get_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
-                                size_t *out_header_len, unsigned depth,
-                                int *was_indefinite_len);
-
-/* cbs_get_asn1_indefinite_len sets |*out| to be a CBS that covers an
- * indefinite length element in |cbs| and advances |*in|. On entry, |cbs| will
- * not have had the tag and length byte removed. On exit, |*out| does not cover
- * the EOC element, but |*in| is skipped over it.
- *
- * The |depth| argument counts the number of times the code has recursed trying
- * to find an indefinite length. */
-static int cbs_get_asn1_indefinite_len(CBS *in, CBS *out, unsigned depth) {
-  static const size_t kEOCLength = 2;
-  size_t header_len;
-  unsigned tag;
-  int was_indefinite_len;
-  CBS orig = *in, child;
-
-  if (!CBS_skip(in, 2 /* tag plus 0x80 byte for indefinite len */)) {
-    return 0;
-  }
-
-  for (;;) {
-    if (!cbs_get_asn1_element(in, &child, &tag, &header_len, depth + 1,
-                              &was_indefinite_len)) {
-      return 0;
-    }
-
-    if (!was_indefinite_len && CBS_len(&child) == kEOCLength &&
-        header_len == kEOCLength && tag == 0) {
-      break;
-    }
-  }
-
-  return CBS_get_bytes(&orig, out, CBS_len(&orig) - CBS_len(in) - kEOCLength);
-}
-
-/* MAX_DEPTH the maximum number of levels of indefinite lengths that we'll
- * support. */
-#define MAX_DEPTH 64
-
-static int cbs_get_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
-                                size_t *out_header_len, unsigned depth,
-                                int *was_indefinite_len) {
+int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
+                             size_t *out_header_len) {
   uint8_t tag, length_byte;
   CBS header = *cbs;
+  CBS throwaway;
+
+  if (out == NULL) {
+    out = &throwaway;
+  }
+
   if (!CBS_get_u8(&header, &tag) ||
       !CBS_get_u8(&header, &length_byte)) {
     return 0;
@@ -212,29 +178,26 @@
     return 0;
   }
 
-  *out_tag = tag;
-  if (was_indefinite_len) {
-    *was_indefinite_len = 0;
+  if (out_tag != NULL) {
+    *out_tag = tag;
   }
 
   size_t len;
   if ((length_byte & 0x80) == 0) {
     /* Short form length. */
     len = ((size_t) length_byte) + 2;
-    *out_header_len = 2;
+    if (out_header_len != NULL) {
+      *out_header_len = 2;
+    }
   } else {
     /* Long form length. */
     const size_t num_bytes = length_byte & 0x7f;
     uint32_t len32;
 
-    if ((tag & CBS_ASN1_CONSTRUCTED) != 0 && depth < MAX_DEPTH &&
-        num_bytes == 0) {
+    if ((tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) {
       /* indefinite length */
       *out_header_len = 2;
-      if (was_indefinite_len) {
-        *was_indefinite_len = 1;
-      }
-      return cbs_get_asn1_indefinite_len(cbs, out, depth);
+      return CBS_get_bytes(cbs, out, 2);
     }
 
     if (num_bytes == 0 || num_bytes > 4) {
@@ -257,13 +220,15 @@
       return 0;
     }
     len += 2 + num_bytes;
-    *out_header_len = 2 + num_bytes;
+    if (out_header_len != NULL) {
+      *out_header_len = 2 + num_bytes;
+    }
   }
 
   return CBS_get_bytes(cbs, out, len);
 }
 
-static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value, int ber,
+static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value,
                         int skip_header) {
   size_t header_len;
   unsigned tag;
@@ -273,9 +238,13 @@
     out = &throwaway;
   }
 
-  if (!cbs_get_asn1_element(cbs, out, &tag, &header_len, ber ? 0 : MAX_DEPTH,
-                            NULL) ||
-      tag != tag_value) {
+  if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
+      tag != tag_value ||
+      (header_len > 0 &&
+       /* This ensures that the tag is either zero length or
+        * indefinite-length. */
+       CBS_len(out) == header_len &&
+       CBS_data(out)[header_len - 1] == 0x80)) {
     return 0;
   }
 
@@ -288,16 +257,39 @@
 }
 
 int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) {
-  return cbs_get_asn1(cbs, out, tag_value, 0 /* DER */,
-                      1 /* skip header */);
-}
-
-int CBS_get_asn1_ber(CBS *cbs, CBS *out, unsigned tag_value) {
-  return cbs_get_asn1(cbs, out, tag_value, 1 /* BER */,
-                      1 /* skip header */);
+  return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
 }
 
 int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) {
-  return cbs_get_asn1(cbs, out, tag_value, 0 /* DER */,
-                      0 /* include header */);
+  return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
+}
+
+int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
+  CBS bytes;
+  const uint8_t *data;
+  size_t i, len;
+
+  if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) {
+    return 0;
+  }
+
+  *out = 0;
+  data = CBS_data(&bytes);
+  len = CBS_len(&bytes);
+
+  if (len > 0 && (data[0] & 0x80) != 0) {
+    /* negative number */
+    return 0;
+  }
+
+  for (i = 0; i < len; i++) {
+    if ((*out >> 56) != 0) {
+      /* Too large to represent as a uint64_t. */
+      return 0;
+    }
+    *out <<= 8;
+    *out |= data[i];
+  }
+
+  return 1;
 }
diff --git a/crypto/bytestring/internal.h b/crypto/bytestring/internal.h
new file mode 100644
index 0000000..b4ea7e5
--- /dev/null
+++ b/crypto/bytestring/internal.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_BYTESTRING_INTERNAL_H
+#define OPENSSL_HEADER_BYTESTRING_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* CBS_asn1_ber_to_der reads an ASN.1 structure from |in|. If it finds
+ * indefinite-length elements then it attempts to convert the BER data to DER
+ * and sets |*out| and |*out_length| to describe a malloced buffer containing
+ * the DER data. Additionally, |*in| will be advanced over the ASN.1 data.
+ *
+ * If it doesn't find any indefinite-length elements then it sets |*out| to
+ * NULL and |*in| is unmodified.
+ *
+ * A sufficiently complex ASN.1 structure will break this function because it's
+ * not possible to generically convert BER to DER without knowledge of the
+ * structure itself. However, this sufficies to handle the PKCS#7 and #12 output
+ * from NSS.
+ *
+ * It returns one on success and zero otherwise. */
+OPENSSL_EXPORT int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len);
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
+
+#endif  /* OPENSSL_HEADER_BYTESTRING_INTERNAL_H */
diff --git a/crypto/chacha/chacha_generic.c b/crypto/chacha/chacha_generic.c
index 40a6f20..c497980 100644
--- a/crypto/chacha/chacha_generic.c
+++ b/crypto/chacha/chacha_generic.c
@@ -47,7 +47,7 @@
   x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
   x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
 
-#if defined(OPENSSL_ARM)
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
 /* Defined in chacha_vec.c */
 void CRYPTO_chacha_20_neon(uint8_t *out, const uint8_t *in, size_t in_len,
                            const uint8_t key[32], const uint8_t nonce[8],
@@ -87,7 +87,7 @@
   uint8_t buf[64];
   size_t todo, i;
 
-#if defined(OPENSSL_ARM)
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
   if (CRYPTO_is_NEON_capable() && ((intptr_t)in & 15) == 0 &&
       ((intptr_t)out & 15) == 0) {
     CRYPTO_chacha_20_neon(out, in, in_len, key, nonce, counter);
diff --git a/crypto/chacha/chacha_vec_arm.S b/crypto/chacha/chacha_vec_arm.S
index be87ab3..535e20a 100644
--- a/crypto/chacha/chacha_vec_arm.S
+++ b/crypto/chacha/chacha_vec_arm.S
@@ -21,6 +21,8 @@
 #
 #     /opt/gcc-linaro-arm-linux-gnueabihf-4.7-2012.10-20121022_linux/bin/arm-linux-gnueabihf-gcc -O3 -mcpu=cortex-a8 -mfpu=neon -S chacha_vec.c -I ../../include -fpic -o chacha_vec_arm.S
 
+#if !defined(OPENSSL_NO_ASM)
+
 	.syntax unified
 	.cpu cortex-a8
 	.eabi_attribute 27, 3
@@ -884,3 +886,5 @@
 	.word	1797285236
 	.ident	"GCC: (crosstool-NG linaro-1.13.1-4.7-2012.10-20121022 - Linaro GCC 2012.10) 4.7.3 20121001 (prerelease)"
 	.section	.note.GNU-stack,"",%progbits
+
+#endif  /* !OPENSSL_NO_ASM */
diff --git a/crypto/cipher/CMakeLists.txt b/crypto/cipher/CMakeLists.txt
index cf2a4e2..40e239c 100644
--- a/crypto/cipher/CMakeLists.txt
+++ b/crypto/cipher/CMakeLists.txt
@@ -11,6 +11,7 @@
 	aead.c
 
 	e_null.c
+	e_rc2.c
 	e_rc4.c
 	e_des.c
 	e_aes.c
diff --git a/crypto/cipher/aead_test.c b/crypto/cipher/aead_test.c
index f0f3cf4..ff2244c 100644
--- a/crypto/cipher/aead_test.c
+++ b/crypto/cipher/aead_test.c
@@ -18,6 +18,7 @@
 #include <string.h>
 
 #include <openssl/aead.h>
+#include <openssl/crypto.h>
 
 /* This program tests an AEAD against a series of test vectors from a file. The
  * test vector file consists of key-value lines where the key and value are
@@ -155,6 +156,8 @@
   unsigned char bufs[NUM_TYPES][BUF_MAX];
   unsigned int lengths[NUM_TYPES];
 
+  CRYPTO_library_init();
+
   if (argc != 3) {
     fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]);
     return 1;
diff --git a/crypto/cipher/cipher.c b/crypto/cipher/cipher.c
index c6572b8..cdb8f43 100644
--- a/crypto/cipher/cipher.c
+++ b/crypto/cipher/cipher.c
@@ -573,6 +573,21 @@
   return 1;
 }
 
+int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, unsigned key_len) {
+  if (c->key_len == key_len) {
+    return 1;
+  }
+
+  if (key_len == 0 || !(c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH)) {
+    OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_set_key_length,
+                      CIPHER_R_INVALID_KEY_LENGTH);
+    return 0;
+  }
+
+  c->key_len = key_len;
+  return 1;
+}
+
 int EVP_CIPHER_nid(const EVP_CIPHER *cipher) { return cipher->nid; }
 
 const char *EVP_CIPHER_name(const EVP_CIPHER *cipher) {
diff --git a/crypto/cipher/cipher_error.c b/crypto/cipher/cipher_error.c
index ed72436..5e1afe6 100644
--- a/crypto/cipher/cipher_error.c
+++ b/crypto/cipher/cipher_error.c
@@ -22,6 +22,7 @@
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_AEAD_CTX_seal, 0), "EVP_AEAD_CTX_seal"},
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CIPHER_CTX_copy, 0), "EVP_CIPHER_CTX_copy"},
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CIPHER_CTX_ctrl, 0), "EVP_CIPHER_CTX_ctrl"},
+  {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CIPHER_CTX_set_key_length, 0), "EVP_CIPHER_CTX_set_key_length"},
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CipherInit_ex, 0), "EVP_CipherInit_ex"},
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_DecryptFinal_ex, 0), "EVP_DecryptFinal_ex"},
   {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_EncryptFinal_ex, 0), "EVP_EncryptFinal_ex"},
@@ -50,6 +51,7 @@
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INPUT_NOT_INITIALIZED), "INPUT_NOT_INITIALIZED"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INVALID_AD), "INVALID_AD"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INVALID_AD_SIZE), "INVALID_AD_SIZE"},
+  {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INVALID_KEY_LENGTH), "INVALID_KEY_LENGTH"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_IV_TOO_LARGE), "IV_TOO_LARGE"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_NO_CIPHER_SET), "NO_CIPHER_SET"},
   {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_OUTPUT_ALIASES_INPUT), "OUTPUT_ALIASES_INPUT"},
diff --git a/crypto/cipher/cipher_test.c b/crypto/cipher/cipher_test.c
index 3dadb8a..b91b505 100644
--- a/crypto/cipher/cipher_test.c
+++ b/crypto/cipher/cipher_test.c
@@ -56,9 +56,10 @@
 
 #include <stdio.h>
 
-#include <openssl/cipher.h>
-#include <openssl/err.h>
 #include <openssl/bio.h>
+#include <openssl/cipher.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
 
 
 static void hexdump(FILE *f, const char *title, const uint8_t *s, int l) {
@@ -331,6 +332,8 @@
   const char *input_file;
   FILE *f;
 
+  CRYPTO_library_init();
+
   if (argc != 2) {
     fprintf(stderr, "%s <test file>\n", argv[0]);
     return 1;
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
index 15a886c..d22274e 100644
--- a/crypto/cipher/e_aes.c
+++ b/crypto/cipher/e_aes.c
@@ -92,13 +92,13 @@
 #define VPAES
 extern unsigned int OPENSSL_ia32cap_P[];
 
-static char vpaes_capable() {
+static char vpaes_capable(void) {
   return (OPENSSL_ia32cap_P[1] & (1 << (41 - 32))) != 0;
 }
 
 #if defined(OPENSSL_X86_64)
 #define BSAES
-static char bsaes_capable() {
+static char bsaes_capable(void) {
   return vpaes_capable();
 }
 #endif
@@ -107,7 +107,7 @@
 #include "../arm_arch.h"
 #if __ARM_ARCH__ >= 7
 #define BSAES
-static char bsaes_capable() {
+static char bsaes_capable(void) {
   return CRYPTO_is_NEON_capable();
 }
 #endif  /* __ARM_ARCH__ >= 7 */
@@ -121,7 +121,7 @@
 void bsaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len,
                                 const AES_KEY *key, const uint8_t ivec[16]);
 #else
-static char bsaes_capable() {
+static char bsaes_capable(void) {
   return 0;
 }
 
@@ -150,7 +150,7 @@
 void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
                        const AES_KEY *key, uint8_t *ivec, int enc);
 #else
-static char vpaes_capable() {
+static char vpaes_capable(void) {
   return 0;
 }
 
@@ -658,7 +658,7 @@
 
 /* AES-NI section. */
 
-static char aesni_capable() {
+static char aesni_capable(void) {
   return (OPENSSL_ia32cap_P[1] & (1 << (57 - 32))) != 0;
 }
 
@@ -812,7 +812,7 @@
 
 #else  /* ^^^  OPENSSL_X86_64 || OPENSSL_X86 */
 
-static char aesni_capable() {
+static char aesni_capable(void) {
   return 0;
 }
 
@@ -1004,9 +1004,9 @@
     aead_aes_gcm_seal,        aead_aes_gcm_open,
 };
 
-const EVP_AEAD *EVP_aead_aes_128_gcm() { return &aead_aes_128_gcm; }
+const EVP_AEAD *EVP_aead_aes_128_gcm(void) { return &aead_aes_128_gcm; }
 
-const EVP_AEAD *EVP_aead_aes_256_gcm() { return &aead_aes_256_gcm; }
+const EVP_AEAD *EVP_aead_aes_256_gcm(void) { return &aead_aes_256_gcm; }
 
 
 /* AES Key Wrap is specified in
@@ -1268,9 +1268,9 @@
     aead_aes_key_wrap_seal, aead_aes_key_wrap_open,
 };
 
-const EVP_AEAD *EVP_aead_aes_128_key_wrap() { return &aead_aes_128_key_wrap; }
+const EVP_AEAD *EVP_aead_aes_128_key_wrap(void) { return &aead_aes_128_key_wrap; }
 
-const EVP_AEAD *EVP_aead_aes_256_key_wrap() { return &aead_aes_256_key_wrap; }
+const EVP_AEAD *EVP_aead_aes_256_key_wrap(void) { return &aead_aes_256_key_wrap; }
 
 int EVP_has_aes_hardware(void) {
 #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
diff --git a/crypto/cipher/e_chacha20poly1305.c b/crypto/cipher/e_chacha20poly1305.c
index 8b6d378..e656cd7 100644
--- a/crypto/cipher/e_chacha20poly1305.c
+++ b/crypto/cipher/e_chacha20poly1305.c
@@ -217,4 +217,6 @@
     aead_chacha20_poly1305_seal, aead_chacha20_poly1305_open,
 };
 
-const EVP_AEAD *EVP_aead_chacha20_poly1305() { return &aead_chacha20_poly1305; }
+const EVP_AEAD *EVP_aead_chacha20_poly1305(void) {
+  return &aead_chacha20_poly1305;
+}
diff --git a/crypto/cipher/e_rc2.c b/crypto/cipher/e_rc2.c
new file mode 100644
index 0000000..c26c94e
--- /dev/null
+++ b/crypto/cipher/e_rc2.c
@@ -0,0 +1,421 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+#define c2l(c, l)                                                           \
+  (l = ((uint32_t)(*((c)++))), l |= ((uint32_t)(*((c)++))) << 8L, \
+   l |= ((uint32_t)(*((c)++))) << 16L,                                 \
+   l |= ((uint32_t)(*((c)++))) << 24L)
+
+#define c2ln(c, l1, l2, n)                        \
+  {                                               \
+    c += n;                                       \
+    l1 = l2 = 0;                                  \
+    switch (n) {                                  \
+      case 8:                                     \
+        l2 = ((uint32_t)(*(--(c)))) << 24L;  \
+      case 7:                                     \
+        l2 |= ((uint32_t)(*(--(c)))) << 16L; \
+      case 6:                                     \
+        l2 |= ((uint32_t)(*(--(c)))) << 8L;  \
+      case 5:                                     \
+        l2 |= ((uint32_t)(*(--(c))));        \
+      case 4:                                     \
+        l1 = ((uint32_t)(*(--(c)))) << 24L;  \
+      case 3:                                     \
+        l1 |= ((uint32_t)(*(--(c)))) << 16L; \
+      case 2:                                     \
+        l1 |= ((uint32_t)(*(--(c)))) << 8L;  \
+      case 1:                                     \
+        l1 |= ((uint32_t)(*(--(c))));        \
+    }                                             \
+  }
+
+#define l2c(l, c)                                   \
+  (*((c)++) = (uint8_t)(((l)) & 0xff),        \
+   *((c)++) = (uint8_t)(((l) >> 8L) & 0xff),  \
+   *((c)++) = (uint8_t)(((l) >> 16L) & 0xff), \
+   *((c)++) = (uint8_t)(((l) >> 24L) & 0xff))
+
+#define l2cn(l1, l2, c, n)                                \
+  {                                                       \
+    c += n;                                               \
+    switch (n) {                                          \
+      case 8:                                             \
+        *(--(c)) = (uint8_t)(((l2) >> 24L) & 0xff); \
+      case 7:                                             \
+        *(--(c)) = (uint8_t)(((l2) >> 16L) & 0xff); \
+      case 6:                                             \
+        *(--(c)) = (uint8_t)(((l2) >> 8L) & 0xff);  \
+      case 5:                                             \
+        *(--(c)) = (uint8_t)(((l2)) & 0xff);        \
+      case 4:                                             \
+        *(--(c)) = (uint8_t)(((l1) >> 24L) & 0xff); \
+      case 3:                                             \
+        *(--(c)) = (uint8_t)(((l1) >> 16L) & 0xff); \
+      case 2:                                             \
+        *(--(c)) = (uint8_t)(((l1) >> 8L) & 0xff);  \
+      case 1:                                             \
+        *(--(c)) = (uint8_t)(((l1)) & 0xff);        \
+    }                                                     \
+  }
+
+typedef struct rc2_key_st { uint16_t data[64]; } RC2_KEY;
+
+static void RC2_encrypt(uint32_t *d, RC2_KEY *key) {
+  int i, n;
+  uint16_t *p0, *p1;
+  uint16_t x0, x1, x2, x3, t;
+  uint32_t l;
+
+  l = d[0];
+  x0 = (uint16_t)l & 0xffff;
+  x1 = (uint16_t)(l >> 16L);
+  l = d[1];
+  x2 = (uint16_t)l & 0xffff;
+  x3 = (uint16_t)(l >> 16L);
+
+  n = 3;
+  i = 5;
+
+  p0 = p1 = &key->data[0];
+  for (;;) {
+    t = (x0 + (x1 & ~x3) + (x2 & x3) + *(p0++)) & 0xffff;
+    x0 = (t << 1) | (t >> 15);
+    t = (x1 + (x2 & ~x0) + (x3 & x0) + *(p0++)) & 0xffff;
+    x1 = (t << 2) | (t >> 14);
+    t = (x2 + (x3 & ~x1) + (x0 & x1) + *(p0++)) & 0xffff;
+    x2 = (t << 3) | (t >> 13);
+    t = (x3 + (x0 & ~x2) + (x1 & x2) + *(p0++)) & 0xffff;
+    x3 = (t << 5) | (t >> 11);
+
+    if (--i == 0) {
+      if (--n == 0) {
+        break;
+      }
+      i = (n == 2) ? 6 : 5;
+
+      x0 += p1[x3 & 0x3f];
+      x1 += p1[x0 & 0x3f];
+      x2 += p1[x1 & 0x3f];
+      x3 += p1[x2 & 0x3f];
+    }
+  }
+
+  d[0] = (uint32_t)(x0 & 0xffff) | ((uint32_t)(x1 & 0xffff) << 16L);
+  d[1] = (uint32_t)(x2 & 0xffff) | ((uint32_t)(x3 & 0xffff) << 16L);
+}
+
+static void RC2_decrypt(uint32_t *d, RC2_KEY *key) {
+  int i, n;
+  uint16_t *p0, *p1;
+  uint16_t x0, x1, x2, x3, t;
+  uint32_t l;
+
+  l = d[0];
+  x0 = (uint16_t)l & 0xffff;
+  x1 = (uint16_t)(l >> 16L);
+  l = d[1];
+  x2 = (uint16_t)l & 0xffff;
+  x3 = (uint16_t)(l >> 16L);
+
+  n = 3;
+  i = 5;
+
+  p0 = &key->data[63];
+  p1 = &key->data[0];
+  for (;;) {
+    t = ((x3 << 11) | (x3 >> 5)) & 0xffff;
+    x3 = (t - (x0 & ~x2) - (x1 & x2) - *(p0--)) & 0xffff;
+    t = ((x2 << 13) | (x2 >> 3)) & 0xffff;
+    x2 = (t - (x3 & ~x1) - (x0 & x1) - *(p0--)) & 0xffff;
+    t = ((x1 << 14) | (x1 >> 2)) & 0xffff;
+    x1 = (t - (x2 & ~x0) - (x3 & x0) - *(p0--)) & 0xffff;
+    t = ((x0 << 15) | (x0 >> 1)) & 0xffff;
+    x0 = (t - (x1 & ~x3) - (x2 & x3) - *(p0--)) & 0xffff;
+
+    if (--i == 0) {
+      if (--n == 0) {
+        break;
+      }
+      i = (n == 2) ? 6 : 5;
+
+      x3 = (x3 - p1[x2 & 0x3f]) & 0xffff;
+      x2 = (x2 - p1[x1 & 0x3f]) & 0xffff;
+      x1 = (x1 - p1[x0 & 0x3f]) & 0xffff;
+      x0 = (x0 - p1[x3 & 0x3f]) & 0xffff;
+    }
+  }
+
+  d[0] = (uint32_t)(x0 & 0xffff) | ((uint32_t)(x1 & 0xffff) << 16L);
+  d[1] = (uint32_t)(x2 & 0xffff) | ((uint32_t)(x3 & 0xffff) << 16L);
+}
+
+static void RC2_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+                            RC2_KEY *ks, uint8_t *iv, int encrypt) {
+  uint32_t tin0, tin1;
+  uint32_t tout0, tout1, xor0, xor1;
+  long l = length;
+  uint32_t tin[2];
+
+  if (encrypt) {
+    c2l(iv, tout0);
+    c2l(iv, tout1);
+    iv -= 8;
+    for (l -= 8; l >= 0; l -= 8) {
+      c2l(in, tin0);
+      c2l(in, tin1);
+      tin0 ^= tout0;
+      tin1 ^= tout1;
+      tin[0] = tin0;
+      tin[1] = tin1;
+      RC2_encrypt(tin, ks);
+      tout0 = tin[0];
+      l2c(tout0, out);
+      tout1 = tin[1];
+      l2c(tout1, out);
+    }
+    if (l != -8) {
+      c2ln(in, tin0, tin1, l + 8);
+      tin0 ^= tout0;
+      tin1 ^= tout1;
+      tin[0] = tin0;
+      tin[1] = tin1;
+      RC2_encrypt(tin, ks);
+      tout0 = tin[0];
+      l2c(tout0, out);
+      tout1 = tin[1];
+      l2c(tout1, out);
+    }
+    l2c(tout0, iv);
+    l2c(tout1, iv);
+  } else {
+    c2l(iv, xor0);
+    c2l(iv, xor1);
+    iv -= 8;
+    for (l -= 8; l >= 0; l -= 8) {
+      c2l(in, tin0);
+      tin[0] = tin0;
+      c2l(in, tin1);
+      tin[1] = tin1;
+      RC2_decrypt(tin, ks);
+      tout0 = tin[0] ^ xor0;
+      tout1 = tin[1] ^ xor1;
+      l2c(tout0, out);
+      l2c(tout1, out);
+      xor0 = tin0;
+      xor1 = tin1;
+    }
+    if (l != -8) {
+      c2l(in, tin0);
+      tin[0] = tin0;
+      c2l(in, tin1);
+      tin[1] = tin1;
+      RC2_decrypt(tin, ks);
+      tout0 = tin[0] ^ xor0;
+      tout1 = tin[1] ^ xor1;
+      l2cn(tout0, tout1, out, l + 8);
+      xor0 = tin0;
+      xor1 = tin1;
+    }
+    l2c(xor0, iv);
+    l2c(xor1, iv);
+  }
+  tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
+  tin[0] = tin[1] = 0;
+}
+
+static const uint8_t key_table[256] = {
+    0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79,
+    0x4a, 0xa0, 0xd8, 0x9d, 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e,
+    0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, 0x17, 0x9a, 0x59, 0xf5,
+    0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
+    0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22,
+    0x5c, 0x6b, 0x4e, 0x82, 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c,
+    0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, 0x12, 0x75, 0xca, 0x1f,
+    0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
+    0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b,
+    0xbc, 0x94, 0x43, 0x03, 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7,
+    0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, 0x08, 0xe8, 0xea, 0xde,
+    0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
+    0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e,
+    0x04, 0x18, 0xa4, 0xec, 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc,
+    0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, 0x99, 0x7c, 0x3a, 0x85,
+    0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
+    0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10,
+    0x67, 0x6c, 0xba, 0xc9, 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c,
+    0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, 0x0d, 0x38, 0x34, 0x1b,
+    0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
+    0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68,
+    0xfe, 0x7f, 0xc1, 0xad,
+};
+
+static void RC2_set_key(RC2_KEY *key, int len, const uint8_t *data, int bits) {
+  int i, j;
+  uint8_t *k;
+  uint16_t *ki;
+  unsigned int c, d;
+
+  k = (uint8_t *)&key->data[0];
+  *k = 0; /* for if there is a zero length key */
+
+  if (len > 128) {
+    len = 128;
+  }
+  if (bits <= 0) {
+    bits = 1024;
+  }
+  if (bits > 1024) {
+    bits = 1024;
+  }
+
+  for (i = 0; i < len; i++) {
+    k[i] = data[i];
+  }
+
+  /* expand table */
+  d = k[len - 1];
+  j = 0;
+  for (i = len; i < 128; i++, j++) {
+    d = key_table[(k[j] + d) & 0xff];
+    k[i] = d;
+  }
+
+  /* hmm.... key reduction to 'bits' bits */
+
+  j = (bits + 7) >> 3;
+  i = 128 - j;
+  c = (0xff >> (-bits & 0x07));
+
+  d = key_table[k[i] & c];
+  k[i] = d;
+  while (i--) {
+    d = key_table[k[i + j] ^ d];
+    k[i] = d;
+  }
+
+  /* copy from bytes into uint16_t's */
+  ki = &(key->data[63]);
+  for (i = 127; i >= 0; i -= 2) {
+    *(ki--) = ((k[i] << 8) | k[i - 1]) & 0xffff;
+  }
+}
+
+typedef struct {
+  int key_bits; /* effective key bits */
+  RC2_KEY ks;   /* key schedule */
+} EVP_RC2_KEY;
+
+static int rc2_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+                        const uint8_t *iv, int enc) {
+  EVP_RC2_KEY *rc2_key = (EVP_RC2_KEY *)ctx->cipher_data;
+  RC2_set_key(&rc2_key->ks, EVP_CIPHER_CTX_key_length(ctx), key,
+              rc2_key->key_bits);
+  return 1;
+}
+
+static int rc2_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+                          size_t inl) {
+  EVP_RC2_KEY *key = (EVP_RC2_KEY *)ctx->cipher_data;
+  static const size_t kChunkSize = 0x10000;
+
+  while (inl >= kChunkSize) {
+    RC2_cbc_encrypt(in, out, kChunkSize, &key->ks, ctx->iv, ctx->encrypt);
+    inl -= kChunkSize;
+    in += kChunkSize;
+    out += kChunkSize;
+  }
+  if (inl) {
+    RC2_cbc_encrypt(in, out, inl, &key->ks, ctx->iv, ctx->encrypt);
+  }
+  return 1;
+}
+
+static int rc2_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) {
+  EVP_RC2_KEY *key = (EVP_RC2_KEY *)ctx->cipher_data;
+
+  switch (type) {
+    case EVP_CTRL_INIT:
+      key->key_bits = EVP_CIPHER_CTX_key_length(ctx) * 8;
+      return 1;
+
+    default:
+      return -1;
+  }
+}
+
+static const EVP_CIPHER rc2_40_cbc_cipher = {
+    NID_rc2_40_cbc,
+    8 /* block size */,
+    5 /* 40 bit */,
+    8 /* iv len */,
+    sizeof(EVP_RC2_KEY),
+    EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT,
+    NULL /* app_data */,
+    rc2_init_key,
+    rc2_cbc_cipher,
+    NULL,
+    rc2_ctrl,
+};
+
+const EVP_CIPHER *EVP_rc2_40_cbc() {
+  return &rc2_40_cbc_cipher;
+}
diff --git a/crypto/cipher/e_rc4.c b/crypto/cipher/e_rc4.c
index df1bc11..f1d4c50 100644
--- a/crypto/cipher/e_rc4.c
+++ b/crypto/cipher/e_rc4.c
@@ -366,4 +366,4 @@
     aead_rc4_md5_tls_seal,  aead_rc4_md5_tls_open,
 };
 
-const EVP_AEAD *EVP_aead_rc4_md5_tls() { return &aead_rc4_md5_tls; }
+const EVP_AEAD *EVP_aead_rc4_md5_tls(void) { return &aead_rc4_md5_tls; }
diff --git a/crypto/conf/conf.c b/crypto/conf/conf.c
index 1630c93..520416a 100644
--- a/crypto/conf/conf.c
+++ b/crypto/conf/conf.c
@@ -90,7 +90,7 @@
   }
 }
 
-CONF *NCONF_new() {
+CONF *NCONF_new(void) {
   CONF *conf;
 
   conf = OPENSSL_malloc(sizeof(CONF));
diff --git a/crypto/cpu-arm.c b/crypto/cpu-arm.c
index 814df26..dac7e1e 100644
--- a/crypto/cpu-arm.c
+++ b/crypto/cpu-arm.c
@@ -69,7 +69,7 @@
 uint32_t OPENSSL_armcap_P = ARMV7_NEON_FUNCTIONAL;
 #endif
 
-char CRYPTO_is_NEON_capable() {
+char CRYPTO_is_NEON_capable(void) {
   return (OPENSSL_armcap_P & ARMV7_NEON) != 0;
 }
 
@@ -81,7 +81,7 @@
   }
 }
 
-char CRYPTO_is_NEON_functional() {
+char CRYPTO_is_NEON_functional(void) {
   static const uint32_t kWantFlags = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL;
   return (OPENSSL_armcap_P & kWantFlags) == kWantFlags;
 }
diff --git a/crypto/cpu-intel.c b/crypto/cpu-intel.c
index bc3148f..3dd08a9 100644
--- a/crypto/cpu-intel.c
+++ b/crypto/cpu-intel.c
@@ -61,7 +61,7 @@
 #include <openssl/cpu.h>
 
 
-#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
+#if !defined(OPENSSL_NO_ASM) && (defined(OPENSSL_X86) || defined(OPENSSL_X86_64))
 
 #include <stdio.h>
 #include <inttypes.h>
@@ -78,10 +78,6 @@
 /* OPENSSL_ia32_cpuid is defined in cpu-x86_64-asm.pl. */
 extern uint64_t OPENSSL_ia32_cpuid(uint32_t*);
 
-#if !defined(OPENSSL_WINDOWS)
-void OPENSSL_cpuid_setup(void) __attribute__ ((constructor));
-#endif
-
 /* handle_cpu_env applies the value from |in| to the CPUID values in |out[0]|
  * and |out[1]|. See the comment in |OPENSSL_cpuid_setup| about this. */
 static void handle_cpu_env(uint32_t *out, const char *in) {
@@ -101,14 +97,7 @@
   }
 }
 
-#if defined(OPENSSL_WINDOWS)
-#pragma section(".CRT$XCU", read)
-void __cdecl OPENSSL_cpuid_setup(void);
-__declspec(allocate(".CRT$XCU")) void(*cpuid_constructor)(void) = OPENSSL_cpuid_setup;
-void __cdecl OPENSSL_cpuid_setup(void) {
-#else
 void OPENSSL_cpuid_setup(void) {
-#endif
   const char *env1, *env2;
 
 #if defined(OPENSSL_X86_64)
@@ -143,4 +132,4 @@
   }
 }
 
-#endif  /* OPENSSL_X86 || OPENSSL_X86_64 */
+#endif  /* !OPENSSL_NO_ASM && (OPENSSL_X86 || OPENSSL_X86_64) */
diff --git a/crypto/crypto.c b/crypto/crypto.c
new file mode 100644
index 0000000..ee7c405
--- /dev/null
+++ b/crypto/crypto.c
@@ -0,0 +1,68 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/crypto.h>
+
+#include "internal.h"
+
+#if !defined(OPENSSL_NO_ASM) && \
+    (defined(OPENSSL_X86) || defined(OPENSSL_X86_64))
+/* x86 and x86_64 need to record the result of a cpuid call for the asm to work
+ * correctly, unless compiled without asm code. */
+#define NEED_CPUID
+
+#else
+
+/* Otherwise, don't emit a static initialiser. */
+
+#if !defined(BORINGSSL_NO_STATIC_INITIALIZER)
+#define BORINGSSL_NO_STATIC_INITIALIZER
+#endif
+
+#endif  /* !OPENSSL_NO_ASM && (OPENSSL_X86 || OPENSSL_X86_64) */
+
+#if defined(OPENSSL_WINDOWS)
+#define OPENSSL_CDECL __cdecl
+#else
+#define OPENSSL_CDECL
+#endif
+
+#if !defined(BORINGSSL_NO_STATIC_INITIALIZER)
+#if !defined(OPENSSL_WINDOWS)
+static void do_library_init(void) __attribute__ ((constructor));
+#else
+#pragma section(".CRT$XCU", read)
+static void __cdecl do_library_init(void);
+__declspec(allocate(".CRT$XCU")) void(*library_init_constructor)(void) =
+    do_library_init;
+#endif
+#endif  /* !BORINGSSL_NO_STATIC_INITIALIZER */
+
+/* do_library_init is the actual initialization function. If
+ * BORINGSSL_NO_STATIC_INITIALIZER isn't defined, this is set as a static
+ * initializer. Otherwise, it is called by CRYPTO_library_init. */
+static void OPENSSL_CDECL do_library_init(void) {
+#if defined(NEED_CPUID)
+  OPENSSL_cpuid_setup();
+#endif
+}
+
+void CRYPTO_library_init(void) {
+  /* TODO(davidben): It would be tidier if this build knob could be replaced
+   * with an internal lazy-init mechanism that would handle things correctly
+   * in-library. */
+#if defined(BORINGSSL_NO_STATIC_INITIALIZER)
+  do_library_init();
+#endif
+}
diff --git a/crypto/dh/dh_test.c b/crypto/dh/dh_test.c
index 73dbba9..31b3dd9 100644
--- a/crypto/dh/dh_test.c
+++ b/crypto/dh/dh_test.c
@@ -60,6 +60,7 @@
 
 #include <openssl/bio.h>
 #include <openssl/bn.h>
+#include <openssl/crypto.h>
 #include <openssl/mem.h>
 
 #include "internal.h"
@@ -93,6 +94,8 @@
   int i, alen, blen, aout, bout, ret = 1;
   BIO *out;
 
+  CRYPTO_library_init();
+
   out = BIO_new(BIO_s_file());
   if (out == NULL) {
     return 1;
diff --git a/crypto/digest/digest.c b/crypto/digest/digest.c
index 2bfb0fa..3897c60 100644
--- a/crypto/digest/digest.c
+++ b/crypto/digest/digest.c
@@ -267,3 +267,7 @@
 uint32_t EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx, uint32_t flags) {
   return ctx->flags & flags;
 }
+
+int EVP_add_digest(const EVP_MD *digest) {
+  return 1;
+}
diff --git a/crypto/digest/digests.c b/crypto/digest/digests.c
index b757ea8..e3d3a87 100644
--- a/crypto/digest/digests.c
+++ b/crypto/digest/digests.c
@@ -56,6 +56,7 @@
 
 #include <openssl/digest.h>
 
+#include <openssl/md4.h>
 #include <openssl/md5.h>
 #include <openssl/obj.h>
 #include <openssl/sha.h>
@@ -63,6 +64,24 @@
 #include "internal.h"
 
 
+static int md4_init(EVP_MD_CTX *ctx) { return MD4_Init(ctx->md_data); }
+
+static int md4_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+  return MD4_Update(ctx->md_data, data, count);
+}
+
+static int md4_final(EVP_MD_CTX *ctx, unsigned char *out) {
+  return MD4_Final(out, ctx->md_data);
+}
+
+static const EVP_MD md4_md = {
+    NID_md4,    MD4_DIGEST_LENGTH, 0 /* flags */,       md4_init,
+    md4_update, md4_final,         64 /* block size */, sizeof(MD4_CTX),
+};
+
+const EVP_MD *EVP_md4(void) { return &md4_md; }
+
+
 static int md5_init(EVP_MD_CTX *ctx) { return MD5_Init(ctx->md_data); }
 
 static int md5_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c
index 8c66ddf..25d15c0 100644
--- a/crypto/dsa/dsa.c
+++ b/crypto/dsa/dsa.c
@@ -60,6 +60,7 @@
 #include <openssl/dsa.h>
 
 #include <openssl/asn1.h>
+#include <openssl/dh.h>
 #include <openssl/engine.h>
 #include <openssl/err.h>
 #include <openssl/ex_data.h>
@@ -332,3 +333,35 @@
 void *DSA_get_ex_data(const DSA *d, int idx) {
   return CRYPTO_get_ex_data(&d->ex_data, idx);
 }
+
+DH *DSA_dup_DH(const DSA *r) {
+  DH *ret = NULL;
+
+  if (r == NULL) {
+    goto err;
+  }
+  ret = DH_new();
+  if (ret == NULL) {
+    goto err;
+  }
+  if (r->q != NULL) {
+    ret->priv_length = BN_num_bits(r->q);
+    if ((ret->q = BN_dup(r->q)) == NULL) {
+      goto err;
+    }
+  }
+  if ((r->p != NULL && (ret->p = BN_dup(r->p)) == NULL) ||
+      (r->g != NULL && (ret->g = BN_dup(r->g)) == NULL) ||
+      (r->pub_key != NULL && (ret->pub_key = BN_dup(r->pub_key)) == NULL) ||
+      (r->priv_key != NULL && (ret->priv_key = BN_dup(r->priv_key)) == NULL)) {
+      goto err;
+  }
+
+  return ret;
+
+err:
+  if (ret != NULL) {
+    DH_free(ret);
+  }
+  return NULL;
+}
diff --git a/crypto/dsa/dsa_test.c b/crypto/dsa/dsa_test.c
index 8841c12..1edb7e7 100644
--- a/crypto/dsa/dsa_test.c
+++ b/crypto/dsa/dsa_test.c
@@ -61,6 +61,7 @@
 
 #include <openssl/bio.h>
 #include <openssl/bn.h>
+#include <openssl/crypto.h>
 
 #include "internal.h"
 
@@ -107,6 +108,8 @@
   unsigned char sig[256];
   unsigned int siglen;
 
+  CRYPTO_library_init();
+
   bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
   bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
 
diff --git a/crypto/ec/ec.c b/crypto/ec/ec.c
index dcb9083..34e6d90 100644
--- a/crypto/ec/ec.c
+++ b/crypto/ec/ec.c
@@ -519,6 +519,16 @@
   return !BN_is_zero(&group->cofactor);
 }
 
+int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p, BIGNUM *out_a,
+                           BIGNUM *out_b, BN_CTX *ctx) {
+  if (group->meth->group_get_curve == 0) {
+    OPENSSL_PUT_ERROR(EC, EC_GROUP_get_curve_GFp,
+                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    return 0;
+  }
+  return group->meth->group_get_curve(group, out_p, out_a, out_b, ctx);
+}
+
 int EC_GROUP_get_curve_name(const EC_GROUP *group) { return group->curve_name; }
 
 int EC_GROUP_get_degree(const EC_GROUP *group) {
diff --git a/crypto/ec/ec_error.c b/crypto/ec/ec_error.c
index 3b5d158..73807c7 100644
--- a/crypto/ec/ec_error.c
+++ b/crypto/ec/ec_error.c
@@ -18,6 +18,7 @@
 
 const ERR_STRING_DATA EC_error_string_data[] = {
   {ERR_PACK(ERR_LIB_EC, EC_F_EC_GROUP_copy, 0), "EC_GROUP_copy"},
+  {ERR_PACK(ERR_LIB_EC, EC_F_EC_GROUP_get_curve_GFp, 0), "EC_GROUP_get_curve_GFp"},
   {ERR_PACK(ERR_LIB_EC, EC_F_EC_GROUP_get_degree, 0), "EC_GROUP_get_degree"},
   {ERR_PACK(ERR_LIB_EC, EC_F_EC_GROUP_new_by_curve_name, 0), "EC_GROUP_new_by_curve_name"},
   {ERR_PACK(ERR_LIB_EC, EC_F_EC_KEY_check_key, 0), "EC_KEY_check_key"},
diff --git a/crypto/ec/example_mul.c b/crypto/ec/example_mul.c
index 1e83d61..ebb724f 100644
--- a/crypto/ec/example_mul.c
+++ b/crypto/ec/example_mul.c
@@ -68,11 +68,12 @@
 #include <stdio.h>
 
 #include <openssl/bn.h>
+#include <openssl/crypto.h>
 #include <openssl/ec.h>
 #include <openssl/obj.h>
 
 
-int example_EC_POINT_mul() {
+int example_EC_POINT_mul(void) {
   /* This example ensures that 10×∞ + G = G, in P-256. */
   EC_GROUP *group = NULL;
   EC_POINT *p = NULL, *result = NULL;
@@ -119,7 +120,9 @@
   return ret;
 }
 
-int main() {
+int main(void) {
+  CRYPTO_library_init();
+
   if (!example_EC_POINT_mul()) {
     fprintf(stderr, "failed\n");
     return 1;
diff --git a/crypto/ec/internal.h b/crypto/ec/internal.h
index 76c3a80..5c3be55 100644
--- a/crypto/ec/internal.h
+++ b/crypto/ec/internal.h
@@ -186,7 +186,7 @@
   int (*field_set_to_one)(const EC_GROUP *, BIGNUM *r, BN_CTX *);
 } /* EC_METHOD */;
 
-const EC_METHOD* EC_GFp_mont_method();
+const EC_METHOD* EC_GFp_mont_method(void);
 
 struct ec_pre_comp_st;
 void ec_pre_comp_free(struct ec_pre_comp_st *pre_comp);
diff --git a/crypto/ec/wnaf.c b/crypto/ec/wnaf.c
index b86107d..2fed4a5 100644
--- a/crypto/ec/wnaf.c
+++ b/crypto/ec/wnaf.c
@@ -448,8 +448,6 @@
         wNAF[num] = tmp_wNAF;
         wNAF[num + 1] = NULL;
         wNAF_len[num] = tmp_len;
-        if (tmp_len > max_len)
-          max_len = tmp_len;
         /* pre_comp->points starts with the points that we need here: */
         val_sub[num] = pre_comp->points;
       } else {
diff --git a/crypto/ecdsa/ecdsa.c b/crypto/ecdsa/ecdsa.c
index 067fd6c..ddc3e61 100644
--- a/crypto/ecdsa/ecdsa.c
+++ b/crypto/ecdsa/ecdsa.c
@@ -140,8 +140,9 @@
   }
 
   /* check input values */
-  if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL ||
-      (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || sig == NULL) {
+  if ((group = EC_KEY_get0_group(eckey)) == NULL ||
+      (pub_key = EC_KEY_get0_public_key(eckey)) == NULL ||
+      sig == NULL) {
     OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_MISSING_PARAMETERS);
     return 0;
   }
diff --git a/crypto/ecdsa/ecdsa_test.c b/crypto/ecdsa/ecdsa_test.c
index 64480e3..e3b1142 100644
--- a/crypto/ecdsa/ecdsa_test.c
+++ b/crypto/ecdsa/ecdsa_test.c
@@ -54,6 +54,7 @@
 
 #include <openssl/bio.h>
 #include <openssl/bn.h>
+#include <openssl/crypto.h>
 #include <openssl/ec.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
@@ -285,10 +286,11 @@
   int ret = 1;
   BIO *out;
 
-  out = BIO_new_fp(stdout, BIO_NOCLOSE);
-
+  CRYPTO_library_init();
   ERR_load_crypto_strings();
 
+  out = BIO_new_fp(stdout, BIO_NOCLOSE);
+
   if (!test_builtin(out))
     goto err;
 
diff --git a/crypto/engine/engine.c b/crypto/engine/engine.c
index bb0886e..c9b8823 100644
--- a/crypto/engine/engine.c
+++ b/crypto/engine/engine.c
@@ -29,7 +29,7 @@
   ECDSA_METHOD *ecdsa_method;
 };
 
-ENGINE *ENGINE_new() {
+ENGINE *ENGINE_new(void) {
   ENGINE *engine = OPENSSL_malloc(sizeof(ENGINE));
   if (engine == NULL) {
     return NULL;
diff --git a/crypto/err/err.c b/crypto/err/err.c
index fd3a76b..7ca2842 100644
--- a/crypto/err/err.c
+++ b/crypto/err/err.c
@@ -298,7 +298,7 @@
   OPENSSL_free(state);
 }
 
-int ERR_get_next_error_library() {
+int ERR_get_next_error_library(void) {
   err_fns_check();
   return ERRFN(get_next_library)();
 }
@@ -694,6 +694,7 @@
 extern const ERR_STRING_DATA EVP_error_string_data[];
 extern const ERR_STRING_DATA OBJ_error_string_data[];
 extern const ERR_STRING_DATA PEM_error_string_data[];
+extern const ERR_STRING_DATA PKCS8_error_string_data[];
 extern const ERR_STRING_DATA RSA_error_string_data[];
 extern const ERR_STRING_DATA X509V3_error_string_data[];
 extern const ERR_STRING_DATA X509_error_string_data[];
@@ -746,6 +747,7 @@
   ERR_load_strings(EVP_error_string_data);
   ERR_load_strings(OBJ_error_string_data);
   ERR_load_strings(PEM_error_string_data);
+  ERR_load_strings(PKCS8_error_string_data);
   ERR_load_strings(RSA_error_string_data);
   ERR_load_strings(X509V3_error_string_data);
   ERR_load_strings(X509_error_string_data);
@@ -760,11 +762,11 @@
   }
 }
 
-void ERR_load_crypto_strings() { err_load_strings(); }
+void ERR_load_crypto_strings(void) { err_load_strings(); }
 
-void ERR_free_strings() {
+void ERR_free_strings(void) {
   err_fns_check();
   ERRFN(shutdown)();
 }
 
-void ERR_load_BIO_strings() {}
+void ERR_load_BIO_strings(void) {}
diff --git a/crypto/err/err_test.c b/crypto/err/err_test.c
index 540ea07..230cada 100644
--- a/crypto/err/err_test.c
+++ b/crypto/err/err_test.c
@@ -14,11 +14,12 @@
 
 #include <stdio.h>
 
+#include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
 
 
-static int test_overflow() {
+static int test_overflow(void) {
   unsigned i;
 
   for (i = 0; i < ERR_NUM_ERRORS*2; i++) {
@@ -40,7 +41,7 @@
   return 1;
 }
 
-static int test_put_error() {
+static int test_put_error(void) {
   uint32_t packed_error;
   int line, flags;
   const char *file;
@@ -72,7 +73,7 @@
   return 1;
 }
 
-static int test_clear_error() {
+static int test_clear_error(void) {
   if (ERR_get_error() != 0) {
     fprintf(stderr, "ERR_get_error returned value before an error was added.\n");
     return 0;
@@ -89,7 +90,7 @@
   return 1;
 }
 
-static int test_print() {
+static int test_print(void) {
   size_t i;
   char buf[256];
   uint32_t packed_error;
@@ -105,13 +106,15 @@
   return 1;
 }
 
-static int test_release() {
+static int test_release(void) {
   ERR_put_error(1, 2, 3, "test", 4);
   ERR_remove_thread_state(NULL);
   return 1;
 }
 
-int main() {
+int main(void) {
+  CRYPTO_library_init();
+
   if (!test_overflow() ||
       !test_put_error() ||
       !test_clear_error() ||
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c
index 06fdabf..c7c4ffb 100644
--- a/crypto/evp/evp.c
+++ b/crypto/evp/evp.c
@@ -74,7 +74,7 @@
 extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meth;
 
-EVP_PKEY *EVP_PKEY_new() {
+EVP_PKEY *EVP_PKEY_new(void) {
   EVP_PKEY *ret;
 
   ret = OPENSSL_malloc(sizeof(EVP_PKEY));
@@ -427,6 +427,6 @@
                            0, (void *)out_md);
 }
 
-void OpenSSL_add_all_algorithms() {}
+void OpenSSL_add_all_algorithms(void) {}
 
-void EVP_cleanup() {}
+void EVP_cleanup(void) {}
diff --git a/crypto/evp/example_sign.c b/crypto/evp/example_sign.c
index df7156b..c25ef2a 100644
--- a/crypto/evp/example_sign.c
+++ b/crypto/evp/example_sign.c
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 
 #include <openssl/bio.h>
+#include <openssl/crypto.h>
 #include <openssl/digest.h>
 #include <openssl/evp.h>
 #include <openssl/rsa.h>
@@ -95,7 +96,7 @@
 };
 
 
-int example_EVP_DigestSignInit() {
+int example_EVP_DigestSignInit(void) {
   int ret = 0;
   EVP_PKEY *pkey = NULL;
   RSA *rsa = NULL;
@@ -127,9 +128,13 @@
     fprintf(stderr, "sig_len mismatch\n");
     goto out;
   }
+
   sig = malloc(sig_len);
-  if (sig == NULL ||
-      EVP_DigestSignFinal(&md_ctx, sig, &sig_len) != 1) {
+  if (sig == NULL) {
+    goto out;
+  }
+  if (EVP_DigestSignFinal(&md_ctx, sig, &sig_len) != 1) {
+    free(sig);
     goto out;
   }
 
@@ -154,7 +159,7 @@
   return ret;
 }
 
-int example_EVP_DigestVerifyInit() {
+int example_EVP_DigestVerifyInit(void) {
   int ret = 0;
   EVP_PKEY *pkey = NULL;
   RSA *rsa = NULL;
@@ -193,7 +198,9 @@
   return ret;
 }
 
-int main() {
+int main(void) {
+  CRYPTO_library_init();
+
   if (!example_EVP_DigestSignInit()) {
     fprintf(stderr, "EVP_DigestSignInit failed\n");
     return 1;
diff --git a/crypto/ex_data.c b/crypto/ex_data.c
index 00b8ff3..820f48d 100644
--- a/crypto/ex_data.c
+++ b/crypto/ex_data.c
@@ -123,7 +123,7 @@
 extern const CRYPTO_EX_DATA_IMPL ex_data_default_impl;
 
 /* get_impl returns the current ex_data implementatation. */
-static const CRYPTO_EX_DATA_IMPL *get_impl() {
+static const CRYPTO_EX_DATA_IMPL *get_impl(void) {
   const CRYPTO_EX_DATA_IMPL *impl;
 
   CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
diff --git a/crypto/ex_data_impl.c b/crypto/ex_data_impl.c
index 23d1fac..ddc6b8a 100644
--- a/crypto/ex_data_impl.c
+++ b/crypto/ex_data_impl.c
@@ -171,7 +171,7 @@
   sk_CRYPTO_EX_DATA_FUNCS_pop_free(item->meth, data_funcs_free);
 }
 
-static LHASH_OF(EX_CLASS_ITEM) *get_classes() {
+static LHASH_OF(EX_CLASS_ITEM) *get_classes(void) {
   LHASH_OF(EX_CLASS_ITEM) *ret;
 
   CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
diff --git a/crypto/hmac/hmac_test.c b/crypto/hmac/hmac_test.c
index e2ae4a6..7b85196 100644
--- a/crypto/hmac/hmac_test.c
+++ b/crypto/hmac/hmac_test.c
@@ -56,6 +56,7 @@
 
 #include <stdio.h>
 
+#include <openssl/crypto.h>
 #include <openssl/digest.h>
 #include <openssl/hmac.h>
 
@@ -124,6 +125,8 @@
   uint8_t out[EVP_MAX_MD_SIZE];
   unsigned out_len;
 
+  CRYPTO_library_init();
+
   for (i = 0; i < NUM_TESTS; i++) {
     const struct test_st *test = &kTests[i];
 
diff --git a/crypto/internal.h b/crypto/internal.h
index 8464239..ffac2d5 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -109,7 +109,11 @@
 #ifndef OPENSSL_HEADER_CRYPTO_INTERNAL_H
 #define OPENSSL_HEADER_CRYPTO_INTERNAL_H
 
-#include <openssl/base.h>
+#include <openssl/ex_data.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
 
 
 /* st_CRYPTO_EX_DATA_IMPL contains an ex_data implementation. See the comments
@@ -128,6 +132,23 @@
 };
 
 
+#if defined(OPENSSL_WINDOWS)
+#define OPENSSL_U64(x) x##UI64
+#else
+
+#if defined(OPENSSL_64_BIT)
+#define OPENSSL_U64(x) x##UL
+#else
+#define OPENSSL_U64(x) x##ULL
+#endif
+
+#endif  /* OPENSSL_WINDOWS */
+
+#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
+/* OPENSSL_cpuid_setup initializes OPENSSL_ia32cap_P. */
+void OPENSSL_cpuid_setup(void);
+#endif
+
 #if defined(__cplusplus)
 }  /* extern C */
 #endif
diff --git a/crypto/lhash/lhash_test.c b/crypto/lhash/lhash_test.c
index 2aa90c3..eb40cab 100644
--- a/crypto/lhash/lhash_test.c
+++ b/crypto/lhash/lhash_test.c
@@ -14,6 +14,7 @@
 
 #define _BSD_SOURCE
 
+#include <openssl/crypto.h>
 #include <openssl/lhash.h>
 
 #include <stdio.h>
@@ -99,7 +100,7 @@
   return NULL;
 }
 
-static char *rand_string() {
+static char *rand_string(void) {
   unsigned len = 1 + (rand() % 3);
   char *ret = malloc(len + 1);
   unsigned i;
@@ -113,10 +114,14 @@
 }
 
 int main(int argc, char **argv) {
-  _LHASH *lh = lh_new(NULL, NULL);
+  _LHASH *lh;
   struct dummy_lhash dummy_lh = {NULL};
   unsigned i;
 
+  CRYPTO_library_init();
+
+  lh = lh_new(NULL, NULL);
+
   for (i = 0; i < 100000; i++) {
     unsigned action;
     char *s, *s1, *s2;
diff --git a/crypto/md4/CMakeLists.txt b/crypto/md4/CMakeLists.txt
new file mode 100644
index 0000000..7fbce40
--- /dev/null
+++ b/crypto/md4/CMakeLists.txt
@@ -0,0 +1,9 @@
+include_directories(. .. ../../include)
+
+add_library(
+	md4
+
+	OBJECT
+
+	md4.c
+)
diff --git a/crypto/md4/md4.c b/crypto/md4/md4.c
new file mode 100644
index 0000000..8e86945
--- /dev/null
+++ b/crypto/md4/md4.c
@@ -0,0 +1,222 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/md4.h>
+
+
+/* Implemented from RFC1186 The MD4 Message-Digest Algorithm. */
+
+int MD4_Init(MD4_CTX *md4) {
+  memset(md4, 0, sizeof(MD4_CTX));
+  md4->A = 0x67452301UL;
+  md4->B = 0xefcdab89UL;
+  md4->C = 0x98badcfeUL;
+  md4->D = 0x10325476UL;
+  return 1;
+}
+
+void md4_block_data_order (MD4_CTX *md4, const void *p, size_t num);
+
+#define DATA_ORDER_IS_LITTLE_ENDIAN
+
+#define HASH_LONG uint32_t
+#define HASH_CTX MD4_CTX
+#define HASH_CBLOCK 64
+#define HASH_UPDATE MD4_Update
+#define HASH_TRANSFORM MD4_Transform
+#define HASH_FINAL MD4_Final
+#define HASH_MAKE_STRING(c, s) \
+  do {                         \
+    unsigned long ll;          \
+    ll = (c)->A;               \
+    (void) HOST_l2c(ll, (s));  \
+    ll = (c)->B;               \
+    (void) HOST_l2c(ll, (s));  \
+    ll = (c)->C;               \
+    (void) HOST_l2c(ll, (s));  \
+    ll = (c)->D;               \
+    (void) HOST_l2c(ll, (s));  \
+  } while (0)
+#define HASH_BLOCK_DATA_ORDER md4_block_data_order
+
+#include "../digest/md32_common.h"
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
+ * simplified to the code below.  Wei attributes these optimizations
+ * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel. */
+#define F(b, c, d) ((((c) ^ (d)) & (b)) ^ (d))
+#define G(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
+#define H(b, c, d) ((b) ^ (c) ^ (d))
+
+#define R0(a, b, c, d, k, s, t)        \
+  {                                    \
+    a += ((k) + (t)+F((b), (c), (d))); \
+    a = ROTATE(a, s);                  \
+  };
+
+#define R1(a, b, c, d, k, s, t)        \
+  {                                    \
+    a += ((k) + (t)+G((b), (c), (d))); \
+    a = ROTATE(a, s);                  \
+  };
+
+#define R2(a, b, c, d, k, s, t)        \
+  {                                    \
+    a += ((k) + (t)+H((b), (c), (d))); \
+    a = ROTATE(a, s);                  \
+  };
+
+void md4_block_data_order(MD4_CTX *c, const void *data_, size_t num) {
+  const uint8_t *data = data_;
+  uint32_t A, B, C, D, l;
+  uint32_t X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15;
+
+  A = c->A;
+  B = c->B;
+  C = c->C;
+  D = c->D;
+
+  for (; num--;) {
+    HOST_c2l(data, l);
+    X0 = l;
+    HOST_c2l(data, l);
+    X1 = l;
+    /* Round 0 */
+    R0(A, B, C, D, X0, 3, 0);
+    HOST_c2l(data, l);
+    X2 = l;
+    R0(D, A, B, C, X1, 7, 0);
+    HOST_c2l(data, l);
+    X3 = l;
+    R0(C, D, A, B, X2, 11, 0);
+    HOST_c2l(data, l);
+    X4 = l;
+    R0(B, C, D, A, X3, 19, 0);
+    HOST_c2l(data, l);
+    X5 = l;
+    R0(A, B, C, D, X4, 3, 0);
+    HOST_c2l(data, l);
+    X6 = l;
+    R0(D, A, B, C, X5, 7, 0);
+    HOST_c2l(data, l);
+    X7 = l;
+    R0(C, D, A, B, X6, 11, 0);
+    HOST_c2l(data, l);
+    X8 = l;
+    R0(B, C, D, A, X7, 19, 0);
+    HOST_c2l(data, l);
+    X9 = l;
+    R0(A, B, C, D, X8, 3, 0);
+    HOST_c2l(data, l);
+    X10 = l;
+    R0(D, A, B, C, X9, 7, 0);
+    HOST_c2l(data, l);
+    X11 = l;
+    R0(C, D, A, B, X10, 11, 0);
+    HOST_c2l(data, l);
+    X12 = l;
+    R0(B, C, D, A, X11, 19, 0);
+    HOST_c2l(data, l);
+    X13 = l;
+    R0(A, B, C, D, X12, 3, 0);
+    HOST_c2l(data, l);
+    X14 = l;
+    R0(D, A, B, C, X13, 7, 0);
+    HOST_c2l(data, l);
+    X15 = l;
+    R0(C, D, A, B, X14, 11, 0);
+    R0(B, C, D, A, X15, 19, 0);
+    /* Round 1 */
+    R1(A, B, C, D, X0, 3, 0x5A827999L);
+    R1(D, A, B, C, X4, 5, 0x5A827999L);
+    R1(C, D, A, B, X8, 9, 0x5A827999L);
+    R1(B, C, D, A, X12, 13, 0x5A827999L);
+    R1(A, B, C, D, X1, 3, 0x5A827999L);
+    R1(D, A, B, C, X5, 5, 0x5A827999L);
+    R1(C, D, A, B, X9, 9, 0x5A827999L);
+    R1(B, C, D, A, X13, 13, 0x5A827999L);
+    R1(A, B, C, D, X2, 3, 0x5A827999L);
+    R1(D, A, B, C, X6, 5, 0x5A827999L);
+    R1(C, D, A, B, X10, 9, 0x5A827999L);
+    R1(B, C, D, A, X14, 13, 0x5A827999L);
+    R1(A, B, C, D, X3, 3, 0x5A827999L);
+    R1(D, A, B, C, X7, 5, 0x5A827999L);
+    R1(C, D, A, B, X11, 9, 0x5A827999L);
+    R1(B, C, D, A, X15, 13, 0x5A827999L);
+    /* Round 2 */
+    R2(A, B, C, D, X0, 3, 0x6ED9EBA1L);
+    R2(D, A, B, C, X8, 9, 0x6ED9EBA1L);
+    R2(C, D, A, B, X4, 11, 0x6ED9EBA1L);
+    R2(B, C, D, A, X12, 15, 0x6ED9EBA1L);
+    R2(A, B, C, D, X2, 3, 0x6ED9EBA1L);
+    R2(D, A, B, C, X10, 9, 0x6ED9EBA1L);
+    R2(C, D, A, B, X6, 11, 0x6ED9EBA1L);
+    R2(B, C, D, A, X14, 15, 0x6ED9EBA1L);
+    R2(A, B, C, D, X1, 3, 0x6ED9EBA1L);
+    R2(D, A, B, C, X9, 9, 0x6ED9EBA1L);
+    R2(C, D, A, B, X5, 11, 0x6ED9EBA1L);
+    R2(B, C, D, A, X13, 15, 0x6ED9EBA1L);
+    R2(A, B, C, D, X3, 3, 0x6ED9EBA1L);
+    R2(D, A, B, C, X11, 9, 0x6ED9EBA1L);
+    R2(C, D, A, B, X7, 11, 0x6ED9EBA1L);
+    R2(B, C, D, A, X15, 15, 0x6ED9EBA1L);
+
+    A = c->A += A;
+    B = c->B += B;
+    C = c->C += C;
+    D = c->D += D;
+  }
+}
diff --git a/crypto/md5/md5_test.c b/crypto/md5/md5_test.c
index eb5984c..fd24341 100644
--- a/crypto/md5/md5_test.c
+++ b/crypto/md5/md5_test.c
@@ -55,8 +55,9 @@
 
 #include <stdio.h>
 
-#include <openssl/md5.h>
+#include <openssl/crypto.h>
 #include <openssl/digest.h>
+#include <openssl/md5.h>
 
 
 static const char *const test[] = {
@@ -78,6 +79,8 @@
   char md_hex[sizeof(md) * 2 + 1];
   int ok = 1;
 
+  CRYPTO_library_init();
+
   for (i = 0; test[i] != NULL; i++) {
     EVP_Digest(test[i], strlen(test[i]), md, NULL, EVP_md5(), NULL);
     for (j = 0; j < sizeof(md); j++) {
diff --git a/crypto/modes/gcm.c b/crypto/modes/gcm.c
index 065c457..96139a8 100644
--- a/crypto/modes/gcm.c
+++ b/crypto/modes/gcm.c
@@ -54,6 +54,7 @@
 #include <openssl/cpu.h>
 
 #include "internal.h"
+#include "../internal.h"
 
 
 #if !defined(OPENSSL_NO_ASM) && \
@@ -70,17 +71,17 @@
 #endif
 
 #define PACK(s) ((size_t)(s) << (sizeof(size_t) * 8 - 16))
-#define REDUCE1BIT(V)                                     \
-  do {                                                    \
-    if (sizeof(size_t) == 8) {                            \
-      uint64_t T = U64(0xe100000000000000) & (0 - (V.lo & 1)); \
-      V.lo = (V.hi << 63) | (V.lo >> 1);                  \
-      V.hi = (V.hi >> 1) ^ T;                             \
-    } else {                                              \
-      uint32_t T = 0xe1000000U & (0 - (uint32_t)(V.lo & 1));        \
-      V.lo = (V.hi << 63) | (V.lo >> 1);                  \
-      V.hi = (V.hi >> 1) ^ ((uint64_t)T << 32);                \
-    }                                                     \
+#define REDUCE1BIT(V)                                                  \
+  do {                                                                 \
+    if (sizeof(size_t) == 8) {                                         \
+      uint64_t T = OPENSSL_U64(0xe100000000000000) & (0 - (V.lo & 1)); \
+      V.lo = (V.hi << 63) | (V.lo >> 1);                               \
+      V.hi = (V.hi >> 1) ^ T;                                          \
+    } else {                                                           \
+      uint32_t T = 0xe1000000U & (0 - (uint32_t)(V.lo & 1));           \
+      V.lo = (V.hi << 63) | (V.lo >> 1);                               \
+      V.hi = (V.hi >> 1) ^ ((uint64_t)T << 32);                        \
+    }                                                                  \
   } while (0)
 
 
@@ -542,7 +543,7 @@
   }
 
   alen += len;
-  if (alen > (U64(1) << 61) || (sizeof(len) == 8 && alen < len)) {
+  if (alen > (OPENSSL_U64(1) << 61) || (sizeof(len) == 8 && alen < len)) {
     return 0;
   }
   ctx->len.u[0] = alen;
@@ -608,7 +609,8 @@
 #endif
 
   mlen += len;
-  if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) {
+  if (mlen > ((OPENSSL_U64(1) << 36) - 32) ||
+      (sizeof(len) == 8 && mlen < len)) {
     return 0;
   }
   ctx->len.u[1] = mlen;
@@ -767,7 +769,8 @@
 #endif
 
   mlen += len;
-  if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) {
+  if (mlen > ((OPENSSL_U64(1) << 36) - 32) ||
+      (sizeof(len) == 8 && mlen < len)) {
     return 0;
   }
   ctx->len.u[1] = mlen;
@@ -932,7 +935,8 @@
 #endif
 
   mlen += len;
-  if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) {
+  if (mlen > ((OPENSSL_U64(1) << 36) - 32) ||
+      (sizeof(len) == 8 && mlen < len)) {
     return 0;
   }
   ctx->len.u[1] = mlen;
@@ -1041,7 +1045,8 @@
 #endif
 
   mlen += len;
-  if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) {
+  if (mlen > ((OPENSSL_U64(1) << 36) - 32) ||
+      (sizeof(len) == 8 && mlen < len)) {
     return 0;
   }
   ctx->len.u[1] = mlen;
diff --git a/crypto/modes/gcm_test.c b/crypto/modes/gcm_test.c
index 8c52b85..5308976 100644
--- a/crypto/modes/gcm_test.c
+++ b/crypto/modes/gcm_test.c
@@ -49,6 +49,7 @@
 #include <stdio.h>
 
 #include <openssl/aes.h>
+#include <openssl/crypto.h>
 #include <openssl/mem.h>
 #include <openssl/modes.h>
 
@@ -413,10 +414,12 @@
   return ret;
 }
 
-int main() {
+int main(void) {
   int ret = 0;
   unsigned i;
 
+  CRYPTO_library_init();
+
   for (i = 0; i < sizeof(test_cases) / sizeof(struct test_case); i++) {
     if (!run_test_case(i, &test_cases[i])) {
       ret = 1;
diff --git a/crypto/modes/internal.h b/crypto/modes/internal.h
index 4659eab..9662e0d 100644
--- a/crypto/modes/internal.h
+++ b/crypto/modes/internal.h
@@ -185,15 +185,6 @@
   void *key;
 };
 
-#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
-#define U64(C) C##UI64
-#elif defined(__arch64__)
-#define U64(C) C##UL
-#else
-#define U64(C) C##ULL
-#endif
-
-
 #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
 /* crypto_gcm_clmul_enabled returns one if the CLMUL implementation of GCM is
  * used. */
diff --git a/crypto/obj/obj.c b/crypto/obj/obj.c
index 6bbac92..bfcc08b 100644
--- a/crypto/obj/obj.c
+++ b/crypto/obj/obj.c
@@ -66,7 +66,7 @@
 #include <openssl/mem.h>
 #include <openssl/thread.h>
 
-#include <openssl/obj_dat.h>
+#include "obj_dat.h"
 
 /* These globals are protected by CRYPTO_LOCK_OBJ. */
 static LHASH_OF(ASN1_OBJECT) *global_added_by_data = NULL;
@@ -76,7 +76,7 @@
 
 static unsigned global_next_nid = NUM_NID;
 
-static int obj_next_nid() {
+static int obj_next_nid(void) {
   int ret;
 
   CRYPTO_w_lock(CRYPTO_LOCK_OBJ);
diff --git a/include/openssl/obj_dat.h b/crypto/obj/obj_dat.h
similarity index 100%
rename from include/openssl/obj_dat.h
rename to crypto/obj/obj_dat.h
diff --git a/crypto/pem/pem_all.c b/crypto/pem/pem_all.c
index c1b8d6e..24ecc62 100644
--- a/crypto/pem/pem_all.c
+++ b/crypto/pem/pem_all.c
@@ -224,7 +224,6 @@
 #endif
 
 
-#ifndef OPENSSL_NO_EC
 static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey)
 {
 	EC_KEY *dtmp;
@@ -271,15 +270,12 @@
 
 #endif
 
-#endif
 
-#ifndef OPENSSL_NO_DH
 
 IMPLEMENT_PEM_write_const(DHparams, DH, PEM_STRING_DHPARAMS, DHparams)
 
 /* TODO(fork): remove this code? */
 /* IMPLEMENT_PEM_write_const(DHxparams, DH, PEM_STRING_DHXPARAMS, DHxparams) */
 
-#endif
 
 IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY)
diff --git a/crypto/pem/pem_info.c b/crypto/pem/pem_info.c
index 6e59a7f..c4974c2 100644
--- a/crypto/pem/pem_info.c
+++ b/crypto/pem/pem_info.c
@@ -207,7 +207,6 @@
 			}
 		else
 #endif
-#ifndef OPENSSL_NO_EC
  			if (strcmp(name,PEM_STRING_ECPRIVATEKEY) == 0)
  			{
  				d2i=(D2I_OF(void))d2i_ECPrivateKey;
@@ -228,7 +227,6 @@
  				raw=1;
 			}
 		else
-#endif
 			{
 			d2i=NULL;
 			pp=NULL;
diff --git a/crypto/pem/pem_pkey.c b/crypto/pem/pem_pkey.c
index d0f08c8..0ef08d0 100644
--- a/crypto/pem/pem_pkey.c
+++ b/crypto/pem/pem_pkey.c
@@ -262,7 +262,6 @@
 
 #endif
 
-#ifndef OPENSSL_NO_DH
 
 /* Transparently read in PKCS#3 or X9.42 DH parameters */
 
@@ -310,4 +309,3 @@
 	}
 #endif
 
-#endif
diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl
index 8018fbd..7c80dc2 100755
--- a/crypto/perlasm/x86_64-xlate.pl
+++ b/crypto/perlasm/x86_64-xlate.pl
@@ -936,7 +936,7 @@
 
 print "\n$current_segment\tENDS\n"	if ($current_segment && $masm);
 print "END\n"				if ($masm);
-print "#endif"				if ($gas);
+print "#endif\n"			if ($gas);
 
 
 close STDOUT;
diff --git a/crypto/pkcs8/CMakeLists.txt b/crypto/pkcs8/CMakeLists.txt
index b89af85..ad62768 100644
--- a/crypto/pkcs8/CMakeLists.txt
+++ b/crypto/pkcs8/CMakeLists.txt
@@ -11,3 +11,11 @@
 	p5_pbev2.c
 	pkcs8_error.c
 )
+
+add_executable(
+	pkcs12_test
+
+	pkcs12_test.c
+)
+
+target_link_libraries(pkcs12_test crypto)
diff --git a/crypto/pkcs8/p8_pkey.c b/crypto/pkcs8/p8_pkey.c
index 9095ffd..bd9d30c 100644
--- a/crypto/pkcs8/p8_pkey.c
+++ b/crypto/pkcs8/p8_pkey.c
@@ -62,23 +62,24 @@
 
 /* Minor tweak to operation: zero private key data */
 static int pkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
-							void *exarg)
-{
-	/* Since the structure must still be valid use ASN1_OP_FREE_PRE */
-	if(operation == ASN1_OP_FREE_PRE) {
-		PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval;
-		if (key->pkey->value.octet_string)
-		OPENSSL_cleanse(key->pkey->value.octet_string->data,
-			key->pkey->value.octet_string->length);
-	}
-	return 1;
+                   void *exarg) {
+  /* Since the structure must still be valid use ASN1_OP_FREE_PRE */
+  if (operation == ASN1_OP_FREE_PRE) {
+    PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval;
+    if (key->pkey &&
+        key->pkey->value.octet_string) {
+      OPENSSL_cleanse(key->pkey->value.octet_string->data,
+                      key->pkey->value.octet_string->length);
+    }
+  }
+  return 1;
 }
 
 ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = {
-	ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER),
-	ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR),
-	ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_ANY),
-	ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0)
-} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
+  ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER),
+  ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR),
+  ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_ANY),
+  ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0)
+} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO);
 
-IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
+IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO);
diff --git a/crypto/pkcs8/pkcs12_test.c b/crypto/pkcs8/pkcs12_test.c
new file mode 100644
index 0000000..2292b77
--- /dev/null
+++ b/crypto/pkcs8/pkcs12_test.c
@@ -0,0 +1,763 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <openssl/bio.h>
+#include <openssl/bytestring.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pkcs8.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+
+/* kPKCS12DER contains sample PKCS#12 data generated by OpenSSL with:
+ * openssl pkcs12 -export -inkey key.pem -in cacert.pem */
+static const uint8_t kOpenSSL[] = {
+    0x30, 0x82, 0x09, 0xa1, 0x02, 0x01, 0x03, 0x30, 0x82, 0x09, 0x67, 0x06,
+    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
+    0x09, 0x58, 0x04, 0x82, 0x09, 0x54, 0x30, 0x82, 0x09, 0x50, 0x30, 0x82,
+    0x04, 0x07, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
+    0x06, 0xa0, 0x82, 0x03, 0xf8, 0x30, 0x82, 0x03, 0xf4, 0x02, 0x01, 0x00,
+    0x30, 0x82, 0x03, 0xed, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x31, 0x24, 0xca,
+    0x7d, 0xc3, 0x25, 0x3e, 0xdc, 0x02, 0x02, 0x08, 0x00, 0x80, 0x82, 0x03,
+    0xc0, 0x55, 0xe7, 0x7f, 0x9c, 0xd6, 0x0c, 0xd2, 0x69, 0x1d, 0x6e, 0x8b,
+    0xb8, 0x07, 0xec, 0x4a, 0xe7, 0x06, 0x67, 0xd1, 0x24, 0x1b, 0xd5, 0x68,
+    0x13, 0x3d, 0xd7, 0x56, 0x5e, 0x15, 0x40, 0xdb, 0xda, 0x88, 0x36, 0xc9,
+    0x02, 0x96, 0xb5, 0xb5, 0xf7, 0x81, 0xef, 0x88, 0x1d, 0x66, 0x62, 0xa8,
+    0x83, 0xf7, 0x91, 0xb1, 0x26, 0x1f, 0x9b, 0x25, 0x78, 0x0a, 0x04, 0xb1,
+    0xc0, 0x93, 0x48, 0xa2, 0xf0, 0x51, 0x4f, 0x2b, 0xf8, 0x03, 0x67, 0x61,
+    0x1b, 0xed, 0x29, 0xfe, 0x3f, 0xdd, 0x83, 0xa3, 0x93, 0x75, 0xa7, 0xd9,
+    0x37, 0x5b, 0xa7, 0xc9, 0xf4, 0x52, 0x86, 0xd2, 0x3f, 0xca, 0x61, 0x5c,
+    0x1e, 0xf9, 0x07, 0x7d, 0xbd, 0xda, 0x76, 0x8a, 0x03, 0x8e, 0x12, 0x4e,
+    0x8f, 0x68, 0x6e, 0x72, 0x6e, 0xf0, 0xbe, 0x22, 0xc7, 0x9d, 0x97, 0x7c,
+    0x45, 0xc0, 0xaa, 0x31, 0xe1, 0x55, 0x81, 0xb3, 0xec, 0x98, 0x94, 0xac,
+    0xf7, 0x15, 0x9b, 0x42, 0x49, 0x8c, 0x2a, 0x29, 0x7a, 0x25, 0x92, 0x64,
+    0x92, 0xbd, 0x4e, 0x5c, 0xec, 0xff, 0x61, 0xbb, 0x8e, 0x5c, 0xc8, 0xdb,
+    0xba, 0x97, 0x30, 0xf4, 0x55, 0x9e, 0x1b, 0xfa, 0xbe, 0x2a, 0x90, 0xcf,
+    0xe8, 0xc0, 0x9d, 0xb0, 0x0e, 0x24, 0x61, 0xe7, 0x3a, 0xb7, 0x7f, 0xda,
+    0x63, 0xaa, 0x2a, 0x4a, 0xa6, 0x91, 0x52, 0xa6, 0x76, 0xc9, 0xbe, 0x9f,
+    0x1b, 0x1d, 0xa4, 0x09, 0x5b, 0x0f, 0xd1, 0x64, 0x4e, 0xdf, 0x0c, 0x44,
+    0x59, 0x3a, 0xef, 0x9a, 0xd8, 0x22, 0xa2, 0x5f, 0x80, 0xb5, 0x4f, 0xbe,
+    0x84, 0x23, 0xe3, 0x74, 0x77, 0x3c, 0x9e, 0x27, 0x64, 0xac, 0x65, 0xf4,
+    0xbb, 0x34, 0xb7, 0xa4, 0xfe, 0x02, 0x1a, 0x88, 0x05, 0x3b, 0x4b, 0xb8,
+    0xd8, 0xb9, 0x26, 0x69, 0x22, 0x97, 0x3d, 0x93, 0x9b, 0xe8, 0x72, 0xaa,
+    0x4d, 0x8f, 0x76, 0x51, 0x12, 0x59, 0x58, 0xf1, 0x1a, 0xa3, 0xdb, 0x5d,
+    0xbc, 0xea, 0x84, 0x19, 0x55, 0x4f, 0x00, 0xfb, 0xe2, 0x57, 0x47, 0xca,
+    0xea, 0xbe, 0x8f, 0x85, 0x8b, 0x1c, 0x27, 0x8d, 0x81, 0x70, 0x7f, 0xf1,
+    0x56, 0x58, 0xe1, 0x26, 0x94, 0xd8, 0x2f, 0xde, 0xac, 0xc8, 0xac, 0xbf,
+    0xc3, 0xc6, 0x67, 0xa6, 0xf4, 0x6c, 0xec, 0x20, 0x3c, 0xbc, 0x9d, 0xd9,
+    0xd0, 0xa1, 0x4e, 0x8c, 0x11, 0x19, 0x2b, 0xb3, 0xa1, 0xdf, 0x6a, 0x8f,
+    0xa2, 0xc3, 0xcc, 0xf6, 0xbd, 0x09, 0x7a, 0x96, 0x61, 0x20, 0xd4, 0x06,
+    0x99, 0x4c, 0x6f, 0x23, 0x9b, 0x4c, 0xcc, 0x73, 0x8b, 0x42, 0x48, 0x99,
+    0x45, 0x8f, 0xcb, 0xc8, 0x46, 0x1a, 0xfb, 0x51, 0x03, 0x6a, 0xf2, 0x22,
+    0x85, 0x88, 0x9d, 0x61, 0x8b, 0x16, 0x33, 0xf4, 0xf7, 0x9b, 0xc8, 0x21,
+    0x4f, 0xb1, 0xcd, 0x30, 0xfc, 0x29, 0x88, 0x12, 0xdc, 0xd4, 0x30, 0x4c,
+    0xb9, 0xad, 0x34, 0xde, 0x01, 0xf8, 0xc1, 0x12, 0xa7, 0x4d, 0xc7, 0x31,
+    0x99, 0x2b, 0x45, 0x88, 0x06, 0x34, 0x69, 0x6e, 0x6d, 0x34, 0xd8, 0xdd,
+    0x0a, 0x3d, 0x59, 0x74, 0x36, 0x31, 0x6a, 0xed, 0x91, 0x3b, 0x5b, 0x88,
+    0x43, 0x46, 0x3f, 0x67, 0x66, 0xe4, 0xde, 0x52, 0xb4, 0xbf, 0x7b, 0x3d,
+    0x54, 0x79, 0xaf, 0x8d, 0xf5, 0x0a, 0x80, 0xfd, 0xeb, 0x31, 0x24, 0xbc,
+    0x24, 0xd7, 0x21, 0x9f, 0x87, 0xab, 0xbd, 0x75, 0x2c, 0x13, 0x13, 0x96,
+    0xab, 0x76, 0xfb, 0xb2, 0x44, 0xd0, 0xd2, 0x19, 0xf1, 0x95, 0x9a, 0x91,
+    0xbf, 0x7a, 0x7b, 0x76, 0x95, 0x72, 0xa9, 0x16, 0xfc, 0x3e, 0xa9, 0x4e,
+    0x01, 0x15, 0x3d, 0x43, 0x73, 0xa3, 0x8b, 0xef, 0x48, 0xad, 0x11, 0xbd,
+    0x53, 0xd3, 0x0c, 0x15, 0x15, 0x1a, 0xb4, 0x3a, 0xe0, 0x7f, 0x9a, 0xa1,
+    0x36, 0x47, 0x72, 0x92, 0xf0, 0xdf, 0xb0, 0xe2, 0xbc, 0x35, 0xd4, 0x32,
+    0x6b, 0x37, 0x69, 0x4f, 0x47, 0x9a, 0xe2, 0x35, 0x8a, 0x31, 0x60, 0xed,
+    0x80, 0x57, 0xe2, 0x9d, 0x58, 0x9c, 0x7f, 0x46, 0xd2, 0x54, 0x0e, 0x28,
+    0x53, 0x8b, 0x1f, 0x46, 0x34, 0x22, 0xac, 0x71, 0xc7, 0xca, 0x0f, 0xb4,
+    0xb7, 0x7a, 0xfc, 0x34, 0x57, 0xa5, 0x86, 0x8d, 0x66, 0x5c, 0xc7, 0x3a,
+    0xdb, 0xf8, 0x79, 0x3a, 0x8a, 0xf6, 0xa2, 0x1e, 0x09, 0xc9, 0x10, 0xe9,
+    0x93, 0x3a, 0xc5, 0xed, 0xb2, 0xca, 0xbb, 0x66, 0xf1, 0x9d, 0xc9, 0x9c,
+    0x42, 0x75, 0x64, 0x3e, 0xe4, 0x12, 0x2b, 0x67, 0xf8, 0xbf, 0x2b, 0x98,
+    0x5d, 0xb6, 0xa0, 0xba, 0x79, 0x98, 0xe0, 0x47, 0x5c, 0x77, 0x85, 0x4e,
+    0x26, 0x71, 0xfe, 0xab, 0x5c, 0xa8, 0x32, 0x93, 0xec, 0xd0, 0x26, 0x90,
+    0xe4, 0xda, 0x2f, 0x34, 0x8a, 0x50, 0xb8, 0x3b, 0x7b, 0x4c, 0x5f, 0xa9,
+    0x3e, 0x8a, 0xa8, 0xf3, 0xc0, 0xb7, 0x50, 0x0b, 0x77, 0x4e, 0x8c, 0xa0,
+    0xaf, 0xdb, 0x59, 0xe7, 0xac, 0xd1, 0x34, 0x4e, 0x62, 0x47, 0x2e, 0x1e,
+    0x5e, 0xb4, 0xc9, 0x64, 0xf8, 0x0f, 0xf4, 0xf8, 0xb6, 0x9a, 0xe3, 0x7e,
+    0xcf, 0xb7, 0xee, 0x11, 0x14, 0x52, 0x89, 0x3b, 0x27, 0x98, 0xfc, 0x95,
+    0xa7, 0xad, 0xbf, 0x61, 0x34, 0xad, 0x1a, 0x24, 0x2a, 0x48, 0x66, 0x65,
+    0x75, 0x9c, 0x59, 0xc0, 0x4f, 0x5f, 0x3d, 0x5a, 0x8c, 0xee, 0xd0, 0xb1,
+    0x17, 0x6d, 0x34, 0x46, 0x37, 0xa0, 0xba, 0x71, 0xac, 0x77, 0x73, 0x29,
+    0xa3, 0x37, 0x4f, 0x02, 0xd3, 0x7f, 0x0e, 0xe8, 0xce, 0xff, 0x80, 0x11,
+    0x45, 0x42, 0x03, 0x5a, 0x87, 0xaa, 0xff, 0x25, 0x12, 0x1f, 0x43, 0x19,
+    0x3e, 0xa9, 0x62, 0x96, 0x0c, 0x6f, 0x33, 0x88, 0x5c, 0xaa, 0xf9, 0xe2,
+    0xb4, 0xb9, 0xf7, 0x55, 0xae, 0xb5, 0x76, 0x57, 0x47, 0x83, 0xe3, 0xfa,
+    0x05, 0xda, 0x86, 0x02, 0x97, 0xb4, 0x60, 0xae, 0x59, 0xd5, 0x6c, 0xc1,
+    0x33, 0xe1, 0x36, 0x36, 0x94, 0x79, 0x9e, 0xad, 0xa3, 0x2d, 0xbc, 0xb5,
+    0xa2, 0xeb, 0xdd, 0xcd, 0xcb, 0x48, 0x42, 0x15, 0xb8, 0xe6, 0x0e, 0x76,
+    0x5b, 0x57, 0x74, 0x24, 0xe6, 0x89, 0xc4, 0xe8, 0x08, 0xa9, 0xfe, 0xb3,
+    0x23, 0xa6, 0xca, 0x72, 0xe2, 0xe4, 0xcb, 0xc1, 0x4a, 0xd1, 0x1d, 0xb9,
+    0x5e, 0x36, 0x97, 0x19, 0x7c, 0x15, 0x48, 0xf1, 0x2d, 0xeb, 0xec, 0xad,
+    0x52, 0x6f, 0x2f, 0xe1, 0x19, 0xcf, 0xcf, 0x98, 0x13, 0x0d, 0xcc, 0xb2,
+    0xa6, 0x8a, 0xda, 0x93, 0x24, 0x3d, 0x5d, 0x83, 0xfe, 0x8d, 0x9e, 0x47,
+    0xd8, 0x6e, 0x8d, 0x06, 0x52, 0x7d, 0x46, 0x84, 0x04, 0x69, 0x34, 0x61,
+    0x04, 0x50, 0x1f, 0x86, 0x92, 0x94, 0xe9, 0x0b, 0x13, 0x5b, 0xf6, 0x16,
+    0x81, 0xeb, 0xfa, 0xf1, 0xbb, 0x04, 0x68, 0x17, 0xca, 0x35, 0x6f, 0xba,
+    0x4e, 0x4c, 0x33, 0xce, 0xf4, 0x26, 0xb7, 0x74, 0xab, 0xa5, 0xd0, 0xaa,
+    0x0d, 0x85, 0x11, 0x30, 0x58, 0x62, 0xdf, 0x48, 0xc7, 0xdf, 0xc9, 0x38,
+    0x9e, 0x6f, 0x96, 0x23, 0x2f, 0xc1, 0xd4, 0x8d, 0x65, 0x9b, 0x46, 0x5f,
+    0x9c, 0xea, 0x26, 0x60, 0xb5, 0x95, 0x85, 0x71, 0x18, 0xc3, 0xf4, 0x54,
+    0x61, 0xca, 0xfe, 0x55, 0x3b, 0xbe, 0x81, 0xaf, 0xd9, 0x3a, 0x27, 0xe9,
+    0x1c, 0x30, 0x82, 0x05, 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x05, 0x32, 0x04, 0x82, 0x05, 0x2e,
+    0x30, 0x82, 0x05, 0x2a, 0x30, 0x82, 0x05, 0x26, 0x06, 0x0b, 0x2a, 0x86,
+    0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x04,
+    0xee, 0x30, 0x82, 0x04, 0xea, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48,
+    0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0xd9,
+    0x68, 0xcb, 0x08, 0x16, 0xc8, 0x93, 0x57, 0x02, 0x02, 0x08, 0x00, 0x04,
+    0x82, 0x04, 0xc8, 0x7c, 0xdb, 0xa6, 0x1e, 0x33, 0xa4, 0xc6, 0x4e, 0x13,
+    0x22, 0x7a, 0x1f, 0xc6, 0x82, 0xab, 0x93, 0x5f, 0xf0, 0xa4, 0xe4, 0x40,
+    0xac, 0xdf, 0x16, 0xec, 0x8d, 0x1f, 0xd9, 0xe4, 0x03, 0xd6, 0xc9, 0xc4,
+    0x1d, 0xfd, 0xa3, 0xe3, 0xba, 0xfc, 0xcb, 0xd0, 0x47, 0x65, 0x0c, 0x6e,
+    0x5d, 0xfc, 0xd2, 0xd4, 0x63, 0xa7, 0x93, 0xf6, 0x8a, 0x44, 0x8c, 0xfe,
+    0x84, 0xd8, 0x0d, 0xa6, 0x16, 0x22, 0xe1, 0x65, 0x10, 0x5e, 0x18, 0x44,
+    0x58, 0x2f, 0xc7, 0x64, 0x74, 0x5f, 0xcf, 0x73, 0x34, 0xe1, 0x4b, 0xe4,
+    0xb3, 0x5b, 0xdb, 0x81, 0x4b, 0x1c, 0x38, 0x72, 0xa6, 0xc5, 0xeb, 0x56,
+    0x9b, 0xc7, 0xe3, 0x3d, 0x54, 0x6e, 0x05, 0x2c, 0xd3, 0x57, 0xc9, 0x4f,
+    0x80, 0x1e, 0xd7, 0xd8, 0x26, 0x6a, 0xcb, 0x79, 0x46, 0x70, 0xfc, 0x45,
+    0xa7, 0x79, 0xab, 0x01, 0x03, 0xb6, 0xb1, 0x44, 0x41, 0xd9, 0x73, 0x37,
+    0xaa, 0xd7, 0xf9, 0x44, 0x93, 0xaf, 0xbb, 0xb5, 0x77, 0xeb, 0x2b, 0x20,
+    0x2e, 0xbd, 0xea, 0x2f, 0xde, 0xa6, 0x2f, 0xd6, 0xac, 0x74, 0xa5, 0x34,
+    0xfb, 0xdf, 0xf7, 0x02, 0xa2, 0x20, 0x15, 0xc8, 0x61, 0x72, 0xbb, 0x7f,
+    0x04, 0xf6, 0x0f, 0xf8, 0x7e, 0xc3, 0xe6, 0xab, 0x2a, 0xe6, 0xd8, 0xe1,
+    0x0d, 0x5a, 0x3c, 0xc0, 0x58, 0xae, 0xf8, 0x1b, 0x15, 0x3c, 0x7b, 0x7f,
+    0xf5, 0x9f, 0xec, 0xf7, 0x3f, 0x30, 0x4f, 0x3d, 0x6c, 0x44, 0xdd, 0x0e,
+    0x4c, 0x2c, 0x93, 0x68, 0x43, 0x31, 0xa8, 0x97, 0x4b, 0xf6, 0x66, 0x71,
+    0x2a, 0x52, 0x3e, 0x3a, 0xe6, 0x72, 0x8a, 0xe6, 0xe3, 0xc8, 0xff, 0x65,
+    0x68, 0x1a, 0x46, 0x21, 0xb3, 0xf0, 0x46, 0x7c, 0x0c, 0x65, 0xd1, 0x8e,
+    0xa4, 0x91, 0x11, 0x5c, 0x93, 0xeb, 0xeb, 0xae, 0x46, 0xf4, 0xbb, 0xf8,
+    0xf3, 0x7e, 0x20, 0x30, 0xf8, 0xcd, 0x19, 0xcd, 0x54, 0x0a, 0x7f, 0x4f,
+    0xe8, 0xac, 0xa9, 0xac, 0x72, 0x96, 0x80, 0x45, 0x2a, 0x4a, 0x63, 0x90,
+    0x01, 0x19, 0xd0, 0x7e, 0x26, 0x53, 0x2d, 0xc4, 0x20, 0xa5, 0x1f, 0x89,
+    0x67, 0x0f, 0xd9, 0x75, 0x51, 0x0a, 0xf1, 0xd4, 0xfd, 0x2e, 0xbe, 0xe6,
+    0x94, 0x3b, 0x6c, 0x8c, 0xe3, 0x0f, 0x5f, 0xce, 0x58, 0x48, 0xde, 0x8d,
+    0xeb, 0xd3, 0xe1, 0x0a, 0xcd, 0xdf, 0x34, 0x4d, 0xd1, 0x5b, 0xab, 0x41,
+    0x41, 0x6b, 0xeb, 0xa1, 0x2f, 0x01, 0x4a, 0x72, 0x2e, 0xf4, 0x5e, 0x44,
+    0x76, 0xc7, 0xe6, 0x16, 0xb9, 0xfb, 0x10, 0x37, 0x00, 0x2d, 0xc6, 0x3b,
+    0x17, 0x72, 0x21, 0xdb, 0xac, 0x86, 0x7b, 0xf5, 0x70, 0x3f, 0x73, 0xa3,
+    0xce, 0x0e, 0x20, 0xbb, 0x59, 0x4c, 0x23, 0xc2, 0xe8, 0x22, 0x22, 0xe0,
+    0x02, 0x0d, 0xe4, 0xa2, 0x3f, 0x55, 0x9d, 0xc0, 0xeb, 0x9a, 0xc4, 0xf3,
+    0xaa, 0xb8, 0xf1, 0x73, 0xec, 0x47, 0xe8, 0x2d, 0x6b, 0xa1, 0x40, 0x94,
+    0xf6, 0x07, 0xb9, 0x6f, 0x03, 0x5a, 0x78, 0xe5, 0x59, 0x41, 0x1a, 0xc7,
+    0xcd, 0x43, 0x10, 0x20, 0x28, 0x95, 0xe0, 0x2a, 0x6f, 0xf2, 0xf8, 0x12,
+    0xd6, 0x13, 0x7f, 0x37, 0x3d, 0x38, 0xa7, 0x22, 0x91, 0xc6, 0xe3, 0x52,
+    0xde, 0xd8, 0xbf, 0x78, 0x9a, 0xa4, 0xf7, 0xc0, 0x8c, 0xbf, 0x81, 0x28,
+    0x20, 0xb8, 0x01, 0xde, 0xb5, 0x6b, 0x0a, 0x56, 0x12, 0x5c, 0x62, 0x1d,
+    0xaf, 0xb7, 0xf2, 0x74, 0x66, 0x0a, 0x7a, 0xc4, 0x9f, 0x1e, 0xc2, 0xa8,
+    0x4c, 0xd6, 0x76, 0x6d, 0x74, 0x35, 0x37, 0x12, 0x5c, 0x95, 0xee, 0x98,
+    0x1d, 0xe2, 0x91, 0xde, 0x13, 0x08, 0xd0, 0x59, 0x4d, 0x62, 0x92, 0x69,
+    0x1b, 0xf7, 0x21, 0x45, 0xaf, 0x83, 0xf8, 0x64, 0xf0, 0xfb, 0x92, 0x9d,
+    0xa1, 0xd9, 0x61, 0x5e, 0x00, 0xc8, 0x1a, 0x6e, 0x6a, 0x2d, 0xad, 0xa8,
+    0x1b, 0x0e, 0xaf, 0xea, 0xb2, 0xae, 0x1c, 0x89, 0xc7, 0x4d, 0x2c, 0x0f,
+    0x4d, 0x8d, 0x78, 0x8d, 0x15, 0x9d, 0x4c, 0x90, 0x52, 0xa1, 0xa9, 0xd8,
+    0xb2, 0x66, 0xb9, 0xb1, 0x46, 0x0a, 0x69, 0x86, 0x2b, 0x0f, 0xb2, 0x41,
+    0xce, 0xe8, 0x8e, 0x49, 0x97, 0x08, 0x0b, 0x70, 0x97, 0xcb, 0xa4, 0x33,
+    0x3f, 0x83, 0x6b, 0x6c, 0x17, 0xce, 0xd8, 0xd5, 0x9b, 0xd4, 0x55, 0x9b,
+    0x99, 0xe1, 0xba, 0x61, 0x31, 0x36, 0x79, 0x31, 0x5f, 0xa1, 0x8c, 0xa9,
+    0x77, 0x42, 0xaa, 0x8c, 0x45, 0x6e, 0xb6, 0x90, 0x08, 0xe8, 0x2e, 0xc4,
+    0x72, 0x69, 0x42, 0xca, 0xa2, 0xd4, 0x8a, 0x2c, 0x37, 0xe1, 0xde, 0xb8,
+    0x98, 0x36, 0xeb, 0xcc, 0x58, 0x0c, 0x24, 0xad, 0xab, 0x62, 0x44, 0x6d,
+    0x80, 0xd5, 0xce, 0x2e, 0x4a, 0x3e, 0xa5, 0xc5, 0x34, 0xf8, 0x32, 0x26,
+    0x2a, 0x56, 0xa4, 0xdd, 0xe9, 0x92, 0x06, 0xad, 0xe8, 0x85, 0x77, 0x6b,
+    0xf1, 0x1b, 0xeb, 0xac, 0x77, 0x19, 0x1c, 0x6a, 0xb7, 0xef, 0x28, 0x70,
+    0x87, 0x92, 0x33, 0xdd, 0xaa, 0x30, 0xc1, 0xa0, 0x93, 0x64, 0x18, 0xa2,
+    0x91, 0x7f, 0xf7, 0xc4, 0xa5, 0x16, 0x93, 0xb3, 0x5b, 0xd8, 0x53, 0x28,
+    0xc5, 0x5e, 0xb1, 0xce, 0x97, 0xbc, 0xb6, 0x65, 0xa8, 0x53, 0xcd, 0xf4,
+    0x4d, 0x6b, 0xea, 0x6f, 0x6f, 0xa5, 0x1c, 0xf1, 0x0f, 0xcb, 0x04, 0x25,
+    0x4a, 0xfe, 0x7d, 0xfc, 0xa3, 0xbd, 0x41, 0xd3, 0x96, 0x6a, 0x8b, 0xad,
+    0xd4, 0xaa, 0x0a, 0x76, 0xea, 0x3b, 0xab, 0x39, 0x55, 0xa3, 0x89, 0x9f,
+    0xf6, 0xf5, 0x9b, 0x9c, 0x83, 0xf8, 0x28, 0x50, 0xdf, 0x31, 0x74, 0x83,
+    0xdb, 0xf1, 0x0f, 0x4c, 0x35, 0x6a, 0xe5, 0x64, 0x2e, 0xb9, 0x77, 0x3d,
+    0xdd, 0xff, 0xa3, 0xa7, 0x90, 0x79, 0xc6, 0x5b, 0x01, 0x16, 0x38, 0xa8,
+    0x22, 0xa3, 0x14, 0x13, 0xed, 0xd0, 0x89, 0x0d, 0x1f, 0x3a, 0x41, 0x4c,
+    0x57, 0x79, 0xfc, 0x1d, 0xdf, 0xad, 0x1a, 0x11, 0x15, 0x31, 0x7e, 0xdb,
+    0x99, 0x3a, 0x6c, 0xde, 0x94, 0x9a, 0x45, 0x4c, 0xfb, 0xa5, 0xa5, 0x31,
+    0xee, 0xe3, 0x09, 0x13, 0x6d, 0xfd, 0x19, 0x37, 0x3f, 0xf6, 0xed, 0x8f,
+    0x0c, 0xce, 0x4b, 0xd1, 0xe1, 0x3d, 0xfb, 0x85, 0x00, 0x84, 0x19, 0xeb,
+    0xa2, 0x63, 0x1d, 0x2b, 0x2d, 0x21, 0xee, 0x08, 0x5a, 0x6d, 0xb0, 0xb1,
+    0xd6, 0x81, 0x00, 0xb6, 0xd0, 0x09, 0x90, 0xb4, 0x84, 0x17, 0xd9, 0x2a,
+    0x3c, 0x1d, 0x53, 0xc6, 0xc1, 0x8b, 0xda, 0xae, 0x0c, 0x0a, 0x3e, 0x1c,
+    0x8a, 0xc4, 0xd6, 0x97, 0x5d, 0x48, 0xe7, 0x79, 0x80, 0x78, 0xaa, 0xde,
+    0x17, 0x60, 0x5d, 0x28, 0x15, 0x3a, 0x42, 0xb7, 0x85, 0xc8, 0x60, 0x93,
+    0x28, 0xb0, 0x4e, 0xc9, 0xf7, 0x46, 0xe7, 0xfc, 0x4e, 0x9f, 0x9f, 0x12,
+    0xdf, 0xcb, 0x6e, 0x0c, 0xaf, 0x71, 0xda, 0xb7, 0xec, 0x3d, 0x46, 0xf3,
+    0x35, 0x41, 0x42, 0xd8, 0x27, 0x92, 0x99, 0x1c, 0x4d, 0xc9, 0x3c, 0xe9,
+    0x0e, 0xcb, 0x3f, 0x57, 0x65, 0x77, 0x0d, 0xdd, 0xff, 0xea, 0x70, 0x35,
+    0xcc, 0xf5, 0x38, 0x1b, 0x57, 0xdf, 0x6d, 0xcb, 0xfd, 0x13, 0x39, 0xd6,
+    0x04, 0xe2, 0xf1, 0xc2, 0xd9, 0xea, 0x8c, 0x9f, 0xfb, 0xb5, 0xfc, 0xe6,
+    0xa9, 0xaa, 0x0f, 0x43, 0xc9, 0x9c, 0x91, 0xe4, 0x21, 0xaf, 0x37, 0x14,
+    0x78, 0x46, 0xe1, 0x29, 0x41, 0x0c, 0x4e, 0xf5, 0x93, 0x1d, 0xf8, 0x33,
+    0x47, 0x6f, 0x9d, 0x8b, 0xf3, 0x27, 0xd4, 0xbb, 0xf6, 0xae, 0xfa, 0xa5,
+    0x8b, 0x41, 0x8f, 0xb4, 0xd7, 0x2f, 0xc1, 0x27, 0xea, 0x70, 0x55, 0x1d,
+    0xe2, 0xd8, 0x0c, 0x4a, 0x5e, 0x7c, 0x87, 0xa4, 0x0e, 0x84, 0x07, 0xd3,
+    0x38, 0x67, 0x2c, 0x55, 0x11, 0xfd, 0x1e, 0xda, 0x4d, 0x66, 0x01, 0x12,
+    0x0c, 0x1b, 0x7c, 0x7c, 0x5c, 0x82, 0x21, 0x35, 0x65, 0x5c, 0x7a, 0xd2,
+    0x66, 0xc2, 0x2b, 0x5e, 0xb8, 0xb1, 0xcb, 0xdf, 0x59, 0xc9, 0x31, 0xb7,
+    0x17, 0x26, 0x96, 0x5e, 0x6f, 0x1c, 0x62, 0x3d, 0x8d, 0x88, 0xf1, 0xd1,
+    0x01, 0x3e, 0xf9, 0x6f, 0xb9, 0x77, 0xdc, 0xee, 0xee, 0x78, 0x59, 0xef,
+    0xcf, 0x3a, 0x87, 0x88, 0xa2, 0xea, 0xfd, 0x0a, 0xa9, 0xa9, 0x3e, 0x0c,
+    0xf8, 0x7f, 0x97, 0x32, 0x17, 0xc2, 0x97, 0xcb, 0xa4, 0x9b, 0xae, 0x5d,
+    0xe7, 0x39, 0x2b, 0x2b, 0xa8, 0xe6, 0x7b, 0x51, 0x75, 0x1f, 0x53, 0x54,
+    0x37, 0xf4, 0x00, 0xa4, 0xb0, 0xa0, 0x93, 0xb4, 0x33, 0xe7, 0xae, 0x28,
+    0xc0, 0x2d, 0x3a, 0xb3, 0xaa, 0xd7, 0x3c, 0x76, 0x44, 0x4b, 0xbb, 0x6a,
+    0x67, 0x98, 0xce, 0xf8, 0x15, 0x13, 0x67, 0x79, 0x3c, 0x15, 0x09, 0xb7,
+    0x22, 0xc0, 0xec, 0x07, 0x8a, 0xfd, 0x44, 0xcb, 0x99, 0xbd, 0xdc, 0xd5,
+    0x53, 0x4c, 0x97, 0x1b, 0x46, 0xaf, 0xc0, 0x6c, 0x06, 0x01, 0x93, 0x8a,
+    0x50, 0x51, 0x6a, 0xe4, 0x5c, 0x0a, 0x52, 0x81, 0x3b, 0x75, 0xed, 0xa2,
+    0x97, 0xa6, 0x5c, 0x55, 0x63, 0xee, 0xfb, 0x33, 0x82, 0x10, 0xa8, 0x21,
+    0x1a, 0x8d, 0xc8, 0xe1, 0x52, 0x68, 0x38, 0x88, 0x2f, 0xae, 0x2b, 0x22,
+    0x7a, 0x9b, 0x0c, 0x19, 0x73, 0x6f, 0x91, 0xc7, 0xfa, 0x95, 0x61, 0x28,
+    0x74, 0x73, 0x70, 0x31, 0x25, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, 0x48,
+    0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14, 0x14, 0x74,
+    0x2d, 0x52, 0x8e, 0x0d, 0x0c, 0x06, 0x6c, 0x32, 0x64, 0xd3, 0x7e, 0x33,
+    0x31, 0x68, 0x8b, 0x28, 0x1a, 0x75, 0x30, 0x31, 0x30, 0x21, 0x30, 0x09,
+    0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x22,
+    0x8e, 0xff, 0x5a, 0x78, 0xec, 0x2c, 0x21, 0xa2, 0x48, 0xb7, 0x63, 0x88,
+    0x10, 0x47, 0x1c, 0xc0, 0xd3, 0xec, 0x5a, 0x04, 0x08, 0xb3, 0x2e, 0x21,
+    0xfd, 0x82, 0x14, 0xd8, 0x5c, 0x02, 0x02, 0x08, 0x00,
+};
+
+/* kNSS is the result of importing the OpenSSL example PKCS#12 into Chrome and
+ * then exporting it again. */
+static const uint8_t kNSS[] = {
+    0x30, 0x80, 0x02, 0x01, 0x03, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48,
+    0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x82,
+    0x09, 0xef, 0x30, 0x80, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+    0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x82, 0x05,
+    0x77, 0x30, 0x82, 0x05, 0x73, 0x30, 0x82, 0x05, 0x6f, 0x06, 0x0b, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82,
+    0x04, 0xf6, 0x30, 0x82, 0x04, 0xf2, 0x30, 0x24, 0x06, 0x0a, 0x2a, 0x86,
+    0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x16, 0x04, 0x10,
+    0xac, 0x71, 0x8a, 0x7c, 0x89, 0xcf, 0xa8, 0xb0, 0xd6, 0xd1, 0x07, 0xf0,
+    0x83, 0x4f, 0x7a, 0xd0, 0x02, 0x02, 0x07, 0xd0, 0x04, 0x82, 0x04, 0xc8,
+    0xea, 0x51, 0x2c, 0x61, 0xaa, 0x9d, 0xf3, 0x90, 0xe1, 0x38, 0x45, 0xb0,
+    0x5f, 0xfd, 0xe2, 0x04, 0x65, 0xe6, 0xff, 0x87, 0xb6, 0x78, 0x69, 0xb0,
+    0xcb, 0x14, 0xe9, 0x99, 0x39, 0xe3, 0xe5, 0x70, 0x84, 0x57, 0x68, 0xf7,
+    0x28, 0xb9, 0x75, 0xa6, 0xfb, 0x16, 0x72, 0xe1, 0x34, 0xb8, 0x3b, 0x61,
+    0x51, 0x89, 0x18, 0x94, 0x40, 0xef, 0x73, 0xda, 0xdb, 0xd7, 0xb7, 0x44,
+    0x73, 0x8f, 0x16, 0x84, 0xa2, 0x99, 0xa6, 0x05, 0x5e, 0x74, 0xae, 0xe2,
+    0xcf, 0x3e, 0x99, 0xca, 0xcd, 0x76, 0x36, 0x77, 0x59, 0xec, 0x25, 0x59,
+    0x3d, 0x4b, 0x45, 0xa5, 0x4e, 0x7b, 0x7a, 0xc9, 0x8b, 0xde, 0x4f, 0x70,
+    0x6d, 0xb1, 0xa8, 0xf3, 0xb6, 0xb5, 0xe7, 0x67, 0x3f, 0xe9, 0x64, 0xb8,
+    0x49, 0xf4, 0x11, 0x94, 0x9d, 0x1c, 0xb0, 0xa5, 0xfb, 0xb3, 0x61, 0xd4,
+    0xf3, 0xa7, 0x68, 0x66, 0xd7, 0xa4, 0xf0, 0xcd, 0xc8, 0x40, 0x4f, 0x3e,
+    0xa7, 0x26, 0x40, 0x76, 0x64, 0xa1, 0x4e, 0xf1, 0x91, 0xc2, 0xa3, 0xef,
+    0xbc, 0xcd, 0x42, 0xe5, 0xd2, 0x6f, 0xff, 0xfe, 0x4d, 0x33, 0x01, 0xb4,
+    0x99, 0x63, 0x1b, 0xd3, 0x01, 0x55, 0x00, 0xa6, 0x23, 0x9b, 0xa9, 0x17,
+    0x09, 0x38, 0x32, 0x18, 0x36, 0xbc, 0x20, 0x02, 0xfe, 0x7b, 0xec, 0xd3,
+    0x4c, 0x7d, 0xc9, 0xc9, 0xce, 0x66, 0x3b, 0x34, 0x6e, 0xea, 0xf9, 0xb1,
+    0x1a, 0x83, 0xa3, 0x3c, 0x8d, 0xc7, 0x79, 0xc9, 0xff, 0x6b, 0x1d, 0x35,
+    0xf6, 0x2a, 0x3d, 0x3b, 0x83, 0x16, 0x64, 0xcf, 0x9f, 0x7c, 0x31, 0x02,
+    0xda, 0x37, 0x1a, 0x16, 0x49, 0xdc, 0xd9, 0x70, 0xae, 0x99, 0x2c, 0xc7,
+    0x01, 0xba, 0x42, 0xab, 0xe9, 0x4d, 0xa4, 0x78, 0x2c, 0xbd, 0xa0, 0xf1,
+    0xb7, 0xcf, 0xdd, 0xc1, 0xdb, 0x8f, 0x04, 0x87, 0x0b, 0x47, 0x4f, 0xd5,
+    0xd5, 0xe7, 0xfc, 0x6e, 0x42, 0xd5, 0x91, 0x4d, 0x7b, 0x1b, 0x5c, 0x3c,
+    0x02, 0x70, 0xdb, 0x05, 0x91, 0xaf, 0x35, 0x43, 0x05, 0xc2, 0x6d, 0xcf,
+    0x59, 0x23, 0xfc, 0xc4, 0xf6, 0x67, 0xf1, 0x84, 0x61, 0x4a, 0xb6, 0x4c,
+    0x15, 0x15, 0xa3, 0xea, 0x8f, 0x13, 0x15, 0xe3, 0xd2, 0xb5, 0x50, 0xc8,
+    0xae, 0xc8, 0x5c, 0x03, 0xb5, 0x63, 0x93, 0xaa, 0x10, 0xd7, 0x56, 0x0d,
+    0x6e, 0x13, 0x45, 0x8f, 0xec, 0x17, 0x5c, 0x5c, 0x73, 0x91, 0x5f, 0x6c,
+    0xaf, 0x11, 0x13, 0x32, 0x5e, 0x14, 0xf9, 0xaf, 0xaf, 0x43, 0x04, 0x60,
+    0x93, 0x42, 0x30, 0xa6, 0x75, 0xc0, 0x83, 0xd2, 0x4c, 0xa5, 0x0a, 0x16,
+    0x39, 0xef, 0x3f, 0xf7, 0x9d, 0x23, 0x19, 0xb9, 0xcd, 0xd8, 0x7c, 0x6e,
+    0xee, 0x6d, 0x2e, 0xff, 0x5a, 0xf3, 0xb9, 0xab, 0xe5, 0x64, 0xdc, 0xc2,
+    0x67, 0x30, 0x73, 0x19, 0x2d, 0xea, 0xd2, 0x19, 0x1f, 0x1f, 0xe0, 0xd9,
+    0xac, 0xc9, 0xdb, 0x38, 0x74, 0x5e, 0x31, 0x47, 0x2e, 0x9e, 0x2b, 0xcc,
+    0xb9, 0xe4, 0x29, 0xf8, 0xb2, 0xbf, 0x1b, 0xbc, 0x68, 0x96, 0x79, 0xcf,
+    0xaf, 0xf2, 0x1f, 0x57, 0x3f, 0x74, 0xc4, 0x71, 0x63, 0xb4, 0xe8, 0xbe,
+    0x58, 0xdb, 0x28, 0x62, 0xb5, 0x79, 0x8b, 0xe4, 0xd0, 0x96, 0xd0, 0xda,
+    0x0f, 0xd2, 0x70, 0x93, 0x2f, 0x71, 0xe0, 0x9f, 0x28, 0xb7, 0x52, 0x38,
+    0x9c, 0xcb, 0x8b, 0x2a, 0x8e, 0xbf, 0x0e, 0x3d, 0x60, 0x05, 0x0a, 0x91,
+    0x5b, 0xb5, 0x78, 0x10, 0x31, 0x00, 0x80, 0x31, 0x2d, 0xd7, 0xb0, 0x88,
+    0xc7, 0xd9, 0x58, 0xc6, 0xfc, 0x3b, 0xf4, 0xee, 0xec, 0xba, 0x05, 0xae,
+    0xae, 0xff, 0xcf, 0xd0, 0x71, 0xc6, 0xe7, 0xf3, 0x8b, 0x64, 0x50, 0x7a,
+    0x09, 0x93, 0x0f, 0x34, 0x59, 0x2d, 0xde, 0x4b, 0x1d, 0x86, 0x49, 0xff,
+    0x63, 0x76, 0x28, 0x6b, 0x52, 0x1b, 0x46, 0x06, 0x18, 0x90, 0x1c, 0x2d,
+    0xc5, 0x03, 0xcc, 0x00, 0x4d, 0xb7, 0xb2, 0x12, 0xc5, 0xf9, 0xb4, 0xa4,
+    0x6a, 0x36, 0x62, 0x46, 0x34, 0x2a, 0xf0, 0x11, 0xa3, 0xd6, 0x80, 0x21,
+    0xbf, 0x3b, 0xfd, 0xc5, 0x25, 0xa0, 0x4d, 0xc0, 0x2e, 0xc0, 0xf1, 0x7b,
+    0x96, 0x11, 0x64, 0x8e, 0xb9, 0xdb, 0x89, 0x4e, 0x33, 0x89, 0xf5, 0xc6,
+    0xfc, 0x2b, 0x99, 0xf5, 0xc2, 0x04, 0x83, 0x15, 0x47, 0xa8, 0xa5, 0xc1,
+    0x4a, 0xe4, 0x76, 0xab, 0x3e, 0xf0, 0x9b, 0xb7, 0x8d, 0x46, 0xd3, 0x52,
+    0x9b, 0xbd, 0xfd, 0x2b, 0xba, 0x73, 0x5d, 0x23, 0x67, 0x68, 0xe1, 0x76,
+    0x6f, 0x56, 0x2b, 0x17, 0xe4, 0x7e, 0x9a, 0xfd, 0x05, 0x48, 0x39, 0xc9,
+    0xcf, 0xa5, 0x83, 0xf7, 0x90, 0x9c, 0xa4, 0x28, 0x57, 0x40, 0xe9, 0xd4,
+    0x4b, 0x1a, 0x4b, 0x6f, 0x65, 0x14, 0xca, 0x43, 0xc1, 0x3f, 0x7c, 0xec,
+    0x82, 0x47, 0x0e, 0x64, 0x8b, 0x6f, 0x8c, 0xb2, 0xf0, 0x6d, 0xeb, 0x6f,
+    0x71, 0x8f, 0xcc, 0x2d, 0x60, 0x2b, 0xc3, 0x9f, 0x13, 0x94, 0xc7, 0x23,
+    0x02, 0xf5, 0xe6, 0xdf, 0x2d, 0xa9, 0xdb, 0xa9, 0xf3, 0xee, 0xe9, 0x3f,
+    0x2a, 0x69, 0x24, 0x6b, 0x78, 0xff, 0x6a, 0xd7, 0xe4, 0x69, 0x8c, 0x17,
+    0xd5, 0xc1, 0x36, 0x1a, 0xca, 0x77, 0xb0, 0xb5, 0x6b, 0x96, 0x4a, 0xb5,
+    0x0e, 0x4d, 0x0b, 0xd6, 0xd9, 0x78, 0xc5, 0xbf, 0xe3, 0x59, 0xfe, 0x63,
+    0xe3, 0xd3, 0x3c, 0x9a, 0xfa, 0xd7, 0x69, 0x5b, 0xef, 0xd3, 0xa4, 0xa3,
+    0xb9, 0x1f, 0x5c, 0x40, 0x20, 0x95, 0x38, 0x2d, 0xf5, 0x04, 0x0c, 0x2c,
+    0x79, 0x77, 0xc1, 0xb6, 0xcc, 0x74, 0x3c, 0x66, 0xf1, 0xc6, 0x65, 0xab,
+    0x4d, 0x68, 0x41, 0x16, 0x71, 0x51, 0xb9, 0x1b, 0xcb, 0xa7, 0x6d, 0xe0,
+    0x70, 0xa9, 0xfa, 0x65, 0x6b, 0x7b, 0x1e, 0xc5, 0xdf, 0xe2, 0x4c, 0x96,
+    0x44, 0x6b, 0x24, 0xa1, 0x15, 0x8e, 0xe7, 0x9b, 0x1f, 0x51, 0xef, 0xd7,
+    0x65, 0x5f, 0xcd, 0x74, 0x7f, 0x2d, 0x5c, 0xba, 0xba, 0x20, 0x32, 0x8d,
+    0x1c, 0xf1, 0x5a, 0xed, 0x21, 0xad, 0x78, 0x7b, 0x59, 0x58, 0xe4, 0xf6,
+    0xa7, 0x10, 0x35, 0xca, 0x5d, 0x86, 0x1a, 0x68, 0xba, 0x1c, 0x3c, 0x1c,
+    0x23, 0x79, 0x8b, 0x9f, 0xda, 0x5c, 0xd1, 0x5a, 0xa9, 0xc8, 0xf6, 0xc9,
+    0xdf, 0x21, 0x5a, 0x98, 0xdc, 0xf4, 0xb9, 0x02, 0x97, 0x2c, 0x10, 0x60,
+    0xc9, 0xb5, 0xea, 0x75, 0x0b, 0xd9, 0x8a, 0xa4, 0x86, 0x92, 0xbe, 0xf5,
+    0xd8, 0xc7, 0x6b, 0x13, 0x8b, 0xbb, 0xca, 0x5f, 0xe4, 0x8b, 0xce, 0xb5,
+    0x27, 0xae, 0x53, 0xed, 0xef, 0x37, 0xa6, 0x81, 0x8f, 0x70, 0x25, 0x18,
+    0x93, 0x06, 0x8c, 0x18, 0xcd, 0x7a, 0x1a, 0x8d, 0xfc, 0xde, 0x6f, 0x30,
+    0xdb, 0x41, 0xb6, 0x42, 0x14, 0x54, 0xf8, 0xcd, 0xc6, 0xf8, 0x0f, 0x82,
+    0x17, 0xfa, 0x8d, 0xba, 0x80, 0x81, 0x6a, 0xf7, 0x02, 0x97, 0x00, 0x78,
+    0xd6, 0x5b, 0xc9, 0xba, 0xd1, 0x99, 0xef, 0x8e, 0x48, 0x6c, 0x35, 0x10,
+    0x5b, 0xf1, 0x9b, 0x93, 0x4f, 0xbd, 0x7d, 0x27, 0x9e, 0xc7, 0x86, 0xb2,
+    0x8f, 0x6a, 0x91, 0x59, 0x2d, 0x14, 0xab, 0x1b, 0x34, 0x6e, 0xfa, 0x25,
+    0x5e, 0x14, 0xc7, 0xef, 0x3d, 0x0f, 0x13, 0xf9, 0x45, 0x4b, 0x90, 0xbc,
+    0xd8, 0x51, 0x42, 0x95, 0x25, 0x9b, 0x1b, 0x7c, 0xaf, 0x3b, 0x60, 0x21,
+    0x4c, 0x5f, 0x7c, 0x63, 0x4b, 0x45, 0xa6, 0xdc, 0xfd, 0x32, 0xf3, 0x06,
+    0x61, 0x11, 0x2d, 0x27, 0xde, 0x19, 0x38, 0x63, 0xf9, 0x70, 0xd1, 0x82,
+    0x8e, 0xc7, 0x99, 0xe1, 0x96, 0x9b, 0x54, 0x93, 0x64, 0x5f, 0xd1, 0x62,
+    0x9c, 0x37, 0x10, 0x1a, 0x8a, 0x82, 0x8d, 0x2a, 0x93, 0x95, 0x22, 0xc9,
+    0x21, 0xf5, 0xce, 0x21, 0xbb, 0x7c, 0x17, 0xee, 0x20, 0xa0, 0x73, 0xaa,
+    0x69, 0x78, 0x4e, 0x0d, 0x2c, 0x2c, 0x96, 0x23, 0xdc, 0x07, 0x16, 0xbd,
+    0xe7, 0xd5, 0x49, 0xcc, 0x44, 0xd1, 0x9d, 0xd7, 0xa3, 0x01, 0x60, 0xa0,
+    0xe0, 0x41, 0x63, 0x28, 0x8a, 0x43, 0xdb, 0x4f, 0x25, 0x5b, 0x27, 0x52,
+    0x4a, 0xee, 0x42, 0x43, 0x9a, 0xef, 0x33, 0x43, 0x70, 0xda, 0x64, 0x57,
+    0x49, 0x0c, 0x7f, 0xfd, 0xc7, 0x88, 0x26, 0x94, 0x10, 0xcc, 0x05, 0x1d,
+    0x54, 0x95, 0xea, 0x4e, 0x65, 0x28, 0x03, 0xbc, 0xa2, 0x62, 0xd2, 0xce,
+    0x60, 0x34, 0xf9, 0xdb, 0x26, 0xb5, 0xe6, 0x9b, 0x55, 0x2c, 0x8f, 0x30,
+    0x3a, 0x94, 0x9a, 0x15, 0x79, 0x22, 0x75, 0x4d, 0x1b, 0x91, 0xe0, 0x5b,
+    0xdb, 0xd1, 0x15, 0x7f, 0xcc, 0xc6, 0x88, 0xb5, 0x00, 0x3f, 0x5d, 0x84,
+    0x2e, 0x68, 0xde, 0x6f, 0x41, 0x5b, 0x4e, 0xe7, 0xdf, 0xe6, 0x3b, 0x7e,
+    0xf2, 0xdd, 0xfc, 0x01, 0xf2, 0x1b, 0x52, 0xba, 0xc4, 0x51, 0xae, 0x8f,
+    0xa0, 0x55, 0x12, 0x81, 0x57, 0xe0, 0x58, 0x5e, 0xea, 0xd7, 0x85, 0xfb,
+    0x19, 0x8b, 0xb7, 0x24, 0x29, 0x94, 0xa7, 0xfc, 0xed, 0x17, 0xaa, 0x32,
+    0x50, 0x11, 0xb3, 0x7a, 0x43, 0x3a, 0xc0, 0x2b, 0x82, 0x9c, 0x85, 0xd9,
+    0xd0, 0xdb, 0x21, 0x71, 0x83, 0xb4, 0x30, 0x14, 0xec, 0xfc, 0x8d, 0x32,
+    0xd6, 0xa2, 0x36, 0x5e, 0x3b, 0xe9, 0x12, 0x0c, 0x95, 0xd6, 0x0c, 0x0c,
+    0x31, 0x66, 0x30, 0x3f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x09, 0x14, 0x31, 0x32, 0x1e, 0x30, 0x00, 0x49, 0x00, 0x6e, 0x00,
+    0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00,
+    0x20, 0x00, 0x57, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x69, 0x00,
+    0x74, 0x00, 0x73, 0x00, 0x20, 0x00, 0x50, 0x00, 0x74, 0x00, 0x79, 0x00,
+    0x20, 0x00, 0x4c, 0x00, 0x74, 0x00, 0x64, 0x30, 0x23, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x16, 0x04, 0x14,
+    0x14, 0x74, 0x2d, 0x52, 0x8e, 0x0d, 0x0c, 0x06, 0x6c, 0x32, 0x64, 0xd3,
+    0x7e, 0x33, 0x31, 0x68, 0x8b, 0x28, 0x1a, 0x75, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x07, 0x06, 0xa0, 0x80, 0x30, 0x80, 0x02, 0x01, 0x00, 0x30, 0x80,
+    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30,
+    0x24, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01,
+    0x06, 0x30, 0x16, 0x04, 0x10, 0x9d, 0x1b, 0x68, 0x8e, 0x11, 0xc2, 0xb2,
+    0xd6, 0xd0, 0xe9, 0x5a, 0x9e, 0x96, 0xc1, 0x8c, 0xa6, 0x02, 0x02, 0x07,
+    0xd0, 0xa0, 0x80, 0x04, 0x82, 0x03, 0xf8, 0x1d, 0xce, 0x13, 0x70, 0x7a,
+    0x6b, 0x0a, 0x12, 0x2d, 0x01, 0x84, 0x63, 0x5c, 0x07, 0x82, 0x23, 0xf8,
+    0x8a, 0x5e, 0x53, 0x8f, 0xc8, 0xb4, 0x87, 0x1a, 0xa2, 0x98, 0xdb, 0xc6,
+    0x26, 0xca, 0xbb, 0x20, 0x24, 0xad, 0xac, 0xdf, 0xbe, 0x73, 0x6d, 0x97,
+    0x4b, 0x6e, 0x5b, 0x45, 0xd2, 0x84, 0xd4, 0xa4, 0x82, 0xd0, 0xce, 0x40,
+    0x13, 0x4c, 0x6d, 0x4d, 0x2e, 0xc1, 0x96, 0x95, 0x01, 0x64, 0xf3, 0xf0,
+    0x5f, 0x06, 0x06, 0xea, 0xf7, 0x84, 0x8f, 0xb3, 0xb0, 0x6e, 0x7c, 0x9b,
+    0x71, 0x73, 0xb9, 0xcd, 0xac, 0x72, 0xf6, 0xa0, 0x23, 0xda, 0x9b, 0x9f,
+    0xec, 0x16, 0xef, 0x33, 0xd4, 0xd0, 0x4d, 0x20, 0xf0, 0x75, 0xa9, 0x73,
+    0xf4, 0x31, 0xc7, 0x57, 0xb8, 0x0d, 0x9d, 0x85, 0x7c, 0xee, 0x3a, 0x24,
+    0x7b, 0x74, 0xa0, 0x5c, 0xad, 0xde, 0x5e, 0x05, 0x1e, 0xeb, 0x02, 0x78,
+    0x12, 0xb4, 0xb9, 0xc6, 0xe5, 0xc5, 0x99, 0xbc, 0x05, 0x62, 0x5b, 0x10,
+    0x52, 0x08, 0x00, 0x9e, 0x73, 0xac, 0xe4, 0x1d, 0xdb, 0xb8, 0xbf, 0x48,
+    0x03, 0x28, 0x05, 0x3c, 0x61, 0x1a, 0x8b, 0x4c, 0xd7, 0x5f, 0x8c, 0xb4,
+    0xcd, 0x91, 0x1c, 0x0b, 0xf4, 0x55, 0xd4, 0x1c, 0x42, 0x4a, 0xd4, 0xf5,
+    0x15, 0x38, 0xd9, 0x06, 0xfc, 0x49, 0xf6, 0xe5, 0xa7, 0x09, 0x5d, 0x01,
+    0xbd, 0xc3, 0xd1, 0x09, 0x9f, 0x5d, 0x0c, 0x19, 0x43, 0xd0, 0xfa, 0x25,
+    0x17, 0xad, 0x2a, 0xbf, 0x89, 0x63, 0x06, 0xa8, 0x02, 0x03, 0xe4, 0xfe,
+    0x19, 0x08, 0x70, 0xa1, 0x74, 0x74, 0xb6, 0xb6, 0x0f, 0x19, 0x4d, 0x54,
+    0xa5, 0xb2, 0xd7, 0x37, 0x3b, 0x17, 0xc0, 0x5d, 0xc2, 0x8a, 0xf1, 0xcc,
+    0xed, 0xef, 0x65, 0xc8, 0xca, 0xbe, 0x02, 0xd4, 0x9b, 0x1e, 0xef, 0xc9,
+    0xe0, 0x91, 0x82, 0xb0, 0xe0, 0x50, 0xc7, 0xa0, 0xcc, 0x01, 0x6d, 0x55,
+    0xe5, 0x67, 0x99, 0x65, 0x13, 0xe4, 0xd2, 0x90, 0x91, 0xf3, 0x76, 0x0b,
+    0x6a, 0x2d, 0x19, 0xaf, 0x61, 0xb3, 0x7f, 0x4c, 0x04, 0xfe, 0x68, 0xf6,
+    0xb3, 0x56, 0xd8, 0xf3, 0x34, 0xd7, 0x04, 0x0a, 0x31, 0xc8, 0x37, 0xdf,
+    0xac, 0xd8, 0x91, 0x80, 0x8a, 0x30, 0x12, 0x22, 0x80, 0xd7, 0x24, 0xcf,
+    0x70, 0xaf, 0x56, 0xaf, 0x81, 0xfe, 0x63, 0xf1, 0xea, 0x57, 0x4c, 0xf2,
+    0xdb, 0x30, 0x50, 0x92, 0xc1, 0xeb, 0x04, 0x9a, 0xdf, 0xf5, 0x74, 0x57,
+    0x5b, 0x58, 0xc2, 0x4e, 0x6b, 0x11, 0xf3, 0xe1, 0xb3, 0x0f, 0x56, 0x35,
+    0x04, 0xf8, 0x50, 0x1d, 0x7e, 0xe6, 0x99, 0xa2, 0x48, 0xdb, 0xea, 0x62,
+    0x4f, 0x98, 0xc2, 0xef, 0xbf, 0x7f, 0x94, 0xc0, 0x36, 0xc0, 0xf3, 0x27,
+    0xfe, 0xe2, 0x17, 0x1e, 0x91, 0x7d, 0x96, 0xa9, 0x2b, 0x71, 0x51, 0xc3,
+    0x59, 0x2d, 0x11, 0x50, 0x1e, 0xcb, 0xce, 0xff, 0x04, 0x4d, 0x16, 0xf5,
+    0xc2, 0xd4, 0x1f, 0xdd, 0x7f, 0x5a, 0xfd, 0x1d, 0xe9, 0x63, 0x52, 0x44,
+    0x76, 0x5f, 0x91, 0xfd, 0xe8, 0xdf, 0x0a, 0x69, 0x0d, 0xd3, 0x64, 0x91,
+    0xea, 0xdd, 0x03, 0x4f, 0x42, 0xa5, 0xe9, 0xa1, 0x70, 0x05, 0xf3, 0x22,
+    0x8e, 0xad, 0x70, 0x1a, 0x3e, 0x94, 0x42, 0x06, 0xe7, 0x47, 0x37, 0x3d,
+    0xf5, 0xda, 0x3e, 0x2a, 0x3a, 0xc0, 0x23, 0xd9, 0x4a, 0x26, 0x69, 0x13,
+    0xa6, 0x93, 0x7c, 0xf2, 0xaf, 0x04, 0x5e, 0x9b, 0x88, 0xc7, 0x77, 0xd0,
+    0x93, 0xab, 0x1b, 0xbd, 0x3d, 0x69, 0x90, 0xab, 0x41, 0xa9, 0xbc, 0x84,
+    0x18, 0x4d, 0x29, 0x02, 0xc1, 0xf8, 0xff, 0x63, 0x18, 0x24, 0x74, 0x8f,
+    0x7e, 0x44, 0x33, 0xaf, 0x88, 0x8b, 0x93, 0x5b, 0x9a, 0xae, 0x6b, 0x08,
+    0xa2, 0x82, 0x5d, 0xf3, 0xbe, 0x61, 0xc3, 0xf0, 0x2d, 0x31, 0x4c, 0xb5,
+    0xb5, 0x91, 0x0f, 0xfa, 0x81, 0x61, 0xad, 0xfc, 0xba, 0x91, 0xeb, 0x3b,
+    0x9d, 0x22, 0x41, 0x45, 0x0e, 0x8e, 0x24, 0xc7, 0x1c, 0x81, 0x95, 0xa8,
+    0x7b, 0x64, 0xed, 0xa5, 0xec, 0x5a, 0x68, 0x3c, 0x85, 0x8d, 0x92, 0xb7,
+    0x24, 0x0f, 0xed, 0xf5, 0xc6, 0x31, 0x61, 0xdc, 0xef, 0xa7, 0xcb, 0x8f,
+    0xda, 0x43, 0x05, 0x42, 0xf6, 0x9e, 0xbc, 0x1b, 0x9a, 0xa1, 0xe8, 0x1d,
+    0x8d, 0x42, 0xdb, 0x80, 0x83, 0x55, 0x52, 0x2b, 0x95, 0x00, 0x05, 0x82,
+    0x84, 0xc3, 0x54, 0x23, 0x8e, 0x1d, 0x00, 0xa2, 0x16, 0x3e, 0xce, 0x3d,
+    0xcc, 0x9e, 0xb8, 0x4c, 0x59, 0xb2, 0x12, 0xa2, 0x23, 0xc1, 0x46, 0x50,
+    0x86, 0xae, 0x75, 0x7e, 0x49, 0x38, 0x77, 0x94, 0xf0, 0x27, 0xd8, 0x17,
+    0x38, 0x8c, 0xe0, 0x73, 0x00, 0xfb, 0xaf, 0xbf, 0xe8, 0xed, 0x85, 0x58,
+    0x3e, 0xb4, 0x88, 0x04, 0xc8, 0x22, 0x1b, 0xb4, 0x75, 0xa2, 0xc4, 0xdd,
+    0x06, 0xd2, 0x83, 0x42, 0x21, 0x57, 0xfc, 0xd8, 0xae, 0x9c, 0x0e, 0xd8,
+    0x6a, 0x70, 0xd1, 0xeb, 0x44, 0x9c, 0xb7, 0x37, 0x04, 0x05, 0xf5, 0x17,
+    0xbe, 0xf3, 0x56, 0x1b, 0x06, 0x36, 0x1c, 0x59, 0x7b, 0x65, 0x8d, 0xbb,
+    0xbe, 0x22, 0x9a, 0x70, 0xa3, 0xe9, 0x60, 0x1a, 0xc9, 0xdd, 0x81, 0x3c,
+    0x2d, 0x4e, 0xc0, 0x8a, 0xe5, 0x91, 0xa7, 0xc1, 0x80, 0x07, 0x47, 0x7a,
+    0x74, 0x4f, 0x3e, 0x4a, 0xdc, 0xb2, 0xcc, 0xff, 0x37, 0x66, 0x05, 0xcb,
+    0xd6, 0xe9, 0x90, 0xf5, 0xef, 0x2b, 0x7e, 0xa7, 0x66, 0x51, 0xcb, 0x48,
+    0xb3, 0x8a, 0x6f, 0x06, 0xba, 0x8b, 0x3d, 0x35, 0x36, 0xdf, 0x0e, 0x40,
+    0xe5, 0xa1, 0xe3, 0xdd, 0x89, 0xab, 0x64, 0x9c, 0x01, 0x15, 0x9e, 0x93,
+    0xea, 0xf9, 0x4f, 0x9e, 0xf5, 0x8b, 0xf2, 0xc2, 0xbb, 0xe5, 0xc3, 0xa3,
+    0xe3, 0x13, 0x63, 0x4f, 0x7d, 0x20, 0xe4, 0x66, 0x96, 0x84, 0x8d, 0xd4,
+    0xca, 0x72, 0x52, 0xdc, 0xb8, 0x93, 0xd4, 0xa5, 0x3e, 0x6e, 0x42, 0x56,
+    0x80, 0x46, 0x77, 0x86, 0x49, 0xfe, 0xf3, 0xb4, 0x5b, 0x37, 0xfc, 0xb8,
+    0x0c, 0xd7, 0x63, 0xac, 0x3c, 0x6f, 0xf0, 0xbe, 0xbe, 0xb4, 0x13, 0xe7,
+    0x34, 0xe5, 0x06, 0xbf, 0x17, 0x48, 0x6e, 0xc0, 0x26, 0x94, 0xdd, 0xed,
+    0xf4, 0xda, 0x97, 0x25, 0xab, 0xd6, 0x9b, 0xc3, 0x8c, 0xeb, 0x17, 0x09,
+    0xfc, 0x03, 0x5a, 0x2f, 0x19, 0x85, 0x50, 0xc4, 0xe6, 0x35, 0x71, 0x94,
+    0xad, 0xc5, 0xcf, 0x08, 0xcf, 0x69, 0x3b, 0xc3, 0x31, 0xec, 0xf1, 0xfa,
+    0x80, 0x66, 0x8f, 0x14, 0xde, 0x56, 0x21, 0x12, 0x9b, 0x0c, 0xdf, 0x92,
+    0x48, 0x06, 0xce, 0xdb, 0xeb, 0x28, 0x54, 0x27, 0x8b, 0xa9, 0xef, 0x0c,
+    0xf4, 0xa0, 0xcc, 0x84, 0x59, 0x60, 0xed, 0x18, 0x65, 0xca, 0x67, 0x0c,
+    0xd1, 0x1f, 0xcf, 0x59, 0x4b, 0xce, 0x07, 0x27, 0x08, 0x6a, 0xea, 0x53,
+    0xdc, 0x47, 0xb3, 0x4e, 0xe4, 0x0b, 0xff, 0x9a, 0x7d, 0x6b, 0x0d, 0x2f,
+    0x2d, 0x60, 0xd7, 0x8b, 0x22, 0xf5, 0x30, 0x43, 0x09, 0xe6, 0xdf, 0x01,
+    0x03, 0x27, 0x2d, 0xb5, 0x74, 0x52, 0x5d, 0x08, 0xc7, 0x5a, 0x44, 0x25,
+    0x0f, 0x2c, 0x14, 0x8f, 0x48, 0xea, 0x18, 0x99, 0xd1, 0xcc, 0xc5, 0xdc,
+    0x65, 0xa5, 0x3d, 0x25, 0x94, 0xa9, 0xc7, 0xad, 0x3e, 0xa4, 0xf6, 0xe6,
+    0xbd, 0xa7, 0x70, 0xd4, 0xdc, 0x9b, 0x26, 0xcb, 0x31, 0x70, 0xaf, 0x3e,
+    0xa4, 0xb6, 0x8d, 0x21, 0x31, 0x67, 0x35, 0x35, 0x86, 0x67, 0xd1, 0x02,
+    0x6c, 0x36, 0x76, 0xc9, 0x20, 0xf6, 0x0f, 0x30, 0x41, 0x83, 0x19, 0xf5,
+    0xe1, 0x33, 0x90, 0xbc, 0x7b, 0x8c, 0x9b, 0x8a, 0x68, 0x30, 0x9e, 0xed,
+    0xf4, 0x88, 0xc9, 0x04, 0x08, 0x2b, 0xb0, 0x0f, 0xae, 0xc7, 0xe0, 0x6e,
+    0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39, 0x30, 0x21, 0x30,
+    0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
+    0xe0, 0xf7, 0xa1, 0x1b, 0xf6, 0x3f, 0x05, 0xad, 0x55, 0x6a, 0x20, 0x4c,
+    0x71, 0xca, 0x62, 0x47, 0x13, 0x28, 0xd5, 0x05, 0x04, 0x10, 0x3e, 0x87,
+    0x2d, 0x96, 0xea, 0x80, 0x4b, 0xab, 0x3a, 0xb9, 0xee, 0x09, 0x65, 0x28,
+    0xbc, 0x8d, 0x02, 0x02, 0x07, 0xd0, 0x00, 0x00,
+};
+
+/* kWindows is a dummy key and certificate exported from the certificate
+ * manager on Windows 7. */
+static const uint8_t kWindows[] = {
+    0x30, 0x82, 0x0a, 0x02, 0x02, 0x01, 0x03, 0x30, 0x82, 0x09, 0xbe, 0x06,
+    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,
+    0x09, 0xaf, 0x04, 0x82, 0x09, 0xab, 0x30, 0x82, 0x09, 0xa7, 0x30, 0x82,
+    0x06, 0x08, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
+    0x01, 0xa0, 0x82, 0x05, 0xf9, 0x04, 0x82, 0x05, 0xf5, 0x30, 0x82, 0x05,
+    0xf1, 0x30, 0x82, 0x05, 0xed, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02, 0xa0, 0x82, 0x04, 0xfe, 0x30, 0x82,
+    0x04, 0xfa, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x0c, 0x01, 0x03, 0x30, 0x0e, 0x04, 0x08, 0xb7, 0x20, 0x55, 0x5a,
+    0x4d, 0x3f, 0x0e, 0x89, 0x02, 0x02, 0x07, 0xd0, 0x04, 0x82, 0x04, 0xd8,
+    0x3a, 0xcc, 0xd6, 0xcb, 0x4d, 0x54, 0xc0, 0x04, 0x56, 0x10, 0xcc, 0x49,
+    0xe4, 0xe0, 0x10, 0x73, 0xfb, 0x1a, 0xdd, 0x1d, 0x4f, 0x6e, 0x55, 0xe3,
+    0xa4, 0xab, 0xf9, 0x26, 0xaa, 0x42, 0x54, 0xa0, 0xd1, 0xf0, 0x8d, 0xbf,
+    0x71, 0x7d, 0x18, 0x00, 0x17, 0xb3, 0xb7, 0x63, 0x50, 0x8d, 0x2c, 0xeb,
+    0x2f, 0xe3, 0xc3, 0xbf, 0x93, 0xc8, 0x46, 0x48, 0x99, 0x47, 0xe2, 0x3b,
+    0x8d, 0x71, 0x01, 0x5f, 0x59, 0x5b, 0x61, 0x7e, 0x1f, 0x0c, 0x6e, 0x3e,
+    0xc4, 0x74, 0x99, 0x98, 0x30, 0xff, 0x37, 0x7b, 0x30, 0x19, 0xb5, 0xfc,
+    0x69, 0x94, 0x5f, 0x79, 0x69, 0x34, 0xda, 0xb5, 0x21, 0xcf, 0xfe, 0x72,
+    0x87, 0xe8, 0x7d, 0x29, 0x7e, 0x27, 0x25, 0x90, 0x80, 0x98, 0xdd, 0x8d,
+    0xbf, 0x42, 0xb0, 0x10, 0xd8, 0x7d, 0x6d, 0xfe, 0x6f, 0x0d, 0x61, 0x09,
+    0xfd, 0xb2, 0x9b, 0xeb, 0xbf, 0x1c, 0xca, 0x33, 0xbc, 0x4e, 0x19, 0x52,
+    0x55, 0x53, 0xb4, 0xa5, 0x98, 0x6c, 0xa3, 0x3b, 0xf8, 0xa4, 0x8d, 0x79,
+    0xcf, 0x40, 0xf2, 0x89, 0x09, 0x3c, 0x38, 0xab, 0xae, 0xf4, 0x09, 0x3b,
+    0xb6, 0xcb, 0xdd, 0xd7, 0xad, 0xe0, 0x5a, 0x71, 0x64, 0xc9, 0x0f, 0x18,
+    0xac, 0x3c, 0x12, 0xd4, 0x22, 0x54, 0x24, 0x1a, 0xa5, 0x35, 0x78, 0x99,
+    0x09, 0x4a, 0x18, 0x95, 0x23, 0xb9, 0xf7, 0x89, 0x3f, 0x13, 0x43, 0x1f,
+    0x8d, 0x76, 0x6b, 0x04, 0xdb, 0x64, 0xf4, 0x8e, 0xf5, 0x50, 0xa0, 0xae,
+    0x1c, 0x8c, 0xc8, 0xf3, 0xde, 0xf3, 0x11, 0x2d, 0xfe, 0x76, 0xf0, 0xac,
+    0x46, 0x54, 0x23, 0x03, 0x49, 0xfa, 0x73, 0xcd, 0xe0, 0xa1, 0x6c, 0x66,
+    0x4d, 0x1b, 0x99, 0x57, 0x3d, 0x61, 0x61, 0xeb, 0x61, 0x40, 0xc7, 0xd6,
+    0x41, 0xbe, 0x63, 0x21, 0x1e, 0x7e, 0xb5, 0x0e, 0x94, 0x93, 0x37, 0x41,
+    0xe8, 0x91, 0x06, 0xd7, 0xa3, 0x33, 0x78, 0x17, 0x17, 0x59, 0x78, 0x8f,
+    0xaf, 0xed, 0xf9, 0x90, 0xfb, 0xb6, 0xc8, 0xa9, 0x0b, 0x10, 0x1a, 0xf1,
+    0xab, 0x10, 0x11, 0xbc, 0x7f, 0xa5, 0x2d, 0x34, 0x7d, 0x7b, 0xaf, 0xc8,
+    0xb2, 0x00, 0x6b, 0xd4, 0xbb, 0x25, 0x9b, 0xc7, 0x14, 0x8b, 0x50, 0x0a,
+    0xd5, 0x2c, 0x1f, 0xa0, 0x5f, 0x07, 0x1d, 0x5e, 0x1a, 0xa4, 0x4b, 0x85,
+    0xb2, 0xa6, 0xe2, 0xdd, 0xb7, 0xda, 0x11, 0x25, 0x51, 0xbf, 0x72, 0x50,
+    0x53, 0xa1, 0x3d, 0xfa, 0x1d, 0x34, 0x75, 0xdd, 0x7a, 0xe0, 0x90, 0x56,
+    0x14, 0xc3, 0xe8, 0x0b, 0xea, 0x32, 0x5f, 0x92, 0xfc, 0x2e, 0x4d, 0x0e,
+    0xfe, 0xba, 0x1a, 0x00, 0x6d, 0x8f, 0x75, 0xac, 0x49, 0x4c, 0x79, 0x03,
+    0x2e, 0xf2, 0xcc, 0x8e, 0x96, 0x27, 0x3c, 0x59, 0x28, 0x7f, 0x52, 0x8d,
+    0xc3, 0x3b, 0x24, 0x68, 0xff, 0xbb, 0xd0, 0x4e, 0xdf, 0xc4, 0x91, 0x32,
+    0x14, 0x5e, 0x43, 0x73, 0xd8, 0x56, 0x65, 0xe1, 0x48, 0x89, 0xe4, 0x33,
+    0xef, 0x4b, 0x51, 0x50, 0xf2, 0x53, 0xe7, 0xae, 0x7d, 0xb6, 0x8c, 0x80,
+    0xee, 0x8d, 0x9e, 0x24, 0x1a, 0xdd, 0x95, 0x7d, 0x22, 0x58, 0x76, 0xf8,
+    0xbb, 0x63, 0x36, 0x17, 0xdc, 0xc6, 0x3e, 0xb8, 0xe9, 0x1f, 0xd8, 0xe0,
+    0x06, 0x18, 0x1b, 0x3c, 0x45, 0xcb, 0xe1, 0x5a, 0x41, 0xe5, 0x32, 0xa3,
+    0x85, 0x1b, 0xff, 0xe0, 0x5e, 0x28, 0xee, 0xe9, 0x05, 0xc7, 0xc8, 0x47,
+    0x85, 0xe8, 0x13, 0x7f, 0x1b, 0xda, 0xd7, 0x3e, 0x8e, 0xb8, 0xa3, 0x96,
+    0x34, 0x19, 0x3b, 0x0c, 0x88, 0x26, 0x38, 0xe7, 0x65, 0xf6, 0x03, 0x4f,
+    0xc8, 0x37, 0x6e, 0x2f, 0x5e, 0x5d, 0xcd, 0xa3, 0x29, 0x37, 0xe8, 0x86,
+    0x84, 0x66, 0x37, 0x84, 0xa0, 0x49, 0x4e, 0x8f, 0x3b, 0x1a, 0x42, 0x9f,
+    0x62, 0x1f, 0x2b, 0x97, 0xc9, 0x18, 0x21, 0xd2, 0xa5, 0xcd, 0x8f, 0xa4,
+    0x03, 0xf8, 0x82, 0x1e, 0xb8, 0x3e, 0x6b, 0x54, 0x29, 0x75, 0x5f, 0x80,
+    0xe6, 0x8f, 0x2f, 0x65, 0xb0, 0x6b, 0xbb, 0x18, 0x6e, 0x0d, 0x32, 0x62,
+    0x8c, 0x97, 0x48, 0xd3, 0xaa, 0xf2, 0x5e, 0xb8, 0x25, 0xbc, 0xb5, 0x22,
+    0x4a, 0xac, 0xcf, 0xdc, 0x8b, 0x48, 0xfc, 0x95, 0xf2, 0x17, 0x21, 0x1e,
+    0xda, 0x13, 0xd3, 0x1b, 0xe2, 0x37, 0xd5, 0xbf, 0x92, 0xe4, 0x81, 0xf5,
+    0x98, 0x57, 0x51, 0x14, 0xda, 0x80, 0x7d, 0x4a, 0x6a, 0xce, 0x17, 0xaf,
+    0xdb, 0xc3, 0x2e, 0x84, 0x3b, 0x1e, 0x02, 0x51, 0x4a, 0xc1, 0x25, 0x8c,
+    0x5a, 0x20, 0x56, 0xee, 0xec, 0x59, 0xcf, 0xd7, 0x3e, 0x5f, 0x39, 0x9f,
+    0xbf, 0x4d, 0x4e, 0x94, 0xb1, 0x1d, 0x83, 0x70, 0xc0, 0xab, 0xff, 0xfa,
+    0x7c, 0x2e, 0x5b, 0xfb, 0x57, 0x3f, 0x60, 0xb8, 0xf3, 0x36, 0x5f, 0xbf,
+    0x6a, 0x8c, 0x6f, 0xe0, 0x34, 0xe8, 0x75, 0x26, 0xc2, 0x1e, 0x22, 0x64,
+    0x0e, 0x43, 0xc1, 0x93, 0xe6, 0x8a, 0x2e, 0xe9, 0xd9, 0xe0, 0x9f, 0x56,
+    0x50, 0x8a, 0xbd, 0x68, 0xf6, 0x57, 0x63, 0x55, 0xbb, 0xe7, 0xfe, 0x22,
+    0xca, 0xdc, 0x85, 0x38, 0x39, 0xc8, 0x66, 0x02, 0x28, 0x0f, 0xe0, 0x1c,
+    0xd6, 0x0f, 0x5d, 0x6a, 0x0b, 0xd8, 0xe5, 0x6a, 0xeb, 0x54, 0xb2, 0xe0,
+    0x02, 0x6f, 0xe2, 0x42, 0x89, 0x66, 0xc2, 0xd5, 0xc6, 0xe2, 0xb2, 0x04,
+    0x6d, 0x8a, 0x2b, 0x48, 0xc2, 0x51, 0x07, 0x8e, 0xf3, 0x91, 0x0b, 0xb7,
+    0x55, 0x6e, 0xbb, 0xbf, 0x11, 0x5a, 0xcb, 0x2c, 0xb3, 0x1e, 0x61, 0xd3,
+    0xdb, 0x90, 0xad, 0xba, 0x10, 0x96, 0xe2, 0x16, 0xf4, 0x0c, 0x47, 0xbd,
+    0x64, 0x66, 0x7a, 0x17, 0x63, 0xb9, 0x02, 0xcb, 0x53, 0x7a, 0x35, 0x92,
+    0x74, 0xc3, 0x2a, 0x7d, 0xc5, 0x11, 0x18, 0x2f, 0xa3, 0x62, 0x2c, 0xc0,
+    0x87, 0xd3, 0xd3, 0xba, 0xcb, 0xe0, 0x86, 0x9b, 0x4b, 0xc5, 0x59, 0x98,
+    0x7e, 0x32, 0x96, 0x55, 0xc1, 0x3d, 0x5a, 0xcd, 0x90, 0x2d, 0xf8, 0xb7,
+    0xa8, 0xba, 0xce, 0x89, 0x64, 0xa6, 0xf3, 0x1b, 0x11, 0x2e, 0x12, 0x99,
+    0x4d, 0x34, 0x45, 0x13, 0x66, 0xb7, 0x69, 0x7b, 0xc5, 0x79, 0xf5, 0x6b,
+    0xc2, 0x1d, 0xc8, 0x3f, 0x09, 0x18, 0x0a, 0xfc, 0xf7, 0xaf, 0x98, 0xc2,
+    0xc7, 0xcc, 0x85, 0x29, 0xc6, 0x22, 0x7a, 0x77, 0xab, 0xb5, 0xac, 0xf7,
+    0x9e, 0x70, 0x8e, 0x7f, 0x3c, 0xf1, 0xbd, 0xd9, 0x7a, 0x92, 0x84, 0xc5,
+    0xb8, 0x56, 0xc3, 0xcb, 0xf7, 0x25, 0xad, 0xda, 0x0e, 0x1c, 0xe4, 0x68,
+    0x66, 0x83, 0x91, 0x78, 0xf1, 0xe7, 0x8c, 0xaa, 0x45, 0xb6, 0x85, 0x74,
+    0x9b, 0x08, 0xff, 0xac, 0x38, 0x55, 0xa5, 0x6a, 0xea, 0x2e, 0x75, 0x71,
+    0xd3, 0xa2, 0xdc, 0x1c, 0xc0, 0xc7, 0x0b, 0xa9, 0xd5, 0x7e, 0xf9, 0x63,
+    0x82, 0x87, 0xb7, 0x81, 0x01, 0xb9, 0x31, 0xdf, 0x41, 0x35, 0x0e, 0xe2,
+    0x1f, 0x48, 0xbf, 0x60, 0xce, 0xb0, 0xb4, 0x38, 0xa5, 0xb4, 0x76, 0xa3,
+    0x80, 0x1f, 0x93, 0x57, 0xf2, 0x05, 0x81, 0x42, 0xd1, 0xae, 0x56, 0x6d,
+    0xc5, 0x4c, 0xab, 0xa6, 0x24, 0x2a, 0x02, 0x3b, 0xb1, 0xc4, 0x75, 0xcf,
+    0x15, 0x90, 0xb5, 0xf2, 0xe7, 0x10, 0x69, 0xa0, 0xe3, 0xc4, 0xe6, 0x52,
+    0x63, 0x14, 0xb4, 0x15, 0x91, 0x8e, 0xba, 0x7a, 0xad, 0x2d, 0x9b, 0x24,
+    0x74, 0x36, 0x31, 0xca, 0xcb, 0x4b, 0x5a, 0xbf, 0xd3, 0x4e, 0xb4, 0xc1,
+    0x48, 0x44, 0x74, 0x2f, 0x83, 0xe4, 0x39, 0x3d, 0x90, 0x2d, 0x32, 0x12,
+    0xf7, 0xfa, 0xd3, 0xe3, 0xdb, 0x4f, 0xe6, 0xe7, 0x20, 0x2c, 0x57, 0xc0,
+    0xf9, 0x80, 0xe1, 0xdc, 0x1c, 0xf2, 0x05, 0x54, 0x35, 0xf6, 0xbd, 0xfb,
+    0xbd, 0xc5, 0xb2, 0x82, 0x32, 0x63, 0x32, 0xca, 0xf4, 0xf7, 0x14, 0x92,
+    0x87, 0x8a, 0x45, 0x37, 0x56, 0x93, 0xda, 0x4f, 0x04, 0x59, 0x03, 0x24,
+    0x93, 0x1a, 0x0b, 0x4e, 0xdb, 0x58, 0xbf, 0xda, 0x2a, 0x0e, 0x7e, 0x98,
+    0x6c, 0x0c, 0xeb, 0x21, 0xf9, 0xbf, 0x9b, 0x1f, 0xc0, 0xef, 0xd3, 0xea,
+    0xcb, 0x99, 0x5e, 0x14, 0x3e, 0x10, 0xfa, 0xad, 0x38, 0xf7, 0x68, 0x9f,
+    0xa3, 0xcc, 0xdf, 0xe5, 0x31, 0x91, 0x98, 0xde, 0x74, 0x5f, 0x7b, 0xce,
+    0xe4, 0x54, 0xd9, 0x51, 0xec, 0xf5, 0x4b, 0x17, 0x5f, 0x99, 0x4c, 0xf8,
+    0x00, 0xe0, 0x10, 0x09, 0x07, 0x64, 0xae, 0x61, 0x3b, 0x60, 0xa3, 0x89,
+    0x38, 0xc4, 0x80, 0xf2, 0x1e, 0x11, 0x26, 0x78, 0x72, 0x05, 0x97, 0x27,
+    0xba, 0x83, 0x33, 0x1b, 0x14, 0x4b, 0xc0, 0xc8, 0xb0, 0xcc, 0x0a, 0x9b,
+    0x3e, 0x4c, 0xde, 0x12, 0x07, 0x11, 0xd5, 0xf0, 0xc0, 0xdd, 0x70, 0x3d,
+    0xd8, 0x7a, 0xf7, 0xa2, 0xf2, 0x70, 0xad, 0x54, 0xce, 0x67, 0x41, 0x12,
+    0x29, 0x1f, 0xe1, 0x49, 0x5f, 0x4c, 0x77, 0x41, 0x7c, 0x74, 0x25, 0x9c,
+    0x91, 0xd1, 0x0d, 0xa5, 0x9a, 0xb8, 0x56, 0x4c, 0x01, 0xc0, 0x77, 0x51,
+    0x14, 0xc8, 0x92, 0x40, 0x9a, 0xbd, 0x7f, 0x3b, 0x9b, 0x17, 0xbb, 0x80,
+    0x6e, 0x50, 0x64, 0x31, 0xed, 0xe2, 0x22, 0x9f, 0x96, 0x8e, 0xe2, 0x4e,
+    0x54, 0x6e, 0x36, 0x35, 0xfc, 0xf2, 0xed, 0xfc, 0x56, 0x63, 0xdb, 0x89,
+    0x19, 0x99, 0xf8, 0x47, 0xff, 0xce, 0x35, 0xd2, 0x86, 0x63, 0xbc, 0xe4,
+    0x8c, 0x5d, 0x12, 0x94, 0x31, 0x81, 0xdb, 0x30, 0x13, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x15, 0x31, 0x06, 0x04, 0x04,
+    0x01, 0x00, 0x00, 0x00, 0x30, 0x57, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+    0xf7, 0x0d, 0x01, 0x09, 0x14, 0x31, 0x4a, 0x1e, 0x48, 0x00, 0x65, 0x00,
+    0x65, 0x00, 0x36, 0x00, 0x64, 0x00, 0x38, 0x00, 0x38, 0x00, 0x30, 0x00,
+    0x35, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x36, 0x00, 0x64, 0x00, 0x39, 0x00,
+    0x2d, 0x00, 0x34, 0x00, 0x32, 0x00, 0x65, 0x00, 0x32, 0x00, 0x2d, 0x00,
+    0x38, 0x00, 0x62, 0x00, 0x36, 0x00, 0x38, 0x00, 0x2d, 0x00, 0x66, 0x00,
+    0x65, 0x00, 0x61, 0x00, 0x62, 0x00, 0x35, 0x00, 0x65, 0x00, 0x66, 0x00,
+    0x32, 0x00, 0x38, 0x00, 0x32, 0x00, 0x37, 0x00, 0x30, 0x30, 0x6b, 0x06,
+    0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x11, 0x01, 0x31, 0x5e,
+    0x1e, 0x5c, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f,
+    0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x20, 0x00, 0x45,
+    0x00, 0x6e, 0x00, 0x68, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65,
+    0x00, 0x64, 0x00, 0x20, 0x00, 0x43, 0x00, 0x72, 0x00, 0x79, 0x00, 0x70,
+    0x00, 0x74, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x72, 0x00, 0x61, 0x00, 0x70,
+    0x00, 0x68, 0x00, 0x69, 0x00, 0x63, 0x00, 0x20, 0x00, 0x50, 0x00, 0x72,
+    0x00, 0x6f, 0x00, 0x76, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65, 0x00, 0x72,
+    0x00, 0x20, 0x00, 0x76, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x30, 0x30, 0x82,
+    0x03, 0x97, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
+    0x06, 0xa0, 0x82, 0x03, 0x88, 0x30, 0x82, 0x03, 0x84, 0x02, 0x01, 0x00,
+    0x30, 0x82, 0x03, 0x7d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+    0x0d, 0x01, 0x0c, 0x01, 0x06, 0x30, 0x0e, 0x04, 0x08, 0x92, 0x16, 0x6d,
+    0x6d, 0x68, 0xd3, 0xb0, 0xc1, 0x02, 0x02, 0x07, 0xd0, 0x80, 0x82, 0x03,
+    0x50, 0xee, 0x76, 0xe8, 0x60, 0xbf, 0xca, 0x3c, 0x2d, 0xe5, 0x29, 0x22,
+    0xf6, 0x33, 0xc3, 0x50, 0x6a, 0xdb, 0xf3, 0x58, 0x3c, 0xd9, 0x7c, 0xd8,
+    0xf9, 0x83, 0x89, 0x17, 0xa8, 0x1b, 0x6b, 0x09, 0xc1, 0x99, 0x49, 0xb0,
+    0x43, 0x06, 0xc6, 0x42, 0x4b, 0x7c, 0x85, 0x4b, 0xe6, 0x69, 0x38, 0x91,
+    0xce, 0x3d, 0x3c, 0x97, 0xd5, 0x14, 0x4f, 0x15, 0x5a, 0x81, 0x4d, 0x77,
+    0x40, 0xe0, 0xe1, 0x1c, 0x69, 0x3f, 0x1d, 0x65, 0x68, 0xb3, 0x98, 0x95,
+    0x30, 0x6c, 0xb0, 0x70, 0x93, 0x0c, 0xce, 0xec, 0xaf, 0x57, 0xc6, 0x9c,
+    0x34, 0xb4, 0x2b, 0xaf, 0xc3, 0x5e, 0x70, 0x87, 0x17, 0xe8, 0xc9, 0x54,
+    0x06, 0xb5, 0xb7, 0x83, 0xff, 0x46, 0x2b, 0xb6, 0x6a, 0x66, 0x2f, 0x6d,
+    0x0f, 0x96, 0x53, 0x66, 0x65, 0xb8, 0x7b, 0x48, 0x55, 0x83, 0xd3, 0xc4,
+    0x16, 0x93, 0xde, 0x72, 0x59, 0xf1, 0x9a, 0xab, 0xd5, 0xd5, 0xcb, 0x24,
+    0xa6, 0x4a, 0x4e, 0x57, 0xf3, 0x6e, 0xca, 0xb1, 0xeb, 0x7d, 0xdb, 0x02,
+    0xd2, 0x79, 0x89, 0xef, 0xa2, 0x8b, 0xee, 0x6f, 0xdc, 0x5e, 0x65, 0xa5,
+    0x09, 0x33, 0x51, 0xb5, 0x21, 0xc8, 0xc6, 0xab, 0xed, 0xd5, 0x50, 0x93,
+    0x39, 0x71, 0x97, 0xd3, 0x2c, 0xdd, 0xaf, 0xb1, 0xc6, 0x9b, 0x4b, 0x69,
+    0x98, 0xae, 0xaf, 0x21, 0xa0, 0x8a, 0x90, 0x25, 0xe0, 0xf4, 0x8c, 0xf2,
+    0xc3, 0x4f, 0x64, 0xb6, 0xc6, 0x64, 0x90, 0xff, 0x95, 0x0a, 0xcc, 0x8c,
+    0xf4, 0x86, 0x80, 0x53, 0x8d, 0x51, 0x0b, 0xcd, 0x45, 0x4f, 0xcf, 0x7c,
+    0xc6, 0xdf, 0x08, 0x5e, 0xa7, 0xdf, 0x4f, 0xcf, 0x84, 0xde, 0xb8, 0x4d,
+    0x73, 0x40, 0x06, 0xbe, 0x33, 0x82, 0xe8, 0x41, 0x1b, 0x9a, 0xc3, 0x5b,
+    0xb6, 0xf3, 0xfc, 0x32, 0x98, 0xcc, 0xcc, 0x5e, 0xd5, 0xb7, 0x86, 0x0f,
+    0xc8, 0x59, 0x72, 0xcb, 0x9a, 0xc5, 0x3c, 0x50, 0xb8, 0x25, 0xb8, 0x87,
+    0x3e, 0x49, 0xd4, 0x2d, 0x2f, 0x50, 0x35, 0xeb, 0xb8, 0x10, 0xa7, 0xea,
+    0xb1, 0xe2, 0x0c, 0x6a, 0x84, 0x2c, 0xe2, 0x7a, 0x26, 0xef, 0x7e, 0x6b,
+    0x1e, 0x47, 0x6e, 0x98, 0xc0, 0x3f, 0x92, 0x24, 0xe7, 0x88, 0xf9, 0x18,
+    0x78, 0x37, 0x8a, 0x54, 0xa6, 0x2b, 0x5b, 0xf0, 0xc7, 0xe2, 0x98, 0xa4,
+    0xa6, 0x2e, 0xc3, 0x6a, 0x75, 0x66, 0x51, 0xe8, 0x0d, 0x90, 0xfd, 0xa7,
+    0xec, 0x22, 0xb3, 0x7d, 0x9d, 0x0c, 0xfe, 0x72, 0x7f, 0x98, 0xf6, 0x86,
+    0x30, 0xd3, 0x7c, 0xee, 0xa5, 0xc5, 0x20, 0x89, 0x79, 0x04, 0x8e, 0xa8,
+    0xb6, 0x94, 0x70, 0x4e, 0x75, 0xe5, 0xa0, 0xae, 0x8c, 0x7f, 0x72, 0x4c,
+    0xd5, 0x9f, 0xd2, 0x56, 0x0d, 0xb2, 0x28, 0x45, 0x99, 0xf8, 0x40, 0xd4,
+    0x3f, 0x42, 0x4a, 0x0c, 0x92, 0x23, 0xe1, 0x17, 0xaf, 0x68, 0xa6, 0x0f,
+    0x1d, 0x32, 0x0d, 0xf8, 0x08, 0x8e, 0xdc, 0x79, 0x68, 0xf0, 0xfe, 0x0b,
+    0xda, 0x94, 0x2d, 0xa6, 0xa7, 0x76, 0x7e, 0xd6, 0xca, 0xec, 0x7c, 0x37,
+    0x52, 0x4f, 0x77, 0xcf, 0xa3, 0xcf, 0x8a, 0xfe, 0x89, 0xd9, 0x3e, 0xbc,
+    0xb5, 0x06, 0xa0, 0x21, 0x91, 0x89, 0x77, 0x84, 0x85, 0x43, 0x2a, 0x65,
+    0xec, 0x75, 0x4d, 0x0d, 0x1c, 0x79, 0x0f, 0x61, 0xca, 0x3e, 0x62, 0xbb,
+    0x41, 0xf9, 0x4c, 0x5c, 0x3b, 0xde, 0x33, 0x8e, 0xdf, 0x51, 0x72, 0x93,
+    0xca, 0xa6, 0xc7, 0x16, 0xe5, 0xb3, 0x22, 0xb6, 0x2e, 0xbf, 0xae, 0x1d,
+    0x91, 0x1d, 0x49, 0x96, 0xa3, 0x25, 0xd4, 0xce, 0x6f, 0xf0, 0xfb, 0xb7,
+    0xf5, 0x4a, 0x24, 0x03, 0x54, 0x4b, 0x7f, 0x0b, 0xb4, 0x31, 0xb4, 0x33,
+    0xb7, 0x40, 0xf0, 0xd5, 0x4c, 0xee, 0xe3, 0x4b, 0x12, 0x8c, 0xc9, 0xa7,
+    0x06, 0xb1, 0x02, 0x5a, 0x14, 0x6f, 0xe2, 0x3b, 0x68, 0x9b, 0x3d, 0xfc,
+    0x83, 0x4a, 0xcc, 0xb5, 0x77, 0xe7, 0xf0, 0x1b, 0x52, 0xce, 0x60, 0x89,
+    0xe2, 0x45, 0x76, 0xaa, 0x76, 0x70, 0xc2, 0xfd, 0x21, 0x8f, 0x1d, 0x67,
+    0x1a, 0x4c, 0xe8, 0x81, 0x2b, 0x2e, 0xa9, 0x56, 0x0a, 0x27, 0x0f, 0x81,
+    0xba, 0x5c, 0x4f, 0xfa, 0x6e, 0x7e, 0x33, 0x7d, 0x78, 0xed, 0xd2, 0xe3,
+    0x24, 0xae, 0x24, 0xb2, 0x1b, 0x62, 0x71, 0x0e, 0x73, 0xfe, 0x8a, 0x3b,
+    0x98, 0x0d, 0x82, 0x8e, 0x8d, 0x0f, 0xb3, 0xe2, 0x65, 0x87, 0xeb, 0x36,
+    0x91, 0x4d, 0x8a, 0xfb, 0x22, 0x7a, 0x23, 0x2c, 0xe1, 0xb6, 0x94, 0xb6,
+    0x90, 0x94, 0xcc, 0x0c, 0x7d, 0x02, 0x36, 0x56, 0xda, 0x45, 0x20, 0x90,
+    0x48, 0xdb, 0xa4, 0xf5, 0x27, 0xac, 0x22, 0x49, 0x25, 0xaa, 0xd8, 0xa7,
+    0x79, 0x38, 0x80, 0xc0, 0x95, 0xc7, 0xd1, 0x5c, 0x17, 0x7c, 0xa7, 0xec,
+    0xd2, 0x63, 0xc6, 0xc6, 0x55, 0xfe, 0x78, 0x99, 0x06, 0x2c, 0x6e, 0x4f,
+    0xfe, 0xd1, 0x5b, 0x8c, 0x2f, 0xa1, 0x42, 0x03, 0x26, 0x5a, 0x5e, 0xda,
+    0xef, 0x43, 0xd2, 0x0e, 0xf9, 0x5f, 0xdb, 0x1d, 0x9c, 0xd1, 0xcb, 0x65,
+    0x84, 0x26, 0xed, 0x91, 0x8f, 0x16, 0xb4, 0x1c, 0xc0, 0xb3, 0x8d, 0x79,
+    0xae, 0x9b, 0xcb, 0x36, 0x6d, 0xcd, 0x67, 0x1f, 0x87, 0x11, 0x2a, 0x7c,
+    0xb1, 0x8c, 0xfb, 0x06, 0xab, 0xd2, 0xd6, 0x2a, 0xe3, 0x45, 0x6c, 0xa5,
+    0xc0, 0x19, 0x6b, 0xfc, 0xc3, 0xb7, 0x54, 0x35, 0xda, 0xdf, 0x12, 0x97,
+    0x5c, 0xac, 0x59, 0xb4, 0x42, 0x25, 0xef, 0x04, 0xf7, 0x4c, 0xdb, 0x74,
+    0xb9, 0x68, 0x8f, 0xee, 0x37, 0x0a, 0xc6, 0x21, 0x86, 0x0f, 0x6f, 0x8e,
+    0xab, 0xd5, 0x7b, 0x38, 0x5e, 0x5f, 0x7d, 0xb9, 0x5a, 0xcb, 0xce, 0xa0,
+    0x56, 0x37, 0x13, 0x71, 0x4b, 0xba, 0x43, 0x7c, 0xc0, 0xb7, 0x7f, 0x32,
+    0xd7, 0x46, 0x27, 0x58, 0xfc, 0xdb, 0xb5, 0x64, 0x20, 0x3b, 0x20, 0x85,
+    0x79, 0xa8, 0x9a, 0x22, 0xaf, 0x29, 0x86, 0xc5, 0x9d, 0x23, 0x96, 0x52,
+    0xca, 0xc7, 0x9d, 0x92, 0x26, 0xe5, 0x3a, 0x60, 0xd6, 0xad, 0x8d, 0x5a,
+    0xd9, 0x29, 0xbe, 0xd5, 0x5c, 0x3a, 0x77, 0xda, 0x34, 0xe2, 0x76, 0xcb,
+    0x98, 0xa4, 0xf3, 0x33, 0xf1, 0x68, 0x20, 0x83, 0x95, 0x0b, 0x8d, 0x93,
+    0x59, 0x02, 0x0c, 0x8f, 0xe4, 0xc4, 0xb0, 0xe7, 0x61, 0x0d, 0xf9, 0x80,
+    0x20, 0x58, 0x40, 0xea, 0xb7, 0x0b, 0x1b, 0xad, 0xe3, 0x30, 0x3b, 0x30,
+    0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14,
+    0x2d, 0x77, 0x79, 0x79, 0x90, 0x41, 0x75, 0xf4, 0x4a, 0x7f, 0xf7, 0x15,
+    0x94, 0x28, 0x62, 0xf7, 0x69, 0xd4, 0x44, 0x27, 0x04, 0x14, 0x2b, 0x2f,
+    0xd9, 0x24, 0xc3, 0x8a, 0x34, 0xbb, 0x52, 0x52, 0x7b, 0xf6, 0x0e, 0x7b,
+    0xfe, 0x3a, 0x66, 0x47, 0x40, 0x49, 0x02, 0x02, 0x07, 0xd0,
+};
+
+static int test(const char *name, const uint8_t *der, size_t der_len) {
+  CBS pkcs12;
+  EVP_PKEY *key;
+  STACK_OF(X509) *certs;
+
+  certs = sk_X509_new_null();
+
+  CBS_init(&pkcs12, der, der_len);
+  if (!PKCS12_get_key_and_certs(&key, certs, &pkcs12, "foo")) {
+    fprintf(stderr, "PKCS12 failed on %s data.\n", name);
+    BIO_print_errors_fp(stderr);
+    return 0;
+  }
+
+  if (sk_X509_num(certs) != 1 || key == NULL) {
+    fprintf(stderr, "Bad result from %s data.\n", name);
+    return 0;
+  }
+
+  sk_X509_pop_free(certs, X509_free);
+  EVP_PKEY_free(key);
+
+  return 1;
+}
+
+static int test_compat(const uint8_t *der, size_t der_len) {
+  PKCS12 *p12;
+  X509 *cert = NULL;
+  STACK_OF(X509) *ca_certs = NULL;
+  EVP_PKEY *key;
+  BIO *bio;
+
+  bio = BIO_new_mem_buf((void*) der, der_len);
+
+  p12 = d2i_PKCS12_bio(bio, NULL);
+  if (p12 == NULL) {
+    fprintf(stderr, "PKCS12_parse failed.\n");
+    BIO_print_errors_fp(stderr);
+    return 0;
+  }
+  BIO_free(bio);
+
+  if (!PKCS12_parse(p12, "foo", &key, &cert, &ca_certs)) {
+    fprintf(stderr, "PKCS12_parse failed.\n");
+    BIO_print_errors_fp(stderr);
+    return 0;
+  }
+
+  if (key == NULL || cert == NULL) {
+    fprintf(stderr, "Bad result from PKCS12_parse.\n");
+    return 0;
+  }
+
+  EVP_PKEY_free(key);
+  X509_free(cert);
+
+  if (sk_X509_num(ca_certs) != 0) {
+    fprintf(stderr, "Bad result from PKCS12_parse.\n");
+    return 0;
+  }
+  sk_X509_free(ca_certs);
+
+  PKCS12_free(p12);
+
+  return 1;
+}
+
+int main(int argc, char **argv) {
+  CRYPTO_library_init();
+  ERR_load_crypto_strings();
+
+  if (!test("OpenSSL", kOpenSSL, sizeof(kOpenSSL)) ||
+      !test("NSS", kNSS, sizeof(kNSS)) ||
+      !test("Windows", kWindows, sizeof(kWindows)) ||
+      !test_compat(kWindows, sizeof(kWindows))) {
+    return 1;
+  }
+
+  printf("PASS\n");
+  return 0;
+}
diff --git a/crypto/pkcs8/pkcs8.c b/crypto/pkcs8/pkcs8.c
index b39f10b..58e400d 100644
--- a/crypto/pkcs8/pkcs8.c
+++ b/crypto/pkcs8/pkcs8.c
@@ -55,19 +55,26 @@
 
 #include <openssl/pkcs8.h>
 
+#include <assert.h>
+#include <limits.h>
+
 #include <openssl/asn1.h>
 #include <openssl/bn.h>
+#include <openssl/buf.h>
 #include <openssl/cipher.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
+#include <openssl/hmac.h>
 #include <openssl/mem.h>
 #include <openssl/x509.h>
 
+#include "../bytestring/internal.h"
 #include "../evp/internal.h"
 
 
 #define PKCS12_KEY_ID 1
 #define PKCS12_IV_ID 2
+#define PKCS12_MAC_ID 3
 
 static int ascii_to_ucs2(const char *ascii, size_t ascii_len,
                          uint8_t **out, size_t *out_len) {
@@ -96,7 +103,7 @@
 }
 
 static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
-                              uint8_t *salt, size_t salt_len,
+                              const uint8_t *salt, size_t salt_len,
                               int id, int iterations,
                               size_t out_len, uint8_t *out,
                               const EVP_MD *md_type) {
@@ -256,17 +263,20 @@
 
 struct pbe_suite {
   int pbe_nid;
-  int cipher_nid;
-  int md_nid;
+  const EVP_CIPHER* (*cipher_func)();
+  const EVP_MD* (*md_func)();
   keygen_func keygen;
 };
 
 static const struct pbe_suite kBuiltinPBE[] = {
     {
-     NID_pbe_WithSHA1And128BitRC4, NID_rc4, NID_sha1, pkcs12_pbe_keyivgen,
+     NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1, pkcs12_pbe_keyivgen,
     },
     {
-     NID_pbe_WithSHA1And3_Key_TripleDES_CBC, NID_des_ede3_cbc, NID_sha1,
+     NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1, pkcs12_pbe_keyivgen,
+    },
+    {
+     NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1,
      pkcs12_pbe_keyivgen,
     },
 };
@@ -283,8 +293,8 @@
   const int pbe_nid = OBJ_obj2nid(pbe_obj);
 
   for (i = 0; i < sizeof(kBuiltinPBE) / sizeof(struct pbe_suite); i++) {
-    suite = &kBuiltinPBE[i];
-    if (suite->pbe_nid == pbe_nid) {
+    if (kBuiltinPBE[i].pbe_nid == pbe_nid) {
+      suite = &kBuiltinPBE[i];
       break;
     }
   }
@@ -301,20 +311,20 @@
     return 0;
   }
 
-  if (suite->cipher_nid == -1) {
+  if (suite->cipher_func == NULL) {
     cipher = NULL;
   } else {
-    cipher = EVP_get_cipherbynid(suite->cipher_nid);
+    cipher = suite->cipher_func();
     if (!cipher) {
       OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_CIPHER);
       return 0;
     }
   }
 
-  if (suite->md_nid == -1) {
+  if (suite->md_func == NULL) {
     md = NULL;
   } else {
-    md = EVP_get_digestbynid(suite->md_nid);
+    md = suite->md_func();
     if (!md) {
       OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_DIGEST);
       return 0;
@@ -332,7 +342,8 @@
 
 static int pbe_crypt(const X509_ALGOR *algor,
                      const uint8_t *pass_raw, size_t pass_raw_len,
-                     uint8_t *in, size_t in_len, uint8_t **out, size_t *out_len,
+                     const uint8_t *in, size_t in_len,
+                     uint8_t **out, size_t *out_len,
                      int is_encrypt) {
   uint8_t *buf;
   int n, ret = 0;
@@ -601,3 +612,543 @@
   PKCS8_PRIV_KEY_INFO_free(p8);
   return NULL;
 }
+
+struct pkcs12_context {
+  EVP_PKEY **out_key;
+  STACK_OF(X509) *out_certs;
+  uint8_t *password;
+  size_t password_len;
+};
+
+static int PKCS12_handle_content_info(CBS *content_info, unsigned depth,
+                                      struct pkcs12_context *ctx);
+
+/* PKCS12_handle_content_infos parses a series of PKCS#7 ContentInfos in a
+ * SEQUENCE. */
+static int PKCS12_handle_content_infos(CBS *content_infos,
+                                       unsigned depth,
+                                       struct pkcs12_context *ctx) {
+  uint8_t *der_bytes = NULL;
+  size_t der_len;
+  CBS in;
+  int ret = 0;
+
+  /* Generally we only expect depths 0 (the top level, with a
+   * pkcs7-encryptedData and a pkcs7-data) and depth 1 (the various PKCS#12
+   * bags). */
+  if (depth > 3) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_infos,
+                      PKCS8_R_PKCS12_TOO_DEEPLY_NESTED);
+    return 0;
+  }
+
+  /* Although a BER->DER conversion is done at the beginning of |PKCS12_parse|,
+   * the ASN.1 data gets wrapped in OCTETSTRINGs and/or encrypted and the
+   * conversion cannot see through those wrappings. So each time we step
+   * through one we need to convert to DER again. */
+  if (!CBS_asn1_ber_to_der(content_infos, &der_bytes, &der_len)) {
+    return 0;
+  }
+
+  if (der_bytes != NULL) {
+    CBS_init(&in, der_bytes, der_len);
+  } else {
+    CBS_init(&in, CBS_data(content_infos), CBS_len(content_infos));
+  }
+
+  if (!CBS_get_asn1(&in, &in, CBS_ASN1_SEQUENCE)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_infos,
+                      PKCS8_R_BAD_PKCS12_DATA);
+    goto err;
+  }
+
+  while (CBS_len(&in) > 0) {
+    CBS content_info;
+    if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE)) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_infos,
+                        PKCS8_R_BAD_PKCS12_DATA);
+      goto err;
+    }
+
+    if (!PKCS12_handle_content_info(&content_info, depth + 1, ctx)) {
+      goto err;
+    }
+  }
+
+  /* NSS includes additional data after the SEQUENCE, but it's an (unwrapped)
+   * copy of the same encrypted private key (with the same IV and
+   * ciphertext)! */
+
+  ret = 1;
+
+err:
+  if (der_bytes != NULL) {
+    OPENSSL_free(der_bytes);
+  }
+  return ret;
+}
+
+/* PKCS12_handle_content_info parses a single PKCS#7 ContentInfo element in a
+ * PKCS#12 structure. */
+static int PKCS12_handle_content_info(CBS *content_info, unsigned depth,
+                                      struct pkcs12_context *ctx) {
+  CBS content_type, wrapped_contents, contents, content_infos;
+  int nid, ret = 0;
+
+  if (!CBS_get_asn1(content_info, &content_type, CBS_ASN1_OBJECT) ||
+      !CBS_get_asn1(content_info, &wrapped_contents,
+                        CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
+    goto err;
+  }
+
+  nid = OBJ_cbs2nid(&content_type);
+  if (nid == NID_pkcs7_encrypted) {
+    /* See https://tools.ietf.org/html/rfc2315#section-13.
+     *
+     * PKCS#7 encrypted data inside a PKCS#12 structure is generally an
+     * encrypted certificate bag and it's generally encrypted with 40-bit
+     * RC2-CBC. */
+    CBS version_bytes, eci, contents_type, ai, encrypted_contents;
+    X509_ALGOR *algor = NULL;
+    const uint8_t *inp;
+    uint8_t *out;
+    size_t out_len;
+
+    if (!CBS_get_asn1(&wrapped_contents, &contents, CBS_ASN1_SEQUENCE) ||
+        !CBS_get_asn1(&contents, &version_bytes, CBS_ASN1_INTEGER) ||
+        /* EncryptedContentInfo, see
+         * https://tools.ietf.org/html/rfc2315#section-10.1 */
+        !CBS_get_asn1(&contents, &eci, CBS_ASN1_SEQUENCE) ||
+        !CBS_get_asn1(&eci, &contents_type, CBS_ASN1_OBJECT) ||
+        /* AlgorithmIdentifier, see
+         * https://tools.ietf.org/html/rfc5280#section-4.1.1.2 */
+        !CBS_get_asn1_element(&eci, &ai, CBS_ASN1_SEQUENCE) ||
+        !CBS_get_asn1(&eci, &encrypted_contents,
+                      CBS_ASN1_CONTEXT_SPECIFIC | 0)) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                        PKCS8_R_BAD_PKCS12_DATA);
+      goto err;
+    }
+
+    if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                        PKCS8_R_BAD_PKCS12_DATA);
+      goto err;
+    }
+
+    inp = CBS_data(&ai);
+    algor = d2i_X509_ALGOR(NULL, &inp, CBS_len(&ai));
+    if (algor == NULL) {
+      goto err;
+    }
+    if (inp != CBS_data(&ai) + CBS_len(&ai)) {
+      X509_ALGOR_free(algor);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                        PKCS8_R_BAD_PKCS12_DATA);
+      goto err;
+    }
+
+    if (!pbe_crypt(algor, ctx->password, ctx->password_len,
+                   CBS_data(&encrypted_contents), CBS_len(&encrypted_contents),
+                   &out, &out_len, 0 /* decrypt */)) {
+      X509_ALGOR_free(algor);
+      goto err;
+    }
+    X509_ALGOR_free(algor);
+
+    CBS_init(&content_infos, out, out_len);
+    ret = PKCS12_handle_content_infos(&content_infos, depth + 1, ctx);
+    OPENSSL_free(out);
+  } else if (nid == NID_pkcs7_data) {
+    CBS octet_string_contents;
+
+    if (!CBS_get_asn1(&wrapped_contents, &octet_string_contents,
+                          CBS_ASN1_OCTETSTRING)) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                        PKCS8_R_BAD_PKCS12_DATA);
+      goto err;
+    }
+
+    ret = PKCS12_handle_content_infos(&octet_string_contents, depth + 1, ctx);
+  } else if (nid == NID_pkcs8ShroudedKeyBag) {
+    /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section
+     * 4.2.2. */
+    const uint8_t *inp = CBS_data(&wrapped_contents);
+    PKCS8_PRIV_KEY_INFO *pki = NULL;
+    X509_SIG *encrypted = NULL;
+
+    if (*ctx->out_key) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                        PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12);
+      goto err;
+    }
+
+    /* encrypted isn't actually an X.509 signature, but it has the same
+     * structure as one and so |X509_SIG| is reused to store it. */
+    encrypted = d2i_X509_SIG(NULL, &inp, CBS_len(&wrapped_contents));
+    if (encrypted == NULL) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                        PKCS8_R_BAD_PKCS12_DATA);
+      goto err;
+    }
+    if (inp != CBS_data(&wrapped_contents) + CBS_len(&wrapped_contents)) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                        PKCS8_R_BAD_PKCS12_DATA);
+      X509_SIG_free(encrypted);
+      goto err;
+    }
+
+    pki = PKCS8_decrypt_pbe(encrypted, ctx->password, ctx->password_len);
+    X509_SIG_free(encrypted);
+    if (pki == NULL) {
+      goto err;
+    }
+
+    *ctx->out_key = EVP_PKCS82PKEY(pki);
+    PKCS8_PRIV_KEY_INFO_free(pki);
+
+    if (ctx->out_key == NULL) {
+      goto err;
+    }
+    ret = 1;
+  } else if (nid == NID_certBag) {
+    CBS cert_bag, cert_type, wrapped_cert, cert;
+
+    if (!CBS_get_asn1(&wrapped_contents, &cert_bag, CBS_ASN1_SEQUENCE) ||
+        !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) ||
+        !CBS_get_asn1(&cert_bag, &wrapped_cert,
+                      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
+        !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                        PKCS8_R_BAD_PKCS12_DATA);
+      goto err;
+    }
+
+    if (OBJ_cbs2nid(&cert_type) == NID_x509Certificate) {
+      const uint8_t *inp = CBS_data(&cert);
+      X509 *x509 = d2i_X509(NULL, &inp, CBS_len(&cert));
+      if (!x509) {
+        OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                          PKCS8_R_BAD_PKCS12_DATA);
+        goto err;
+      }
+      if (inp != CBS_data(&cert) + CBS_len(&cert)) {
+        OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
+                          PKCS8_R_BAD_PKCS12_DATA);
+        X509_free(x509);
+        goto err;
+      }
+
+      if (0 == sk_X509_push(ctx->out_certs, x509)) {
+        X509_free(x509);
+        goto err;
+      }
+    }
+    ret = 1;
+  } else {
+    /* Unknown element type - ignore it. */
+    ret = 1;
+  }
+
+err:
+  return ret;
+}
+
+int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs,
+                             CBS *ber_in, const char *password) {
+  uint8_t *der_bytes = NULL;
+  size_t der_len;
+  CBS in, pfx, mac_data, authsafe, content_type, wrapped_authsafes, authsafes;
+  uint64_t version;
+  int ret = 0;
+  struct pkcs12_context ctx;
+  const size_t original_out_certs_len = sk_X509_num(out_certs);
+
+  /* The input may be in BER format. */
+  if (!CBS_asn1_ber_to_der(ber_in, &der_bytes, &der_len)) {
+    return 0;
+  }
+  if (der_bytes != NULL) {
+    CBS_init(&in, der_bytes, der_len);
+  } else {
+    CBS_init(&in, CBS_data(ber_in), CBS_len(ber_in));
+  }
+
+  *out_key = NULL;
+  memset(&ctx, 0, sizeof(ctx));
+
+  /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section
+   * four. */
+  if (!CBS_get_asn1(&in, &pfx, CBS_ASN1_SEQUENCE) ||
+      CBS_len(&in) != 0 ||
+      !CBS_get_asn1_uint64(&pfx, &version)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
+    goto err;
+  }
+
+  if (version < 3) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_VERSION);
+    goto err;
+  }
+
+  if (!CBS_get_asn1(&pfx, &authsafe, CBS_ASN1_SEQUENCE)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
+    goto err;
+  }
+
+  if (CBS_len(&pfx) == 0) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_MISSING_MAC);
+    goto err;
+  }
+
+  if (!CBS_get_asn1(&pfx, &mac_data, CBS_ASN1_SEQUENCE)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
+    goto err;
+  }
+
+  /* authsafe is a PKCS#7 ContentInfo. See
+   * https://tools.ietf.org/html/rfc2315#section-7. */
+  if (!CBS_get_asn1(&authsafe, &content_type, CBS_ASN1_OBJECT) ||
+      !CBS_get_asn1(&authsafe, &wrapped_authsafes,
+                        CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
+    goto err;
+  }
+
+  /* The content type can either be |NID_pkcs7_data| or |NID_pkcs7_signed|. The
+   * latter indicates that it's signed by a public key, which isn't
+   * supported. */
+  if (OBJ_cbs2nid(&content_type) != NID_pkcs7_data) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse,
+                      PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED);
+    goto err;
+  }
+
+  if (!CBS_get_asn1(&wrapped_authsafes, &authsafes, CBS_ASN1_OCTETSTRING)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
+    goto err;
+  }
+
+  ctx.out_key = out_key;
+  ctx.out_certs = out_certs;
+  if (!ascii_to_ucs2(password, strlen(password), &ctx.password,
+                     &ctx.password_len)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_DECODE_ERROR);
+    goto err;
+  }
+
+  /* Verify the MAC. */
+  {
+    CBS mac, hash_type_seq, hash_oid, salt, expected_mac;
+    uint64_t iterations;
+    int hash_nid;
+    const EVP_MD *md;
+    uint8_t hmac_key[EVP_MAX_MD_SIZE];
+    uint8_t hmac[EVP_MAX_MD_SIZE];
+    unsigned hmac_len;
+
+    if (!CBS_get_asn1(&mac_data, &mac, CBS_ASN1_SEQUENCE) ||
+        !CBS_get_asn1(&mac, &hash_type_seq, CBS_ASN1_SEQUENCE) ||
+        !CBS_get_asn1(&hash_type_seq, &hash_oid, CBS_ASN1_OBJECT) ||
+        !CBS_get_asn1(&mac, &expected_mac, CBS_ASN1_OCTETSTRING) ||
+        !CBS_get_asn1(&mac_data, &salt, CBS_ASN1_OCTETSTRING)) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
+      goto err;
+    }
+
+    /* The iteration count is optional and the default is one. */
+    iterations = 1;
+    if (CBS_len(&mac_data) > 0) {
+      if (!CBS_get_asn1_uint64(&mac_data, &iterations) ||
+          iterations > INT_MAX) {
+        OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_BAD_PKCS12_DATA);
+        goto err;
+      }
+    }
+
+    hash_nid = OBJ_cbs2nid(&hash_oid);
+    if (hash_nid == NID_undef ||
+        (md = EVP_get_digestbynid(hash_nid)) == NULL) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_UNKNOWN_HASH);
+      goto err;
+    }
+
+    if (!pkcs12_key_gen_raw(ctx.password, ctx.password_len, CBS_data(&salt),
+                            CBS_len(&salt), PKCS12_MAC_ID, iterations,
+                            EVP_MD_size(md), hmac_key, md)) {
+      goto err;
+    }
+
+    if (NULL == HMAC(md, hmac_key, EVP_MD_size(md), CBS_data(&authsafes),
+                     CBS_len(&authsafes), hmac, &hmac_len)) {
+      goto err;
+    }
+
+    if (!CBS_mem_equal(&expected_mac, hmac, hmac_len)) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS12_parse, PKCS8_R_INCORRECT_PASSWORD);
+      goto err;
+    }
+  }
+
+  /* authsafes contains a series of PKCS#7 ContentInfos. */
+  if (!PKCS12_handle_content_infos(&authsafes, 0, &ctx)) {
+    goto err;
+  }
+
+  ret = 1;
+
+err:
+  if (ctx.password) {
+    OPENSSL_free(ctx.password);
+  }
+  if (der_bytes) {
+    OPENSSL_free(der_bytes);
+  }
+  if (!ret) {
+    if (*out_key) {
+      EVP_PKEY_free(*out_key);
+      *out_key = NULL;
+    }
+    while (sk_X509_num(out_certs) > original_out_certs_len) {
+      X509 *x509 = sk_X509_pop(out_certs);
+      X509_free(x509);
+    }
+  }
+
+  return ret;
+}
+
+void PKCS12_PBE_add(){};
+
+struct pkcs12_st {
+  uint8_t *ber_bytes;
+  size_t ber_len;
+};
+
+PKCS12* d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, size_t ber_len) {
+  PKCS12 *p12;
+
+  /* out_p12 must be NULL because we don't export the PKCS12 structure. */
+  assert(out_p12 == NULL);
+
+  p12 = OPENSSL_malloc(sizeof(PKCS12));
+  if (!p12) {
+    return NULL;
+  }
+
+  p12->ber_bytes = OPENSSL_malloc(ber_len);
+  if (!p12->ber_bytes) {
+    OPENSSL_free(p12);
+    return NULL;
+  }
+
+  memcpy(p12->ber_bytes, *ber_bytes, ber_len);
+  p12->ber_len = ber_len;
+  *ber_bytes += ber_len;
+
+  return p12;
+}
+
+PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12) {
+  size_t used = 0;
+  BUF_MEM *buf;
+  const uint8_t *dummy;
+  static const size_t kMaxSize = 256 * 1024;
+  PKCS12 *ret = NULL;
+
+  buf = BUF_MEM_new();
+  if (buf == NULL) {
+    return NULL;
+  }
+  if (BUF_MEM_grow(buf, 8192) == 0) {
+    goto out;
+  }
+
+  for (;;) {
+    int n = BIO_read(bio, &buf->data[used], buf->length - used);
+    if (n < 0) {
+      goto out;
+    }
+
+    if (n == 0) {
+      break;
+    }
+    used += n;
+
+    if (used < buf->length) {
+      continue;
+    }
+
+    if (buf->length > kMaxSize ||
+        BUF_MEM_grow(buf, buf->length * 2) == 0) {
+      goto out;
+    }
+  }
+
+  dummy = (uint8_t*) buf->data;
+  ret = d2i_PKCS12(out_p12, &dummy, used);
+
+out:
+  BUF_MEM_free(buf);
+  return ret;
+}
+
+PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12) {
+  BIO *bio;
+  PKCS12 *ret;
+
+  bio = BIO_new_fp(fp, 0 /* don't take ownership */);
+  if (!bio) {
+    return NULL;
+  }
+
+  ret = d2i_PKCS12_bio(bio, out_p12);
+  BIO_free(bio);
+  return ret;
+}
+
+int PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey,
+                 X509 **out_cert, STACK_OF(X509) **out_ca_certs) {
+  CBS ber_bytes;
+  STACK_OF(X509) *ca_certs = NULL;
+  char ca_certs_alloced = 0;
+
+  if (out_ca_certs != NULL && *out_ca_certs != NULL) {
+    ca_certs = *out_ca_certs;
+  }
+
+  if (!ca_certs) {
+    ca_certs = sk_X509_new_null();
+    if (ca_certs == NULL) {
+      return 0;
+    }
+    ca_certs_alloced = 1;
+  }
+
+  CBS_init(&ber_bytes, p12->ber_bytes, p12->ber_len);
+  if (!PKCS12_get_key_and_certs(out_pkey, ca_certs, &ber_bytes, password)) {
+    if (ca_certs_alloced) {
+      sk_X509_free(ca_certs);
+    }
+    return 0;
+  }
+
+  *out_cert = NULL;
+  if (sk_X509_num(ca_certs) > 0) {
+    *out_cert = sk_X509_shift(ca_certs);
+  }
+
+  if (out_ca_certs) {
+    *out_ca_certs = ca_certs;
+  } else {
+    sk_X509_pop_free(ca_certs, X509_free);
+  }
+
+  return 1;
+}
+
+void PKCS12_free(PKCS12 *p12) {
+  OPENSSL_free(p12->ber_bytes);
+  OPENSSL_free(p12);
+}
diff --git a/crypto/pkcs8/pkcs8_error.c b/crypto/pkcs8/pkcs8_error.c
index de1661b..3041658 100644
--- a/crypto/pkcs8/pkcs8_error.c
+++ b/crypto/pkcs8/pkcs8_error.c
@@ -19,6 +19,10 @@
 const ERR_STRING_DATA PKCS8_error_string_data[] = {
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_EVP_PKCS82PKEY, 0), "EVP_PKCS82PKEY"},
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_EVP_PKEY2PKCS8, 0), "EVP_PKEY2PKCS8"},
+  {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS12_get_key_and_certs, 0), "PKCS12_get_key_and_certs"},
+  {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS12_handle_content_info, 0), "PKCS12_handle_content_info"},
+  {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS12_handle_content_infos, 0), "PKCS12_handle_content_infos"},
+  {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS12_parse, 0), "PKCS12_parse"},
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS5_pbe2_set_iv, 0), "PKCS5_pbe2_set_iv"},
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS5_pbe_set, 0), "PKCS5_pbe_set"},
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS5_pbe_set0_algor, 0), "PKCS5_pbe_set0_algor"},
@@ -30,17 +34,27 @@
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pbe_crypt, 0), "pbe_crypt"},
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_item_decrypt_d2i, 0), "pkcs12_item_decrypt_d2i"},
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_item_i2d_encrypt, 0), "pkcs12_item_i2d_encrypt"},
+  {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_key_gen_asc, 0), "pkcs12_key_gen_asc"},
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_key_gen_raw, 0), "pkcs12_key_gen_raw"},
+  {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_key_gen_uni, 0), "pkcs12_key_gen_uni"},
   {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_pbe_keyivgen, 0), "pkcs12_pbe_keyivgen"},
+  {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_BAD_MAC), "BAD_MAC"},
+  {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_BAD_PKCS12_DATA), "BAD_PKCS12_DATA"},
+  {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_BAD_PKCS12_VERSION), "BAD_PKCS12_VERSION"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER), "CIPHER_HAS_NO_OBJECT_IDENTIFIER"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_CRYPT_ERROR), "CRYPT_ERROR"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_DECODE_ERROR), "DECODE_ERROR"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_ENCODE_ERROR), "ENCODE_ERROR"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_ENCRYPT_ERROR), "ENCRYPT_ERROR"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS), "ERROR_SETTING_CIPHER_PARAMS"},
+  {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_INCORRECT_PASSWORD), "INCORRECT_PASSWORD"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_KEYGEN_FAILURE), "KEYGEN_FAILURE"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_KEY_GEN_ERROR), "KEY_GEN_ERROR"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_METHOD_NOT_SUPPORTED), "METHOD_NOT_SUPPORTED"},
+  {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_MISSING_MAC), "MISSING_MAC"},
+  {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12), "MULTIPLE_PRIVATE_KEYS_IN_PKCS12"},
+  {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED), "PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED"},
+  {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_PKCS12_TOO_DEEPLY_NESTED), "PKCS12_TOO_DEEPLY_NESTED"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_PRIVATE_KEY_DECODE_ERROR), "PRIVATE_KEY_DECODE_ERROR"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_PRIVATE_KEY_ENCODE_ERROR), "PRIVATE_KEY_ENCODE_ERROR"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_TOO_LONG), "TOO_LONG"},
@@ -48,6 +62,7 @@
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNKNOWN_CIPHER), "UNKNOWN_CIPHER"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNKNOWN_CIPHER_ALGORITHM), "UNKNOWN_CIPHER_ALGORITHM"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNKNOWN_DIGEST), "UNKNOWN_DIGEST"},
+  {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNKNOWN_HASH), "UNKNOWN_HASH"},
   {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM), "UNSUPPORTED_PRIVATE_KEY_ALGORITHM"},
   {0, NULL},
 };
diff --git a/crypto/poly1305/poly1305.c b/crypto/poly1305/poly1305.c
index 9b9c734..bf5cd5e 100644
--- a/crypto/poly1305/poly1305.c
+++ b/crypto/poly1305/poly1305.c
@@ -48,7 +48,7 @@
 }
 #endif
 
-#if defined(OPENSSL_ARM)
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
 void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]);
 
 void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in,
@@ -165,7 +165,7 @@
   struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
   uint32_t t0, t1, t2, t3;
 
-#if defined(OPENSSL_ARM)
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
   if (CRYPTO_is_NEON_functional()) {
     CRYPTO_poly1305_init_neon(statep, key);
     return;
@@ -212,7 +212,7 @@
   unsigned int i;
   struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
 
-#if defined(OPENSSL_ARM)
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
   if (CRYPTO_is_NEON_functional()) {
     CRYPTO_poly1305_update_neon(statep, in, in_len);
     return;
@@ -255,7 +255,7 @@
   uint32_t g0, g1, g2, g3, g4;
   uint32_t b, nb;
 
-#if defined(OPENSSL_ARM)
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
   if (CRYPTO_is_NEON_functional()) {
     CRYPTO_poly1305_finish_neon(statep, mac);
     return;
diff --git a/crypto/poly1305/poly1305_arm.c b/crypto/poly1305/poly1305_arm.c
index 9d5e276..002a4c4 100644
--- a/crypto/poly1305/poly1305_arm.c
+++ b/crypto/poly1305/poly1305_arm.c
@@ -17,8 +17,7 @@
 
 #include <openssl/poly1305.h>
 
-
-#if defined(OPENSSL_ARM)
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
 
 typedef struct {
   uint32_t v[12]; /* for alignment; only using 10 */
@@ -285,4 +284,4 @@
   fe1305x2_tobytearray(mac, h);
 }
 
-#endif  /* OPENSSL_ARM */
+#endif  /* OPENSSL_ARM && !OPENSSL_NO_ASM */
diff --git a/crypto/poly1305/poly1305_arm_asm.S b/crypto/poly1305/poly1305_arm_asm.S
index 9cf7656..9d87413 100644
--- a/crypto/poly1305/poly1305_arm_asm.S
+++ b/crypto/poly1305/poly1305_arm_asm.S
@@ -1,4 +1,4 @@
-#if defined(__arm__)
+#if defined(__arm__) && !defined(OPENSSL_NO_ASM)
 
 # This implementation was taken from the public domain, neon2 version in
 # SUPERCOP by D. J. Bernstein and Peter Schwabe.
@@ -2012,4 +2012,4 @@
 add sp,sp,#0
 bx lr
 
-#endif
+#endif  /* __arm__ && !OPENSSL_NO_ASM */
diff --git a/crypto/rand/urandom.c b/crypto/rand/urandom.c
index 6cd9271..2ad4af0 100644
--- a/crypto/rand/urandom.c
+++ b/crypto/rand/urandom.c
@@ -87,7 +87,7 @@
 
 /* urandom_get_fd_locked returns a file descriptor to /dev/urandom. The caller
  * of this function must hold CRYPTO_LOCK_RAND. */
-static int urandom_get_fd_locked() {
+static int urandom_get_fd_locked(void) {
   if (urandom_fd != -2)
     return urandom_fd;
 
diff --git a/crypto/rsa/rsa_test.c b/crypto/rsa/rsa_test.c
index 4a0069c..a5bc366 100644
--- a/crypto/rsa/rsa_test.c
+++ b/crypto/rsa/rsa_test.c
@@ -58,6 +58,7 @@
 
 #include <openssl/bio.h>
 #include <openssl/bn.h>
+#include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/obj.h>
 
@@ -237,7 +238,7 @@
   SetKey;
 }
 
-static int test_bad_key() {
+static int test_bad_key(void) {
   RSA *key = RSA_new();
   BIGNUM e;
 
@@ -267,7 +268,7 @@
   return 1;
 }
 
-static int test_only_d_given() {
+static int test_only_d_given(void) {
   RSA *key = RSA_new();
   uint8_t buf[64];
   unsigned buf_len = sizeof(buf);
@@ -312,7 +313,7 @@
   return ret;
 }
 
-static int test_recover_crt_params() {
+static int test_recover_crt_params(void) {
   RSA *key1, *key2;
   BIGNUM *e = BN_new();
   uint8_t buf[128];
@@ -394,6 +395,8 @@
   int num;
   int n;
 
+  CRYPTO_library_init();
+
   plen = sizeof(ptext_ex) - 1;
 
   for (v = 0; v < 3; v++) {
diff --git a/crypto/sha/sha1_test.c b/crypto/sha/sha1_test.c
index 72ef9e1..d723e40 100644
--- a/crypto/sha/sha1_test.c
+++ b/crypto/sha/sha1_test.c
@@ -56,8 +56,9 @@
 
 #include <stdio.h>
 
-#include <openssl/sha.h>
+#include <openssl/crypto.h>
 #include <openssl/digest.h>
+#include <openssl/sha.h>
 
 
 static const char *const test[] = {
@@ -67,7 +68,7 @@
     "a9993e364706816aba3e25717850c26c9cd0d89d",
     "84983e441c3bd26ebaae4aa1f95129e5e54670f1", };
 
-static int test_incremental() {
+static int test_incremental(void) {
   EVP_MD_CTX ctx;
   char buf[1000];
   uint8_t md[SHA_DIGEST_LENGTH];
@@ -102,6 +103,8 @@
   char md_hex[sizeof(md) * 2 + 1];
   int ok = 1;
 
+  CRYPTO_library_init();
+
   for (i = 0; test[i] != NULL; i++) {
     EVP_Digest(test[i], strlen(test[i]), md, NULL, EVP_sha1(), NULL);
     for (j = 0; j < sizeof(md); j++) {
diff --git a/crypto/sha/sha512.c b/crypto/sha/sha512.c
index dcaac6f..884371a 100644
--- a/crypto/sha/sha512.c
+++ b/crypto/sha/sha512.c
@@ -60,6 +60,8 @@
 
 #include <openssl/mem.h>
 
+#include "../internal.h"
+
 
 /* IMPLEMENTATION NOTES.
  *
@@ -92,14 +94,14 @@
 #endif
 
 int SHA384_Init(SHA512_CTX *sha) {
-  sha->h[0] = 0xcbbb9d5dc1059ed8;
-  sha->h[1] = 0x629a292a367cd507;
-  sha->h[2] = 0x9159015a3070dd17;
-  sha->h[3] = 0x152fecd8f70e5939;
-  sha->h[4] = 0x67332667ffc00b31;
-  sha->h[5] = 0x8eb44a8768581511;
-  sha->h[6] = 0xdb0c2e0d64f98fa7;
-  sha->h[7] = 0x47b5481dbefa4fa4;
+  sha->h[0] = OPENSSL_U64(0xcbbb9d5dc1059ed8);
+  sha->h[1] = OPENSSL_U64(0x629a292a367cd507);
+  sha->h[2] = OPENSSL_U64(0x9159015a3070dd17);
+  sha->h[3] = OPENSSL_U64(0x152fecd8f70e5939);
+  sha->h[4] = OPENSSL_U64(0x67332667ffc00b31);
+  sha->h[5] = OPENSSL_U64(0x8eb44a8768581511);
+  sha->h[6] = OPENSSL_U64(0xdb0c2e0d64f98fa7);
+  sha->h[7] = OPENSSL_U64(0x47b5481dbefa4fa4);
 
   sha->Nl = 0;
   sha->Nh = 0;
@@ -110,14 +112,14 @@
 
 
 int SHA512_Init(SHA512_CTX *sha) {
-  sha->h[0] = 0x6a09e667f3bcc908;
-  sha->h[1] = 0xbb67ae8584caa73b;
-  sha->h[2] = 0x3c6ef372fe94f82b;
-  sha->h[3] = 0xa54ff53a5f1d36f1;
-  sha->h[4] = 0x510e527fade682d1;
-  sha->h[5] = 0x9b05688c2b3e6c1f;
-  sha->h[6] = 0x1f83d9abfb41bd6b;
-  sha->h[7] = 0x5be0cd19137e2179;
+  sha->h[0] = OPENSSL_U64(0x6a09e667f3bcc908);
+  sha->h[1] = OPENSSL_U64(0xbb67ae8584caa73b);
+  sha->h[2] = OPENSSL_U64(0x3c6ef372fe94f82b);
+  sha->h[3] = OPENSSL_U64(0xa54ff53a5f1d36f1);
+  sha->h[4] = OPENSSL_U64(0x510e527fade682d1);
+  sha->h[5] = OPENSSL_U64(0x9b05688c2b3e6c1f);
+  sha->h[6] = OPENSSL_U64(0x1f83d9abfb41bd6b);
+  sha->h[7] = OPENSSL_U64(0x5be0cd19137e2179);
 
   sha->Nl = 0;
   sha->Nh = 0;
@@ -189,7 +191,7 @@
   if (len == 0)
     return 1;
 
-  l = (c->Nl + (((uint64_t)len) << 3)) & 0xffffffffffffffff;
+  l = (c->Nl + (((uint64_t)len) << 3)) & OPENSSL_U64(0xffffffffffffffff);
   if (l < c->Nl) {
     c->Nh++;
   }
diff --git a/crypto/x509/pkcs7.c b/crypto/x509/pkcs7.c
index 7744fcc..75c101b 100644
--- a/crypto/x509/pkcs7.c
+++ b/crypto/x509/pkcs7.c
@@ -19,48 +19,61 @@
 #include <openssl/obj.h>
 #include <openssl/stack.h>
 
+#include "../bytestring/internal.h"
+
 
 int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) {
-  CBS content_info, content_type, wrapped_signed_data, signed_data,
-      version_bytes, certificates;
-  int nid;
+  uint8_t *der_bytes = NULL;
+  size_t der_len;
+  CBS in, content_info, content_type, wrapped_signed_data, signed_data,
+      certificates;
   const size_t initial_certs_len = sk_X509_num(out_certs);
+  uint64_t version;
+  int ret = 0;
 
-  /* See https://tools.ietf.org/html/rfc2315#section-7 */
-  if (!CBS_get_asn1_ber(cbs, &content_info, CBS_ASN1_SEQUENCE) ||
-      !CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) {
+  /* The input may be in BER format. */
+  if (!CBS_asn1_ber_to_der(cbs, &der_bytes, &der_len)) {
     return 0;
   }
+  if (der_bytes != NULL) {
+    CBS_init(&in, der_bytes, der_len);
+  } else {
+    CBS_init(&in, CBS_data(cbs), CBS_len(cbs));
+  }
 
-  nid = OBJ_cbs2nid(&content_type);
-  if (nid != NID_pkcs7_signed) {
+  /* See https://tools.ietf.org/html/rfc2315#section-7 */
+  if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE) ||
+      !CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) {
+    goto err;
+  }
+
+  if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) {
     OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
                       X509_R_NOT_PKCS7_SIGNED_DATA);
-    return 0;
+    goto err;
   }
 
   /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
-  if (!CBS_get_asn1_ber(&content_info, &wrapped_signed_data,
-                        CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
-      !CBS_get_asn1_ber(&wrapped_signed_data, &signed_data,
-                        CBS_ASN1_SEQUENCE) ||
-      !CBS_get_asn1_ber(&signed_data, &version_bytes, CBS_ASN1_INTEGER) ||
-      !CBS_get_asn1_ber(&signed_data, NULL /* digests */, CBS_ASN1_SET) ||
-      !CBS_get_asn1_ber(&signed_data, NULL /* content */, CBS_ASN1_SEQUENCE)) {
-    return 0;
+  if (!CBS_get_asn1(&content_info, &wrapped_signed_data,
+                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
+      !CBS_get_asn1(&wrapped_signed_data, &signed_data, CBS_ASN1_SEQUENCE) ||
+      !CBS_get_asn1_uint64(&signed_data, &version) ||
+      !CBS_get_asn1(&signed_data, NULL /* digests */, CBS_ASN1_SET) ||
+      !CBS_get_asn1(&signed_data, NULL /* content */, CBS_ASN1_SEQUENCE)) {
+    goto err;
   }
 
-  if (CBS_len(&version_bytes) < 1 || CBS_data(&version_bytes)[0] == 0) {
+  if (version < 1) {
     OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
                       X509_R_BAD_PKCS7_VERSION);
-    return 0;
+    goto err;
   }
 
-  if (!CBS_get_asn1_ber(&signed_data, &certificates,
-                        CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
+  if (!CBS_get_asn1(&signed_data, &certificates,
+                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
     OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
                       X509_R_NO_CERTIFICATES_INCLUDED);
-    return 0;
+    goto err;
   }
 
   while (CBS_len(&certificates) > 0) {
@@ -86,15 +99,21 @@
     sk_X509_push(out_certs, x509);
   }
 
-  return 1;
+  ret = 1;
 
 err:
-  while (sk_X509_num(out_certs) != initial_certs_len) {
-    X509 *x509 = sk_X509_pop(out_certs);
-    X509_free(x509);
+  if (der_bytes) {
+    OPENSSL_free(der_bytes);
   }
 
-  return 0;
+  if (!ret) {
+    while (sk_X509_num(out_certs) != initial_certs_len) {
+      X509 *x509 = sk_X509_pop(out_certs);
+      X509_free(x509);
+    }
+  }
+
+  return ret;
 }
 
 int PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) {
diff --git a/crypto/x509/pkcs7_test.c b/crypto/x509/pkcs7_test.c
index eb2668f..2e20c40 100644
--- a/crypto/x509/pkcs7_test.c
+++ b/crypto/x509/pkcs7_test.c
@@ -16,13 +16,14 @@
 #include <stdlib.h>
 
 #include <openssl/bytestring.h>
+#include <openssl/crypto.h>
 #include <openssl/stack.h>
 #include <openssl/x509.h>
 
 
-/* kPKCS7DER contains the certificate chain of mail.google.com, as saved by NSS
+/* kPKCS7NSS contains the certificate chain of mail.google.com, as saved by NSS
  * using the Chrome UI. */
-static const uint8_t kPKCS7DER[] = {
+static const uint8_t kPKCS7NSS[] = {
     0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
     0x02, 0xa0, 0x80, 0x30, 0x80, 0x02, 0x01, 0x01, 0x31, 0x00, 0x30, 0x80,
     0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x00,
@@ -267,7 +268,69 @@
     0x00, 0x00, 0x00,
 };
 
-static int test_reparse() {
+/* kPKCS7Windows is the Equifax root certificate, as exported by Windows 7. */
+static const uint8_t kPKCS7Windows[] = {
+    0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 0x82, 0x02, 0x9e, 0x02,
+    0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+    0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x02, 0x86, 0x30, 0x82, 0x02,
+    0x82, 0x30, 0x82, 0x01, 0xeb, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01,
+    0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+    0x01, 0x04, 0x05, 0x00, 0x30, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+    0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1c, 0x30, 0x1a, 0x06,
+    0x03, 0x55, 0x04, 0x0a, 0x13, 0x13, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61,
+    0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x49, 0x6e, 0x63,
+    0x2e, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1d,
+    0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75,
+    0x72, 0x65, 0x20, 0x65, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73,
+    0x20, 0x43, 0x41, 0x2d, 0x31, 0x30, 0x1e, 0x17, 0x0d, 0x39, 0x39, 0x30,
+    0x36, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d,
+    0x32, 0x30, 0x30, 0x36, 0x32, 0x31, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30,
+    0x5a, 0x30, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+    0x13, 0x02, 0x55, 0x53, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04,
+    0x0a, 0x13, 0x13, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x20, 0x53,
+    0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x26,
+    0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1d, 0x45, 0x71, 0x75,
+    0x69, 0x66, 0x61, 0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20,
+    0x65, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41,
+    0x2d, 0x31, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+    0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00,
+    0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xce, 0x2f, 0x19, 0xbc, 0x17,
+    0xb7, 0x77, 0xde, 0x93, 0xa9, 0x5f, 0x5a, 0x0d, 0x17, 0x4f, 0x34, 0x1a,
+    0x0c, 0x98, 0xf4, 0x22, 0xd9, 0x59, 0xd4, 0xc4, 0x68, 0x46, 0xf0, 0xb4,
+    0x35, 0xc5, 0x85, 0x03, 0x20, 0xc6, 0xaf, 0x45, 0xa5, 0x21, 0x51, 0x45,
+    0x41, 0xeb, 0x16, 0x58, 0x36, 0x32, 0x6f, 0xe2, 0x50, 0x62, 0x64, 0xf9,
+    0xfd, 0x51, 0x9c, 0xaa, 0x24, 0xd9, 0xf4, 0x9d, 0x83, 0x2a, 0x87, 0x0a,
+    0x21, 0xd3, 0x12, 0x38, 0x34, 0x6c, 0x8d, 0x00, 0x6e, 0x5a, 0xa0, 0xd9,
+    0x42, 0xee, 0x1a, 0x21, 0x95, 0xf9, 0x52, 0x4c, 0x55, 0x5a, 0xc5, 0x0f,
+    0x38, 0x4f, 0x46, 0xfa, 0x6d, 0xf8, 0x2e, 0x35, 0xd6, 0x1d, 0x7c, 0xeb,
+    0xe2, 0xf0, 0xb0, 0x75, 0x80, 0xc8, 0xa9, 0x13, 0xac, 0xbe, 0x88, 0xef,
+    0x3a, 0x6e, 0xab, 0x5f, 0x2a, 0x38, 0x62, 0x02, 0xb0, 0x12, 0x7b, 0xfe,
+    0x8f, 0xa6, 0x03, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x66, 0x30, 0x64,
+    0x30, 0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01,
+    0x01, 0x04, 0x04, 0x03, 0x02, 0x00, 0x07, 0x30, 0x0f, 0x06, 0x03, 0x55,
+    0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
+    0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
+    0x14, 0x4a, 0x78, 0x32, 0x52, 0x11, 0xdb, 0x59, 0x16, 0x36, 0x5e, 0xdf,
+    0xc1, 0x14, 0x36, 0x40, 0x6a, 0x47, 0x7c, 0x4c, 0xa1, 0x30, 0x1d, 0x06,
+    0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x4a, 0x78, 0x32, 0x52,
+    0x11, 0xdb, 0x59, 0x16, 0x36, 0x5e, 0xdf, 0xc1, 0x14, 0x36, 0x40, 0x6a,
+    0x47, 0x7c, 0x4c, 0xa1, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+    0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x75,
+    0x5b, 0xa8, 0x9b, 0x03, 0x11, 0xe6, 0xe9, 0x56, 0x4c, 0xcd, 0xf9, 0xa9,
+    0x4c, 0xc0, 0x0d, 0x9a, 0xf3, 0xcc, 0x65, 0x69, 0xe6, 0x25, 0x76, 0xcc,
+    0x59, 0xb7, 0xd6, 0x54, 0xc3, 0x1d, 0xcd, 0x99, 0xac, 0x19, 0xdd, 0xb4,
+    0x85, 0xd5, 0xe0, 0x3d, 0xfc, 0x62, 0x20, 0xa7, 0x84, 0x4b, 0x58, 0x65,
+    0xf1, 0xe2, 0xf9, 0x95, 0x21, 0x3f, 0xf5, 0xd4, 0x7e, 0x58, 0x1e, 0x47,
+    0x87, 0x54, 0x3e, 0x58, 0xa1, 0xb5, 0xb5, 0xf8, 0x2a, 0xef, 0x71, 0xe7,
+    0xbc, 0xc3, 0xf6, 0xb1, 0x49, 0x46, 0xe2, 0xd7, 0xa0, 0x6b, 0xe5, 0x56,
+    0x7a, 0x9a, 0x27, 0x98, 0x7c, 0x46, 0x62, 0x14, 0xe7, 0xc9, 0xfc, 0x6e,
+    0x03, 0x12, 0x79, 0x80, 0x38, 0x1d, 0x48, 0x82, 0x8d, 0xfc, 0x17, 0xfe,
+    0x2a, 0x96, 0x2b, 0xb5, 0x62, 0xa6, 0xa6, 0x3d, 0xbd, 0x7f, 0x92, 0x59,
+    0xcd, 0x5a, 0x2a, 0x82, 0xb2, 0x37, 0x79, 0x31, 0x00,
+};
+
+static int test_reparse(const uint8_t *der_bytes, size_t der_len) {
   CBS pkcs7;
   CBB cbb;
   STACK_OF(X509) *certs = sk_X509_new_null();
@@ -275,13 +338,13 @@
   uint8_t *result_data, *result2_data;
   size_t result_len, result2_len, i;
 
-  CBS_init(&pkcs7, kPKCS7DER, sizeof(kPKCS7DER));
+  CBS_init(&pkcs7, der_bytes, der_len);
   if (!PKCS7_get_certificates(certs, &pkcs7)) {
     fprintf(stderr, "PKCS7_get_certificates failed.\n");
     return 0;
   }
 
-  CBB_init(&cbb, sizeof(kPKCS7DER));
+  CBB_init(&cbb, der_len);
   if (!PKCS7_bundle_certificates(&cbb, certs) ||
       !CBB_finish(&cbb, &result_data, &result_len)) {
     fprintf(stderr, "PKCS7_bundle_certificates failed.\n");
@@ -309,7 +372,7 @@
     }
   }
 
-  CBB_init(&cbb, sizeof(kPKCS7DER));
+  CBB_init(&cbb, der_len);
   if (!PKCS7_bundle_certificates(&cbb, certs2) ||
       !CBB_finish(&cbb, &result2_data, &result2_len)) {
     fprintf(stderr,
@@ -331,8 +394,11 @@
   return 1;
 }
 
-int main() {
-  if (!test_reparse()) {
+int main(void) {
+  CRYPTO_library_init();
+
+  if (!test_reparse(kPKCS7NSS, sizeof(kPKCS7NSS)) ||
+      !test_reparse(kPKCS7Windows, sizeof(kPKCS7Windows))) {
     return 1;
   }
 
diff --git a/crypto/x509/x509_cmp.c b/crypto/x509/x509_cmp.c
index 57e6167..0974ef6 100644
--- a/crypto/x509/x509_cmp.c
+++ b/crypto/x509/x509_cmp.c
@@ -78,7 +78,6 @@
 	return(X509_NAME_cmp(ai->issuer,bi->issuer));
 	}
 
-#ifndef OPENSSL_NO_MD5
 unsigned long X509_issuer_and_serial_hash(X509 *a)
 	{
 	unsigned long ret=0;
@@ -105,7 +104,6 @@
 	EVP_MD_CTX_cleanup(&ctx);
 	return(ret);
 	}
-#endif
 	
 int X509_issuer_name_cmp(const X509 *a, const X509 *b)
 	{
@@ -122,12 +120,10 @@
 	return(X509_NAME_cmp(a->crl->issuer,b->crl->issuer));
 	}
 
-#ifndef OPENSSL_NO_SHA
 int X509_CRL_match(const X509_CRL *a, const X509_CRL *b)
 	{
 	return memcmp(a->sha1_hash, b->sha1_hash, 20);
 	}
-#endif
 
 X509_NAME *X509_get_issuer_name(X509 *a)
 	{
@@ -139,12 +135,10 @@
 	return(X509_NAME_hash(x->cert_info->issuer));
 	}
 
-#ifndef OPENSSL_NO_MD5
 unsigned long X509_issuer_name_hash_old(X509 *x)
 	{
 	return(X509_NAME_hash_old(x->cert_info->issuer));
 	}
-#endif
 
 X509_NAME *X509_get_subject_name(X509 *a)
 	{
@@ -161,14 +155,11 @@
 	return(X509_NAME_hash(x->cert_info->subject));
 	}
 
-#ifndef OPENSSL_NO_MD5
 unsigned long X509_subject_name_hash_old(X509 *x)
 	{
 	return(X509_NAME_hash_old(x->cert_info->subject));
 	}
-#endif
 
-#ifndef OPENSSL_NO_SHA
 /* Compare two certificates: they must be identical for
  * this to work. NB: Although "cmp" operations are generally
  * prototyped to take "const" arguments (eg. for use in
@@ -199,7 +190,6 @@
 		}
 	return rv;
 }
-#endif
 
 
 int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b)
@@ -249,7 +239,6 @@
 	}
 
 
-#ifndef OPENSSL_NO_MD5
 /* I now DER encode the name and hash it.  Since I cache the DER encoding,
  * this is reasonably efficient. */
 
@@ -273,7 +262,6 @@
 
 	return(ret);
 	}
-#endif
 
 /* Search a stack of X509 for a match */
 X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name,
@@ -364,7 +352,6 @@
  * flags.
  */
 
-#ifndef OPENSSL_NO_EC
 
 static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags)
 	{
@@ -484,19 +471,6 @@
 	return check_suite_b(pk, sign_nid, &flags);
 	}
 
-#else
-int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
-							unsigned long flags)
-	{
-	return 0;
-	}
-
-int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
-	{
-	return 0;
-	}
-
-#endif
 /* Not strictly speaking an "up_ref" as a STACK doesn't have a reference
  * count but it has the same effect by duping the STACK and upping the ref
  * of each X509 structure.
diff --git a/crypto/x509/x509_req.c b/crypto/x509/x509_req.c
index ccaf729..64f2c37 100644
--- a/crypto/x509/x509_req.c
+++ b/crypto/x509/x509_req.c
@@ -132,21 +132,17 @@
 		OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_KEY_TYPE_MISMATCH);
 		break;
 	case -2:
-#ifndef OPENSSL_NO_EC
 		if (k->type == EVP_PKEY_EC)
 			{
 			OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, ERR_R_EC_LIB);
 			break;
 			}
-#endif
-#ifndef OPENSSL_NO_DH
 		if (k->type == EVP_PKEY_DH)
 			{
 			/* No idea */
 			OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_CANT_CHECK_DH_KEY);
 			break;
 			}
-#endif
 	        OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_UNKNOWN_KEY_TYPE);
 		}
 
diff --git a/crypto/x509/x509spki.c b/crypto/x509/x509spki.c
index 0b0b4fa..03823b7 100644
--- a/crypto/x509/x509spki.c
+++ b/crypto/x509/x509spki.c
@@ -77,15 +77,19 @@
 {
 	unsigned char *spki_der;
 	const unsigned char *p;
-	int spki_len;
+	size_t spki_len;
 	NETSCAPE_SPKI *spki;
-	if(len <= 0) len = strlen(str);
-	if (!(spki_der = OPENSSL_malloc(len + 1))) {
+	if (len <= 0)
+		len = strlen(str);
+	if (!EVP_DecodedLength(&spki_len, len)) {
+		OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_decode, X509_R_BASE64_DECODE_ERROR);
+		return NULL;
+	}
+	if (!(spki_der = OPENSSL_malloc(spki_len))) {
 		OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_decode, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
-	spki_len = EVP_DecodeBlock(spki_der, (const unsigned char *)str, len);
-	if(spki_len < 0) {
+	if (!EVP_DecodeBase64(spki_der, &spki_len, spki_len, (const uint8_t *)str, len)) {
 		OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_decode, X509_R_BASE64_DECODE_ERROR);
 		OPENSSL_free(spki_der);
 		return NULL;
diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c
index 08cc79d..cbc46e2 100644
--- a/crypto/x509/x_all.c
+++ b/crypto/x509/x_all.c
@@ -345,7 +345,6 @@
 
 #endif
 
-#ifndef OPENSSL_NO_EC
 #ifndef OPENSSL_NO_FP_API
 EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey)
 	{
@@ -386,7 +385,6 @@
 	{
 	return ASN1_i2d_bio_of_const(EC_KEY,i2d_ECPrivateKey,bp,eckey);
 	}
-#endif
 
 
 int X509_pubkey_digest(const X509 *data, const EVP_MD *type, unsigned char *md,
diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c
index 2f77fd7..21785dc 100644
--- a/crypto/x509/x_crl.c
+++ b/crypto/x509/x_crl.c
@@ -234,9 +234,7 @@
 		break;
 
 		case ASN1_OP_D2I_POST:
-#ifndef OPENSSL_NO_SHA
 		X509_CRL_digest(crl, EVP_sha1(), crl->sha1_hash, NULL);
-#endif
 		crl->idp = X509_CRL_get_ext_d2i(crl,
 				NID_issuing_distribution_point, NULL, NULL);
 		if (crl->idp)
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
index 04275f7..c285aa6 100644
--- a/crypto/x509/x_pubkey.c
+++ b/crypto/x509/x_pubkey.c
@@ -300,7 +300,6 @@
 	}
 #endif
 
-#ifndef OPENSSL_NO_EC
 EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length)
 	{
 	EVP_PKEY *pkey;
@@ -336,7 +335,6 @@
 	EVP_PKEY_free(pktmp);
 	return(ret);
 	}
-#endif
 
 int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj,
 					int ptype, void *pval,
diff --git a/crypto/x509v3/tabtest.c b/crypto/x509v3/tabtest.c
index aa27c1e..f783938 100644
--- a/crypto/x509v3/tabtest.c
+++ b/crypto/x509v3/tabtest.c
@@ -62,14 +62,16 @@
 
 #include <stdio.h>
 
+#include <openssl/crypto.h>
 #include <openssl/x509v3.h>
 
 #include "ext_dat.h"
 
-int main()
+int main(void)
 {
 	int i, prev = -1, bad = 0;
 	const X509V3_EXT_METHOD **tmp;
+        CRYPTO_library_init();
 	i = sizeof(standard_exts) / sizeof(X509V3_EXT_METHOD *);
 	if(i != STANDARD_EXTENSION_COUNT)
 		fprintf(stderr, "Extension number invalid expecting %d\n", i);
diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c
index feebd9a..e08bdf4 100644
--- a/crypto/x509v3/v3_purp.c
+++ b/crypto/x509v3/v3_purp.c
@@ -361,9 +361,7 @@
 	size_t i;
 	int j;
 	if(x->ex_flags & EXFLAG_SET) return;
-#ifndef OPENSSL_NO_SHA
 	X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
-#endif
 	/* V1 should mean no extensions ... */
 	if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1;
 	/* Handle basic constraints */
diff --git a/crypto/x509v3/v3nametest.c b/crypto/x509v3/v3nametest.c
index d0d97ff..6a2ea85 100644
--- a/crypto/x509v3/v3nametest.c
+++ b/crypto/x509v3/v3nametest.c
@@ -55,6 +55,7 @@
 #include <string.h>
 #include <strings.h>
 
+#include <openssl/crypto.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
@@ -285,7 +286,7 @@
 	{NULL, NULL, 0}
 	};
 
-static X509 *make_cert()
+static X509 *make_cert(void)
 	{
 	X509 *ret = NULL;
 	X509 *crt = NULL;
@@ -391,6 +392,8 @@
 int
 main(void)
 	{
+	CRYPTO_library_init();
+
 	const struct set_name_fn *pfn = name_fns;
 	while (pfn->name) {
 		const char *const *pname = names;
diff --git a/include/openssl/aead.h b/include/openssl/aead.h
index 6f66e9c..ad2bbf7 100644
--- a/include/openssl/aead.h
+++ b/include/openssl/aead.h
@@ -99,7 +99,7 @@
 OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm(void);
 
 /* EVP_aead_chacha20_poly1305 is an AEAD built from ChaCha20 and Poly1305. */
-OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305();
+OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305(void);
 
 /* EVP_aead_aes_128_key_wrap is AES-128 Key Wrap mode. This should never be
  * used except to interoperate with existing systems that use this mode.
@@ -107,13 +107,13 @@
  * If the nonce is emtpy then the default nonce will be used, otherwise it must
  * be eight bytes long. The input must be a multiple of eight bytes long. No
  * additional data can be given to this mode. */
-OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_key_wrap();
+OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_key_wrap(void);
 
 /* EVP_aead_aes_256_key_wrap is AES-256 in Key Wrap mode. This should never be
  * used except to interoperate with existing systems that use this mode.
  *
  * See |EVP_aead_aes_128_key_wrap| for details. */
-OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_key_wrap();
+OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_key_wrap(void);
 
 /* EVP_has_aes_hardware returns one if we enable hardware support for fast and
  * constant-time AES-GCM. */
@@ -129,7 +129,7 @@
 /* EVP_aead_rc4_md5_tls uses RC4 and HMAC(MD5) in MAC-then-encrypt mode. Unlike
  * a standard AEAD, this is stateful as the RC4 state is carried from operation
  * to operation. */
-OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_tls();
+OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_tls(void);
 
 
 /* Utility functions. */
diff --git a/include/openssl/base.h b/include/openssl/base.h
index d79d63f..52cb1e9 100644
--- a/include/openssl/base.h
+++ b/include/openssl/base.h
@@ -63,6 +63,11 @@
 
 #include <openssl/opensslfeatures.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
 #if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64)
 #define OPENSSL_64_BIT
 #define OPENSSL_X86_64
@@ -184,8 +189,10 @@
 typedef struct evp_pkey_method_st EVP_PKEY_METHOD;
 typedef struct evp_pkey_st EVP_PKEY;
 typedef struct hmac_ctx_st HMAC_CTX;
+typedef struct md4_state_st MD4_CTX;
 typedef struct md5_state_st MD5_CTX;
 typedef struct pkcs8_priv_key_info_st PKCS8_PRIV_KEY_INFO;
+typedef struct pkcs12_st PKCS12;
 typedef struct rand_meth_st RAND_METHOD;
 typedef struct rsa_meth_st RSA_METHOD;
 typedef struct rsa_st RSA;
@@ -204,4 +211,8 @@
 typedef void *OPENSSL_BLOCK;
 
 
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
+
 #endif  /* OPENSSL_HEADER_BASE_H */
diff --git a/include/openssl/base64.h b/include/openssl/base64.h
index de94d8e..44f91eb 100644
--- a/include/openssl/base64.h
+++ b/include/openssl/base64.h
@@ -111,6 +111,19 @@
 
 /* Decoding */
 
+/* EVP_DecodedLength sets |*out_len| to the maximum number of bytes
+ * that will be needed to call |EVP_DecodeBase64| on an input of
+ * length |len|. */
+OPENSSL_EXPORT int EVP_DecodedLength(size_t *out_len, size_t len);
+
+/* EVP_DecodeBase64 decodes |in_len| bytes from base64 and writes
+ * |*out_len| bytes to |out|. |max_out| is the size of the output
+ * buffer. If it is not enough for the maximum output size, the
+ * operation fails. */
+OPENSSL_EXPORT int EVP_DecodeBase64(uint8_t *out, size_t *out_len,
+                                    size_t max_out, const uint8_t *in,
+                                    size_t in_len);
+
 /* EVP_DecodeInit initialises |*ctx|, which is typically stack allocated, for
  * a decoding operation.
  *
@@ -135,11 +148,13 @@
 OPENSSL_EXPORT int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out,
                                    int *out_len);
 
-/* EVP_DecodeBlock encodes |src_len| bytes from |src| and writes the result to
- * |dst|. It returns the number of bytes written or -1 on error.
+/* Deprecated: EVP_DecodeBlock encodes |src_len| bytes from |src| and
+ * writes the result to |dst|. It returns the number of bytes written
+ * or -1 on error.
  *
  * WARNING: EVP_DecodeBlock's return value does not take padding into
- * account. TODO(davidben): Possible or worth it to fix or add new API? */
+ * account. It also strips leading whitespace and trailing
+ * whitespace. */
 OPENSSL_EXPORT int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src,
                                    size_t src_len);
 
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index da0a356..547a36a 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -235,6 +235,10 @@
 /* BIO_pending returns the number of bytes pending to be read. */
 OPENSSL_EXPORT size_t BIO_pending(const BIO *bio);
 
+/* BIO_ctrl_pending calls |BIO_pending| and exists only for compatibility with
+ * OpenSSL. */
+OPENSSL_EXPORT size_t BIO_ctrl_pending(const BIO *bio);
+
 /* BIO_wpending returns the number of bytes pending to be written. */
 OPENSSL_EXPORT size_t BIO_wpending(const BIO *bio);
 
diff --git a/include/openssl/bn.h b/include/openssl/bn.h
index c9fba98..37a4bba 100644
--- a/include/openssl/bn.h
+++ b/include/openssl/bn.h
@@ -351,11 +351,11 @@
 /* BN_add_word adds |w| to |a|. It returns one on success and zero otherwise. */
 OPENSSL_EXPORT int BN_add_word(BIGNUM *a, BN_ULONG w);
 
-/* BN_sub sets |r| = |a| + |b|, where |r| must be a distinct pointer from |a|
+/* BN_sub sets |r| = |a| - |b|, where |r| must be a distinct pointer from |a|
  * and |b|. It returns one on success and zero on allocation failure. */
 OPENSSL_EXPORT int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
 
-/* BN_usub sets |r| = |a| + |b|, where |a| and |b| are non-negative integers,
+/* BN_usub sets |r| = |a| - |b|, where |a| and |b| are non-negative integers,
  * |b| < |a| and |r| must be a distinct pointer from |a| and |b|. It returns
  * one on success and zero on allocation failure. */
 OPENSSL_EXPORT int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index 6c0e799..1af20e8 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -122,14 +122,13 @@
 #define CBS_ASN1_BITSTRING 0x3
 #define CBS_ASN1_OCTETSTRING 0x4
 #define CBS_ASN1_OBJECT 0x6
+#define CBS_ASN1_ENUMERATED 0xa
 #define CBS_ASN1_SEQUENCE (0x10 | CBS_ASN1_CONSTRUCTED)
 #define CBS_ASN1_SET (0x11 | CBS_ASN1_CONSTRUCTED)
 
 #define CBS_ASN1_CONSTRUCTED 0x20
 #define CBS_ASN1_CONTEXT_SPECIFIC 0x80
 
-#define CBS_ASN1_ANY 0x10000
-
 /* CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not
  * including tag and length bytes) and advances |cbs| over it. The ASN.1
  * element must match |tag_value|. It returns one on success and zero
@@ -138,20 +137,28 @@
  * Tag numbers greater than 31 are not supported. */
 OPENSSL_EXPORT int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value);
 
-/* CBS_get_asn1_ber sets |*out| to the contents of BER-encoded, ASN.1 element
- * (not including tag and length bytes) and advances |cbs| over it. The ASN.1
- * element must match |tag_value|. It returns one on success and zero on error.
- *
- * The major difference between this function and |CBS_get_asn1| is that
- * indefinite-length elements may be processed by this function.
- *
- * Tag numbers greater than 31 are not supported. */
-OPENSSL_EXPORT int CBS_get_asn1_ber(CBS *cbs, CBS *out, unsigned tag_value);
-
 /* CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the
  * ASN.1 header bytes too. */
 OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value);
 
+/* CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from
+ * |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to
+ * the tag number and |*out_header_len| to the length of the ASN.1 header. If
+ * the element has indefinite length then |*out| will only contain the
+ * header. Each of |out|, |out_tag|, and |out_header_len| may be NULL to ignore
+ * the value.
+ *
+ * Tag numbers greater than 31 are not supported. */
+OPENSSL_EXPORT int CBS_get_any_asn1_element(CBS *cbs, CBS *out,
+                                            unsigned *out_tag,
+                                            size_t *out_header_len);
+
+/* CBS_get_asn1_uint64 gets an ASN.1 INTEGER from |cbs| using |CBS_get_asn1|
+ * and sets |*out| to its value. It returns one on success and zero on error,
+ * where error includes the integer being negative, or too large to represent
+ * in 64 bits. */
+OPENSSL_EXPORT int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out);
+
 
 /* CRYPTO ByteBuilder.
  *
diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h
index 92cec76..4eae33b 100644
--- a/include/openssl/cipher.h
+++ b/include/openssl/cipher.h
@@ -91,6 +91,12 @@
  * ciphertext. */
 OPENSSL_EXPORT const EVP_CIPHER *EVP_enc_null(void);
 
+/* EVP_rc2_40_cbc returns a cipher that implements 40-bit RC2 in CBC mode. This
+ * is obviously very, very weak and is included only in order to read PKCS#12
+ * files, which often encrypt the certificate chain using this cipher. It is
+ * deliberately not exported. */
+const EVP_CIPHER *EVP_rc2_40_cbc(void);
+
 /* EVP_get_cipherbynid returns the cipher corresponding to the given NID, or
  * NULL if no such cipher is known. */
 OPENSSL_EXPORT const EVP_CIPHER *EVP_get_cipherbynid(int nid);
@@ -255,6 +261,11 @@
  * to disable. */
 OPENSSL_EXPORT int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad);
 
+/* EVP_CIPHER_CTX_set_key_length sets the key length for |ctx|. This is only
+ * valid for ciphers that can take a variable length key. It returns one on
+ * success and zero on error. */
+OPENSSL_EXPORT int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *ctx, unsigned key_len);
+
 
 /* Cipher accessors. */
 
@@ -461,6 +472,7 @@
 #define CIPHER_F_aead_aes_key_wrap_seal 119
 #define CIPHER_F_aead_aes_key_wrap_init 120
 #define CIPHER_F_aead_aes_key_wrap_open 121
+#define CIPHER_F_EVP_CIPHER_CTX_set_key_length 122
 #define CIPHER_R_WRAP_MODE_NOT_ALLOWED 100
 #define CIPHER_R_AES_KEY_SETUP_FAILED 101
 #define CIPHER_R_INPUT_NOT_INITIALIZED 102
@@ -484,5 +496,6 @@
 #define CIPHER_R_UNSUPPORTED_INPUT_SIZE 120
 #define CIPHER_R_UNSUPPORTED_AD_SIZE 121
 #define CIPHER_R_UNSUPPORTED_NONCE_SIZE 122
+#define CIPHER_R_INVALID_KEY_LENGTH 123
 
 #endif  /* OPENSSL_HEADER_CIPHER_H */
diff --git a/include/openssl/conf.h b/include/openssl/conf.h
index 51c5525..c67e023 100644
--- a/include/openssl/conf.h
+++ b/include/openssl/conf.h
@@ -91,7 +91,7 @@
 
 
 /* NCONF_new returns a fresh, empty |CONF|, or NULL on error. */
-CONF *NCONF_new();
+CONF *NCONF_new(void);
 
 /* NCONF_free frees all the data owned by |conf| and then |conf| itself. */
 void NCONF_free(CONF *conf);
diff --git a/include/openssl/cpu.h b/include/openssl/cpu.h
index 3cc1e5e..5f60754 100644
--- a/include/openssl/cpu.h
+++ b/include/openssl/cpu.h
@@ -90,7 +90,7 @@
 /* CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. Note
  * that |OPENSSL_armcap_P| also exists and contains the same information in a
  * form that's easier for assembly to use. */
-OPENSSL_EXPORT char CRYPTO_is_NEON_capable();
+OPENSSL_EXPORT char CRYPTO_is_NEON_capable(void);
 
 /* CRYPTO_set_NEON_capable sets the return value of |CRYPTO_is_NEON_capable|.
  * By default, unless the code was compiled with |-mfpu=neon|, NEON is assumed
@@ -101,7 +101,7 @@
 /* CRYPTO_is_NEON_functional returns true if the current CPU has a /working/
  * NEON unit. Some phones have a NEON unit, but the Poly1305 NEON code causes
  * it to fail. See https://code.google.com/p/chromium/issues/detail?id=341598 */
-OPENSSL_EXPORT char CRYPTO_is_NEON_functional();
+OPENSSL_EXPORT char CRYPTO_is_NEON_functional(void);
 
 /* CRYPTO_set_NEON_functional sets the "NEON functional" flag. For
  * |CRYPTO_is_NEON_functional| to return true, both this flag and the NEON flag
diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h
index ddb97be..112431e 100644
--- a/include/openssl/crypto.h
+++ b/include/openssl/crypto.h
@@ -12,12 +12,34 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
-/* This header is provided in order to make compiling against code that expects
-   OpenSSL easier. */
+#ifndef OPENSSL_HEADER_CRYPTO_H
+#define OPENSSL_HEADER_CRYPTO_H
+
+#include <openssl/base.h>
+
+#include <openssl/mem.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* crypto.h contains functions for initializing the crypto library. */
+
+
+/* CRYPTO_library_init initializes the crypto library. It must be called if the
+ * library is built with BORINGSSL_NO_STATIC_INITIALIZER. Otherwise, it does
+ * nothing and a static initializer is used instead. */
+OPENSSL_EXPORT void CRYPTO_library_init(void);
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
 
 #define CRYPTO_F_CRYPTO_set_ex_data 100
 #define CRYPTO_F_get_class 101
 #define CRYPTO_F_get_new_index 102
 #define CRYPTO_F_get_func_pointers 103
 
-#include "mem.h"
+#endif  /* OPENSSL_HEADER_CRYPTO_H */
diff --git a/include/openssl/digest.h b/include/openssl/digest.h
index 76d6677..6d8a165 100644
--- a/include/openssl/digest.h
+++ b/include/openssl/digest.h
@@ -76,6 +76,7 @@
  * The following functions return |EVP_MD| objects that implement the named hash
  * function. */
 
+OPENSSL_EXPORT const EVP_MD *EVP_md4(void);
 OPENSSL_EXPORT const EVP_MD *EVP_md5(void);
 OPENSSL_EXPORT const EVP_MD *EVP_sha1(void);
 OPENSSL_EXPORT const EVP_MD *EVP_sha224(void);
@@ -199,6 +200,10 @@
  * |in|. It returns one on success and zero on error. */
 OPENSSL_EXPORT int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in);
 
+/* EVP_add_digest does nothing and returns one. It exists only for
+ * compatibility with OpenSSL. */
+OPENSSL_EXPORT int EVP_add_digest(const EVP_MD *digest);
+
 
 /* Digest operation accessors. */
 
diff --git a/include/openssl/dsa.h b/include/openssl/dsa.h
index c8156fa..5e71ae2 100644
--- a/include/openssl/dsa.h
+++ b/include/openssl/dsa.h
@@ -291,6 +291,14 @@
                                   BIGNUM **out_kinv, BIGNUM **out_r);
 
 
+/* Conversion. */
+
+/* DSA_dup_DH returns a |DH| constructed from the parameters of |dsa|. This is
+ * sometimes needed when Diffie-Hellman parameters are stored in the form of
+ * DSA parameters. It returns an allocated |DH| on success or NULL on error. */
+OPENSSL_EXPORT DH *DSA_dup_DH(const DSA *dsa);
+
+
 /* ex_data functions.
  *
  * These functions are wrappers. See |ex_data.h| for details. */
diff --git a/include/openssl/ec.h b/include/openssl/ec.h
index 55f1adf..47ecfca 100644
--- a/include/openssl/ec.h
+++ b/include/openssl/ec.h
@@ -133,6 +133,15 @@
 OPENSSL_EXPORT int EC_GROUP_get_cofactor(const EC_GROUP *group,
                                          BIGNUM *cofactor, BN_CTX *ctx);
 
+/* EC_GROUP_get_curve_GFp gets various parameters about a group. It sets
+ * |*out_p| to the order of the coordinate field and |*out_a| and |*out_b| to
+ * the parameters of the curve when expressed as y² = x³ + ax + b. Any of the
+ * output parameters can be NULL. It returns one on success and zero on
+ * error. */
+OPENSSL_EXPORT int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p,
+                                          BIGNUM *out_a, BIGNUM *out_b,
+                                          BN_CTX *ctx);
+
 /* EC_GROUP_get_curve_name returns a NID that identifies |group|. */
 OPENSSL_EXPORT int EC_GROUP_get_curve_name(const EC_GROUP *group);
 
@@ -351,6 +360,7 @@
 #define EC_F_EC_KEY_generate_key 155
 #define EC_F_ec_GFp_simple_set_compressed_coordinates 156
 #define EC_F_EC_POINT_add 157
+#define EC_F_EC_GROUP_get_curve_GFp 158
 #define EC_R_PKPARAMETERS2GROUP_FAILURE 100
 #define EC_R_NON_NAMED_CURVE 101
 #define EC_R_COORDINATES_OUT_OF_RANGE 102
diff --git a/include/openssl/engine.h b/include/openssl/engine.h
index f2916b3..367e98e 100644
--- a/include/openssl/engine.h
+++ b/include/openssl/engine.h
@@ -37,7 +37,7 @@
 
 /* ENGINE_new returns an empty ENGINE that uses the default method for all
  * algorithms. */
-OPENSSL_EXPORT ENGINE *ENGINE_new();
+OPENSSL_EXPORT ENGINE *ENGINE_new(void);
 
 /* ENGINE_free decrements the reference counts for all methods linked from
  * |engine| and frees |engine| itself. */
diff --git a/include/openssl/err.h b/include/openssl/err.h
index d8e7cd5..67a2601 100644
--- a/include/openssl/err.h
+++ b/include/openssl/err.h
@@ -146,11 +146,11 @@
  * values. If this is not called then the string forms of errors produced by
  * the functions below will contain numeric identifiers rather than
  * human-readable strings. */
-OPENSSL_EXPORT void ERR_load_crypto_strings();
+OPENSSL_EXPORT void ERR_load_crypto_strings(void);
 
 /* ERR_free_strings frees any internal error values that have been loaded. This
  * should only be called at process shutdown. */
-OPENSSL_EXPORT void ERR_free_strings();
+OPENSSL_EXPORT void ERR_free_strings(void);
 
 
 /* Reading and formatting errors. */
@@ -266,7 +266,7 @@
 /* ERR_get_next_error_library returns a value suitable for passing as the
  * |library| argument to |ERR_put_error|. This is intended for code that wishes
  * to push its own, non-standard errors to the error queue. */
-OPENSSL_EXPORT int ERR_get_next_error_library();
+OPENSSL_EXPORT int ERR_get_next_error_library(void);
 
 
 /* Private functions. */
@@ -515,7 +515,7 @@
 /* ERR_load_BIO_strings does nothing.
  *
  * TODO(fork): remove. libjingle calls this. */
-OPENSSL_EXPORT void ERR_load_BIO_strings();
+OPENSSL_EXPORT void ERR_load_BIO_strings(void);
 
 
 #if defined(__cplusplus)
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index edeb850..091912f 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -83,7 +83,7 @@
 
 /* EVP_PKEY_new creates a new, empty public-key object and returns it or NULL
  * on allocation failure. */
-OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_new();
+OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_new(void);
 
 /* EVP_PKEY_free frees all data referenced by |pkey| and then frees |pkey|
  * itself. */
@@ -708,10 +708,10 @@
 /* Private functions */
 
 /* OpenSSL_add_all_algorithms does nothing. */
-OPENSSL_EXPORT void OpenSSL_add_all_algorithms();
+OPENSSL_EXPORT void OpenSSL_add_all_algorithms(void);
 
 /* EVP_cleanup does nothing. */
-OPENSSL_EXPORT void EVP_cleanup();
+OPENSSL_EXPORT void EVP_cleanup(void);
 
 /* EVP_PKEY_asn1_find returns the ASN.1 method table for the given |nid|, which
  * should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is
diff --git a/include/openssl/md4.h b/include/openssl/md4.h
new file mode 100644
index 0000000..715adab
--- /dev/null
+++ b/include/openssl/md4.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_MD4_H
+#define OPENSSL_HEADER_MD4_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* MD4. */
+
+/* MD4_CBLOCK is the block size of MD4. */
+#define MD4_CBLOCK 64
+
+/* MD4_DIGEST_LENGTH is the length of an MD4 digest. */
+#define MD4_DIGEST_LENGTH 16
+
+/* MD41_Init initialises |md4| and returns one. */
+OPENSSL_EXPORT int MD4_Init(MD4_CTX *md4);
+
+/* MD4_Update adds |len| bytes from |data| to |md4| and returns one. */
+OPENSSL_EXPORT int MD4_Update(MD4_CTX *md4, const void *data, size_t len);
+
+/* MD4_Final adds the final padding to |md4| and writes the resulting digest to
+ * |md|, which must have at least |MD4_DIGEST_LENGTH| bytes of space. It
+ * returns one. */
+OPENSSL_EXPORT int MD4_Final(uint8_t *md, MD4_CTX *md4);
+
+/* MD4 writes the digest of |len| bytes from |data| to |out| and returns |out|.
+ * There must be at least |MD4_DIGEST_LENGTH| bytes of space in |out|. */
+OPENSSL_EXPORT uint8_t *MD4(const uint8_t *data, size_t len, uint8_t *out);
+
+/* MD4_Transform is a low-level function that performs a single, MD4 block
+ * transformation using the state from |md4| and 64 bytes from |block|. */
+OPENSSL_EXPORT void MD4_Transform(MD4_CTX *md4, const uint8_t *block);
+
+struct md4_state_st {
+  uint32_t A, B, C, D;
+  uint32_t Nl, Nh;
+  uint32_t data[16];
+  unsigned int num;
+};
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
+
+#endif  /* OPENSSL_HEADER_MD4_H */
diff --git a/include/openssl/md5.h b/include/openssl/md5.h
index dc800c0..efedc98 100644
--- a/include/openssl/md5.h
+++ b/include/openssl/md5.h
@@ -72,7 +72,7 @@
 /* MD5_DIGEST_LENGTH is the length of an MD5 digest. */
 #define MD5_DIGEST_LENGTH 16
 
-/* MD51_Init initialises |md5| and returns 1. */
+/* MD51_Init initialises |md5| and returns one. */
 OPENSSL_EXPORT int MD5_Init(MD5_CTX *md5);
 
 /* MD5_Update adds |len| bytes from |data| to |md5| and returns one. */
diff --git a/include/openssl/opensslfeatures.h b/include/openssl/opensslfeatures.h
index 6026a4b..4f5cb31 100644
--- a/include/openssl/opensslfeatures.h
+++ b/include/openssl/opensslfeatures.h
@@ -37,7 +37,6 @@
 #define OPENSSL_NO_JPAKE
 #define OPENSSL_NO_KRB5
 #define OPENSSL_NO_MD2
-#define OPENSSL_NO_MD4
 #define OPENSSL_NO_MDC2
 #define OPENSSL_NO_OCSP
 #define OPENSSL_NO_RC2
diff --git a/include/openssl/pem.h b/include/openssl/pem.h
index 3eaac0a..c18cedd 100644
--- a/include/openssl/pem.h
+++ b/include/openssl/pem.h
@@ -465,18 +465,14 @@
 
 #endif
 
-#ifndef OPENSSL_NO_EC
 DECLARE_PEM_rw_const(ECPKParameters, EC_GROUP)
 DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY)
 DECLARE_PEM_rw(EC_PUBKEY, EC_KEY)
-#endif
 
-#ifndef OPENSSL_NO_DH
 
 DECLARE_PEM_rw_const(DHparams, DH)
 DECLARE_PEM_write_const(DHxparams, DH)
 
-#endif
 
 DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY)
 
@@ -506,10 +502,8 @@
 OPENSSL_EXPORT EVP_PKEY *b2i_PublicKey_bio(BIO *in);
 OPENSSL_EXPORT int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk);
 OPENSSL_EXPORT int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk);
-#ifndef OPENSSL_NO_RC4
 OPENSSL_EXPORT EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u);
 OPENSSL_EXPORT int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel, pem_password_cb *cb, void *u);
-#endif
 
 
 void ERR_load_PEM_strings(void);
diff --git a/include/openssl/pkcs8.h b/include/openssl/pkcs8.h
index d871e57..8735387 100644
--- a/include/openssl/pkcs8.h
+++ b/include/openssl/pkcs8.h
@@ -59,6 +59,8 @@
 
 #include <openssl/base.h>
 
+#include <stdio.h>
+
 #include <openssl/x509.h>
 
 #if defined(__cplusplus)
@@ -67,11 +69,12 @@
 
 
 /* PKCS8_encrypt_pbe serializes and encrypts a PKCS8_PRIV_KEY_INFO with PBES1 as
- * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4 and
- * pbeWithSHAAnd3-KeyTripleDES-CBC, defined in PKCS #12, are supported. The
- * |pass_raw_len| bytes pointed to by |pass_raw| are used as the password. Note
- * that any conversions from the password as supplied in a text string (such as
- * those specified in B.1 of PKCS #12) must be performed by the caller.
+ * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4,
+ * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS
+ * #12, are supported. The |pass_raw_len| bytes pointed to by |pass_raw| are
+ * used as the password. Note that any conversions from the password as
+ * supplied in a text string (such as those specified in B.1 of PKCS #12) must
+ * be performed by the caller.
  *
  * If |salt| is NULL, a random salt of |salt_len| bytes is generated. If
  * |salt_len| is zero, a default salt length is used instead.
@@ -89,11 +92,12 @@
                                            PKCS8_PRIV_KEY_INFO *p8inf);
 
 /* PKCS8_decrypt_pbe decrypts and decodes a PKCS8_PRIV_KEY_INFO with PBES1 as
- * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4 and
- * pbeWithSHAAnd3-KeyTripleDES-CBC, defined in PKCS #12, are supported. The
- * |pass_raw_len| bytes pointed to by |pass_raw| are used as the password. Note
- * that any conversions from the password as supplied in a text string (such as
- * those specified in B.1 of PKCS #12) must be performed by the caller.
+ * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4,
+ * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS
+ * #12, are supported. The |pass_raw_len| bytes pointed to by |pass_raw| are
+ * used as the password. Note that any conversions from the password as
+ * supplied in a text string (such as those specified in B.1 of PKCS #12) must
+ * be performed by the caller.
  *
  * The resulting structure must be freed by the caller. */
 OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8,
@@ -119,6 +123,50 @@
                                                   const char *pass,
                                                   int pass_len);
 
+/* PKCS12_get_key_and_certs parses a PKCS#12 structure from |in|, authenticates
+ * and decrypts it using |password|, sets |*out_key| to the included private
+ * key and appends the included certificates to |out_certs|. It returns one on
+ * success and zero on error. The caller takes ownership of the outputs. */
+OPENSSL_EXPORT int PKCS12_get_key_and_certs(EVP_PKEY **out_key,
+                                            STACK_OF(X509) *out_certs,
+                                            CBS *in, const char *password);
+
+
+/* Deprecated functions. */
+
+/* PKCS12_PBE_add does nothing. It exists for compatibility with OpenSSL. */
+OPENSSL_EXPORT void PKCS12_PBE_add();
+
+/* d2i_PKCS12 is a dummy function that copies |*ber_bytes| into a
+ * |PKCS12| structure. The |out_p12| argument must be NULL. On exit,
+ * |*ber_bytes| will be advanced by |ber_len|. It returns a fresh |PKCS12|
+ * structure or NULL on error.
+ *
+ * Note: unlike other d2i functions, |d2i_PKCS12| will always consume |ber_len|
+ * bytes.*/
+OPENSSL_EXPORT PKCS12 *d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes,
+                                  size_t ber_len);
+
+/* d2i_PKCS12_bio acts like |d2i_PKCS12| but reads from a |BIO|. */
+OPENSSL_EXPORT PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12);
+
+/* d2i_PKCS12_fp acts like |d2i_PKCS12| but reads from a |FILE|. */
+OPENSSL_EXPORT PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12);
+
+/* PKCS12_parse calls |PKCS12_get_key_and_certs| on the ASN.1 data stored in
+ * |p12|. The |out_pkey| and |out_cert| arguments must not be NULL and, on
+ * successful exit, the private key and first certificate will be stored in
+ * them. The |out_ca_certs| argument may be NULL but, if not, then any extra
+ * certificates will be appended to |*out_ca_certs|. If |*out_ca_certs| is NULL
+ * then it will be set to a freshly allocated stack containing the extra certs.
+ *
+ * It returns one on success and zero on error. */
+OPENSSL_EXPORT int PKCS12_parse(const PKCS12 *p12, const char *password,
+                                EVP_PKEY **out_pkey, X509 **out_cert,
+                                STACK_OF(X509) **out_ca_certs);
+
+/* PKCS12_free frees |p12| and its contents. */
+OPENSSL_EXPORT void PKCS12_free(PKCS12 *p12);
 
 #if defined(__cplusplus)
 }  /* extern C */
@@ -141,6 +189,10 @@
 #define PKCS8_F_pkcs12_key_gen_raw 114
 #define PKCS8_F_PKCS8_decrypt 115
 #define PKCS8_F_PKCS8_encrypt_pbe 116
+#define PKCS8_F_PKCS12_parse 117
+#define PKCS8_F_PKCS12_handle_content_info 118
+#define PKCS8_F_PKCS12_handle_content_infos 119
+#define PKCS8_F_PKCS12_get_key_and_certs 120
 #define PKCS8_R_ERROR_SETTING_CIPHER_PARAMS 100
 #define PKCS8_R_PRIVATE_KEY_ENCODE_ERROR 101
 #define PKCS8_R_UNKNOWN_ALGORITHM 102
@@ -158,5 +210,14 @@
 #define PKCS8_R_METHOD_NOT_SUPPORTED 114
 #define PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 115
 #define PKCS8_R_KEY_GEN_ERROR 116
+#define PKCS8_R_BAD_PKCS12_DATA 117
+#define PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED 118
+#define PKCS8_R_BAD_PKCS12_VERSION 119
+#define PKCS8_R_PKCS12_TOO_DEEPLY_NESTED 120
+#define PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12 121
+#define PKCS8_R_UNKNOWN_HASH 122
+#define PKCS8_R_BAD_MAC 123
+#define PKCS8_R_MISSING_MAC 124
+#define PKCS8_R_INCORRECT_PASSWORD 125
 
 #endif  /* OPENSSL_HEADER_PKCS8_H */
diff --git a/include/openssl/pqueue.h b/include/openssl/pqueue.h
index 8ad023a..ceb1fa2 100644
--- a/include/openssl/pqueue.h
+++ b/include/openssl/pqueue.h
@@ -84,11 +84,11 @@
 
 /* pqueue_new allocates a fresh, empty priority queue object and returns it, or
  * NULL on error. */
-pqueue pqueue_new();
+OPENSSL_EXPORT pqueue pqueue_new(void);
 
 /* pqueue_free frees |pq| but not any of the items it points to. Thus |pq| must
  * be empty or a memory leak will occur. */
-void pqueue_free(pqueue pq);
+OPENSSL_EXPORT void pqueue_free(pqueue pq);
 
 
 /* Creating and freeing items. */
@@ -97,47 +97,46 @@
  * has a priority given by |prio64be|, which is a 64-bit, unsigned number
  * expressed in big-endian form. It returns the fresh item, or NULL on
  * error. */
-pitem *pitem_new(uint8_t prio64be[8], void *data);
+OPENSSL_EXPORT pitem *pitem_new(uint8_t prio64be[8], void *data);
 
 /* pitem_free frees |item|, but not any data that it points to. */
-void pitem_free(pitem *item);
+OPENSSL_EXPORT void pitem_free(pitem *item);
 
 
 /* Queue accessor functions */
 
 /* pqueue_peek returns the item with the smallest priority from |pq|, or NULL
  * if empty. */
-pitem *pqueue_peek(pqueue pq);
+OPENSSL_EXPORT pitem *pqueue_peek(pqueue pq);
 
 /* pqueue_find returns the item whose priority matches |prio64be| or NULL if no
  * such item exists. */
-pitem *pqueue_find(pqueue pq, unsigned char *prio64be);
+OPENSSL_EXPORT pitem *pqueue_find(pqueue pq, uint8_t *prio64be);
 
 
 /* Queue mutation functions */
 
 /* pqueue_insert inserts |item| into |pq| and returns item. */
-pitem *pqueue_insert(pqueue pq, pitem *item);
+OPENSSL_EXPORT pitem *pqueue_insert(pqueue pq, pitem *item);
 
 /* pqueue_pop takes the item with the least priority from |pq| and returns it,
  * or NULL if |pq| is empty. */
-pitem *pqueue_pop(pqueue pq);
+OPENSSL_EXPORT pitem *pqueue_pop(pqueue pq);
 
 /* pqueue_size returns the number of items in |pq|. */
-size_t pqueue_size(pqueue pq);
+OPENSSL_EXPORT size_t pqueue_size(pqueue pq);
 
 
 /* Iterating */
 
 /* pqueue_iterator returns an iterator that can be used to iterate over the
  * contents of the queue. */
-pitem *pqueue_iterator(pqueue pq);
+OPENSSL_EXPORT piterator pqueue_iterator(pqueue pq);
 
 /* pqueue_next returns the current value of |iter| and advances it to the next
  * position. If the iterator has advanced over all the elements, it returns
  * NULL. */
-pitem *pqueue_next(piterator *iter);
-
+OPENSSL_EXPORT pitem *pqueue_next(piterator *iter);
 
 
 #if defined(__cplusplus)
diff --git a/include/openssl/rand.h b/include/openssl/rand.h
index d17c3ea..5a84a89 100644
--- a/include/openssl/rand.h
+++ b/include/openssl/rand.h
@@ -28,7 +28,7 @@
 
 /* RAND_cleanup frees any resources used by the RNG. This is not safe if other
  * threads might still be calling |RAND_bytes|. */
-OPENSSL_EXPORT void RAND_cleanup();
+OPENSSL_EXPORT void RAND_cleanup(void);
 
 
 /* Deprecated functions */
diff --git a/include/openssl/srtp.h b/include/openssl/srtp.h
index 3e29e5d..c11608e 100644
--- a/include/openssl/srtp.h
+++ b/include/openssl/srtp.h
@@ -130,9 +130,23 @@
 #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.
+ *
+ * WARNING: this function is dangerous because it breaks the usual
+ * return value convention. */
 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.
+ *
+ * WARNING: this function is dangerous because it breaks the usual
+ * return value convention. */
 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) *
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 3c64237..48ad549 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -342,7 +342,7 @@
 	int (*ssl_renegotiate)(SSL *s);
 	int (*ssl_renegotiate_check)(SSL *s);
 	long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long
-		max, int *ok);
+		max, int hash_message, int *ok);
 	int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len, 
 		int peek);
 	int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
@@ -380,6 +380,9 @@
  *	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 :-).
@@ -439,16 +442,22 @@
 	 * efficient and to implement a maximum cache size. */
 	struct ssl_session_st *prev,*next;
 	char *tlsext_hostname;
-#ifndef OPENSSL_NO_EC
 	size_t tlsext_ecpointformatlist_length;
 	unsigned char *tlsext_ecpointformatlist; /* peer's list */
 	size_t tlsext_ellipticcurvelist_length;
 	uint16_t *tlsext_ellipticcurvelist; /* peer's list */
-#endif /* OPENSSL_NO_EC */
 	/* RFC4507 info */
 	uint8_t *tlsext_tick;	/* Session ticket */
 	size_t tlsext_ticklen;		/* Session ticket length */
 	uint32_t tlsext_tick_lifetime_hint;	/* Session lifetime hint in seconds */
+
+	size_t tlsext_signed_cert_timestamp_list_length;
+	uint8_t *tlsext_signed_cert_timestamp_list; /* Server's list. */
+
+	/* The OCSP response that came with the session. */
+	size_t ocsp_response_length;
+	uint8_t *ocsp_response;
+
 	char peer_sha256_valid;		/* Non-zero if peer_sha256 is valid */
 	unsigned char peer_sha256[SHA256_DIGEST_LENGTH];  /* SHA256 of peer certificate */
 
@@ -462,33 +471,21 @@
 
 #endif
 
-#define SSL_OP_MICROSOFT_SESS_ID_BUG			0x00000001L
-#define SSL_OP_NETSCAPE_CHALLENGE_BUG			0x00000002L
-/* Allow initial connection to servers that don't support RI */
+/* SSL_OP_LEGACY_SERVER_CONNECT allows initial connection to servers
+ * that don't support RI */
 #define SSL_OP_LEGACY_SERVER_CONNECT			0x00000004L
-#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG		0x00000010L
+
+/* SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER allows for record sizes
+ * SSL3_RT_MAX_EXTRA bytes above the maximum record size. */
 #define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER		0x00000020L
-#define SSL_OP_SAFARI_ECDHE_ECDSA_BUG			0x00000040L
+
+/* SSL_OP_TLS_D5_BUG accepts an RSAClientKeyExchange in TLS encoded as
+ * SSL3, without a length prefix. */
 #define SSL_OP_TLS_D5_BUG				0x00000100L
-#define SSL_OP_TLS_BLOCK_PADDING_BUG			0x00000200L
 
-/* Hasn't done anything since OpenSSL 0.9.7h, retained for compatibility */
-#define SSL_OP_MSIE_SSLV2_RSA_PADDING			0x0
-
-/* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS is vestigial. Previously it disabled the
- * insertion of empty records in CBC mode, but the empty records were commonly
- * misinterpreted as EOF by other TLS stacks and so this was disabled by
- * SSL_OP_ALL.
- *
- * This has been replaced by 1/n-1 record splitting, which is enabled by
- * SSL_MODE_CBC_RECORD_SPLITTING in SSL_set_mode. This involves sending a
- * one-byte record rather than an empty record and has much better
- * compatibility. */
-#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS              0x00000800L /* added in 0.9.6e */
-
-/* SSL_OP_ALL: various bug workarounds that should be rather harmless.
- *             This used to be 0x000FFFFFL before 0.9.7. */
-#define SSL_OP_ALL					0x80000BFFL
+/* SSL_OP_ALL enables the above bug workarounds that should be rather
+ * harmless. */
+#define SSL_OP_ALL					0x00000BFFL
 
 /* DTLS options */
 #define SSL_OP_NO_QUERY_MTU                 0x00001000L
@@ -525,13 +522,13 @@
 #define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|\
 	SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2)
 
-/* These next two were never actually used for anything since SSLeay
- * zap so we have some more flags.
- */
-/* The next flag deliberately changes the ciphertest, this is a check
- * for the PKCS#1 attack */
-#define SSL_OP_PKCS1_CHECK_1				0x0
-#define SSL_OP_PKCS1_CHECK_2				0x0
+/* The following flags do nothing and are included only to make it easier to
+ * compile code with BoringSSL. */
+#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS		0
+#define SSL_OP_MICROSOFT_SESS_ID_BUG			0
+#define SSL_OP_NETSCAPE_CHALLENGE_BUG			0
+#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG		0
+#define SSL_OP_TLS_BLOCK_PADDING_BUG			0
 
 /* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
  * when just a single record has been written): */
@@ -680,6 +677,14 @@
 #define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
 #define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
 
+/* SSL_CTX_set_keylog_bio sets configures all SSL objects attached to |ctx| to
+ * log session material to |keylog_bio|. This is intended for debugging use with
+ * tools like Wireshark. |ctx| takes ownership of |keylog_bio|.
+ *
+ * The format is described in
+ * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. */
+OPENSSL_EXPORT void SSL_CTX_set_keylog_bio(SSL_CTX *ctx, BIO *keylog_bio);
+
 
 struct ssl_aead_ctx_st;
 typedef struct ssl_aead_ctx_st SSL_AEAD_CTX;
@@ -778,7 +783,7 @@
 struct ssl_cipher_preference_list_st
 	{
 	STACK_OF(SSL_CIPHER) *ciphers;
-	unsigned char *in_group_flags;
+	uint8_t *in_group_flags;
 	};
 
 struct ssl_ctx_st
@@ -960,7 +965,6 @@
 	 * memory and session space. Only effective on the server side. */
 	char retain_only_sha256_of_client_certs;
 
-# ifndef OPENSSL_NO_NEXTPROTONEG
 	/* Next protocol negotiation information */
 	/* (for experimental NPN extension). */
 
@@ -977,7 +981,6 @@
 				    unsigned int inlen,
 				    void *arg);
 	void *next_proto_select_cb_arg;
-# endif
 
 	/* ALPN information
 	 * (we are in the process of transitioning from NPN to ALPN.) */
@@ -1005,13 +1008,11 @@
 
         /* SRTP profiles we are willing to do from RFC 5764 */
 	STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
-# ifndef OPENSSL_NO_EC
 	/* EC extension values inherited by SSL structure */
 	size_t tlsext_ecpointformatlist_length;
 	uint8_t *tlsext_ecpointformatlist;
 	size_t tlsext_ellipticcurvelist_length;
 	uint16_t *tlsext_ellipticcurvelist;
-# endif /* OPENSSL_NO_EC */
 
 	/* If true, a client will advertise the Channel ID extension and a
 	 * server will echo it. */
@@ -1023,6 +1024,16 @@
 	/* The client's Channel ID private key. */
 	EVP_PKEY *tlsext_channel_id_private;
 
+	/* If true, a client will request certificate timestamps. */
+	char signed_cert_timestamps_enabled;
+
+	/* If true, a client will request a stapled OCSP response. */
+	char ocsp_stapling_enabled;
+
+	/* If not NULL, session key material will be logged to this BIO for
+	 * debugging purposes. The format matches NSS's and is readable by
+	 * Wireshark. */
+	BIO *keylog_bio;
 	};
 
 #endif
@@ -1087,7 +1098,44 @@
 OPENSSL_EXPORT void (*SSL_CTX_get_channel_id_cb(SSL_CTX *ctx))(SSL *ssl, EVP_PKEY **pkey);
 OPENSSL_EXPORT void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb)(SSL *ssl, uint8_t *cookie, size_t *cookie_len));
 OPENSSL_EXPORT void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL *ssl, const uint8_t *cookie, size_t cookie_len));
-#ifndef OPENSSL_NO_NEXTPROTONEG
+
+
+/* SSL_enable_signed_cert_timestamps causes |ssl| (which must be the client
+ * end of a connection) to request SCTs from the server.
+ * See https://tools.ietf.org/html/rfc6962.
+ * Returns 1 on success. */
+OPENSSL_EXPORT int SSL_enable_signed_cert_timestamps(SSL *ssl);
+
+/* SSL_CTX_enable_signed_cert_timestamps enables SCT requests on all
+ * client SSL objects created from |ctx|. */
+OPENSSL_EXPORT void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx);
+
+/* SSL_enable_signed_cert_timestamps causes |ssl| (which must be the client end
+ * of a connection) to request a stapled OCSP response from the server. Returns
+ * 1 on success. */
+OPENSSL_EXPORT int SSL_enable_ocsp_stapling(SSL *ssl);
+
+/* SSL_CTX_enable_ocsp_stapling enables OCSP stapling on all client SSL objects
+ * created from |ctx|. */
+OPENSSL_EXPORT void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx);
+
+/* SSL_get0_signed_cert_timestamp_list sets |*out| and |*out_len| to point to
+ * |*out_len| bytes of SCT information from the server. This is only valid if
+ * |ssl| is a client. The SCT information is a SignedCertificateTimestampList
+ * (including the two leading length bytes).
+ * See https://tools.ietf.org/html/rfc6962#section-3.3
+ * If no SCT was received then |*out_len| will be zero on return.
+ *
+ * WARNING: the returned data is not guaranteed to be well formed. */
+OPENSSL_EXPORT void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, uint8_t **out, size_t *out_len);
+
+/* SSL_get0_ocsp_response sets |*out| and |*out_len| to point to |*out_len|
+ * bytes of an OCSP response from the server. This is the DER encoding of an
+ * OCSPResponse type as defined in RFC 2560.
+ *
+ * WARNING: the returned data is not guaranteed to be well formed. */
+OPENSSL_EXPORT void SSL_get0_ocsp_response(const SSL *ssl, uint8_t **out, size_t *out_len);
+
 OPENSSL_EXPORT void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s,
 					   int (*cb) (SSL *ssl,
 						      const unsigned char **out,
@@ -1101,7 +1149,6 @@
 				      void *arg);
 OPENSSL_EXPORT void SSL_get0_next_proto_negotiated(const SSL *s,
 				    const uint8_t **data, unsigned *len);
-#endif
 
 OPENSSL_EXPORT int SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
 			  const unsigned char *in, unsigned int inlen,
@@ -1329,31 +1376,15 @@
 					void *arg);
 	void *tlsext_debug_arg;
 	char *tlsext_hostname;
-	int servername_done;   /* no further mod of servername 
-	                          0 : call the servername extension callback.
-	                          1 : prepare 2, allow last ack just after in server callback.
-	                          2 : don't call servername callback, no ack in server hello
-	                       */
-	/* certificate status request info */
-	/* Status type or -1 if no status type */
-	int tlsext_status_type;
-	/* Expect OCSP CertificateStatus message */
-	int tlsext_status_expected;
-	/* OCSP status request only */
-	STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids;
-	X509_EXTENSIONS *tlsext_ocsp_exts;
-	/* OCSP response received or to be sent */
-	uint8_t *tlsext_ocsp_resp;
-	int tlsext_ocsp_resplen;
-
+	/* should_ack_sni is true if the SNI extension should be acked. This is
+	 * only used by a server. */
+	char should_ack_sni;
 	/* RFC4507 session ticket expected to be received or sent */
 	int tlsext_ticket_expected;
-#ifndef OPENSSL_NO_EC
 	size_t tlsext_ecpointformatlist_length;
 	uint8_t *tlsext_ecpointformatlist; /* our list */
 	size_t tlsext_ellipticcurvelist_length;
 	uint16_t *tlsext_ellipticcurvelist; /* our list */
-#endif /* OPENSSL_NO_EC */
 
 	/* TLS Session Ticket extension override */
 	TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
@@ -1368,7 +1399,6 @@
 
 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
 
-#ifndef OPENSSL_NO_NEXTPROTONEG
 	/* Next protocol negotiation. For the client, this is the protocol that
 	 * we sent in NextProtocol and is set when handling ServerHello
 	 * extensions.
@@ -1378,9 +1408,6 @@
 	 * before the Finished message. */
 	uint8_t *next_proto_negotiated;
 	size_t next_proto_negotiated_len;
-#endif
-
-#define session_ctx initial_ctx
 
 	STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;  /* What we'll do */
 	SRTP_PROTECTION_PROFILE *srtp_profile;            /* What's been chosen */
@@ -1392,6 +1419,14 @@
 	/* The client's Channel ID private key. */
 	EVP_PKEY *tlsext_channel_id_private;
 
+	/* Enable signed certificate time stamps. Currently client only. */
+	char signed_cert_timestamps_enabled;
+
+	/* Enable OCSP stapling. Currently client only.
+	 * TODO(davidben): Add a server-side implementation when it becomes
+	 * necesary. */
+	char ocsp_stapling_enabled;
+
 	/* For a client, this contains the list of supported protocols in wire
 	 * format. */
 	unsigned char* alpn_client_proto_list;
@@ -1631,13 +1666,6 @@
 #define SSL_CTRL_SET_TLSEXT_TICKET_KEYS		59
 #define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB	63
 #define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG	64
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE	65
-#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS	66
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS	67
-#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS	68
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS	69
-#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP	70
-#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP	71
 
 #define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB	72
 
@@ -2197,22 +2225,18 @@
 OPENSSL_EXPORT void SSL_set_tmp_rsa_callback(SSL *ssl,
 				  RSA *(*cb)(SSL *ssl,int is_export,
 					     int keylength));
-#ifndef OPENSSL_NO_DH
 OPENSSL_EXPORT void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,
 				 DH *(*dh)(SSL *ssl,int is_export,
 					   int keylength));
 OPENSSL_EXPORT void SSL_set_tmp_dh_callback(SSL *ssl,
 				 DH *(*dh)(SSL *ssl,int is_export,
 					   int keylength));
-#endif
-#ifndef OPENSSL_NO_ECDH
 OPENSSL_EXPORT void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,
 				 EC_KEY *(*ecdh)(SSL *ssl,int is_export,
 					   int keylength));
 OPENSSL_EXPORT void SSL_set_tmp_ecdh_callback(SSL *ssl,
 				 EC_KEY *(*ecdh)(SSL *ssl,int is_export,
 					   int keylength));
-#endif
 
 OPENSSL_EXPORT const void *SSL_get_current_compression(SSL *s);
 OPENSSL_EXPORT const void *SSL_get_current_expansion(SSL *s);
@@ -2352,7 +2376,7 @@
 #define SSL_F_tls1_setup_key_block 183
 #define SSL_F_SSL_set_fd 184
 #define SSL_F_SSL_check_private_key 185
-#define SSL_F_ssl3_send_client_verify 186
+#define SSL_F_ssl3_send_cert_verify 186
 #define SSL_F_ssl3_write_pending 187
 #define SSL_F_ssl_cert_inst 188
 #define SSL_F_ssl3_change_cipher_state 189
@@ -2379,7 +2403,7 @@
 #define SSL_F_SSL_SESSION_new 210
 #define SSL_F_check_suiteb_cipher_list 211
 #define SSL_F_ssl_scan_clienthello_tlsext 212
-#define SSL_F_ssl3_client_hello 213
+#define SSL_F_ssl3_send_client_hello 213
 #define SSL_F_SSL_use_RSAPrivateKey_ASN1 214
 #define SSL_F_ssl3_ctrl 215
 #define SSL_F_ssl3_setup_write_buffer 216
@@ -2450,6 +2474,9 @@
 #define SSL_F_tls1_check_duplicate_extensions 281
 #define SSL_F_ssl3_expect_change_cipher_spec 282
 #define SSL_F_ssl23_get_v2_client_hello 283
+#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_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
@@ -2763,6 +2790,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_SSLV3_ALERT_CLOSE_NOTIFY 1000
 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
 #define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021
@@ -2784,6 +2812,7 @@
 #define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070
 #define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071
 #define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080
+#define SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK 1086
 #define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090
 #define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100
 #define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index a470b89..3aea752 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -340,8 +340,6 @@
 
 #define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS	0x0001
 #define SSL3_FLAGS_POP_BUFFER			0x0004
-#define TLS1_FLAGS_TLS_PADDING_BUG		0x0008
-#define TLS1_FLAGS_KEEP_HANDSHAKE		0x0020
 /* TODO(davidben): This flag can probably be merged into s3->change_cipher_spec
  * to something tri-state. (Normal / Expect CCS / Between CCS and Finished). */
 #define SSL3_FLAGS_EXPECT_CCS			0x0080
@@ -422,9 +420,6 @@
 	 * established connection state in case of renegotiations.
 	 */
 	struct	{
-		/* actually only needs to be 16+20 */
-		unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
-
 		/* actually only need to be 16+20 for SSLv3 and 12 for TLS */
 		unsigned char finish_md[EVP_MAX_MD_SIZE*2];
 		int finish_md_len;
@@ -436,13 +431,9 @@
 
 		/* used to hold the new cipher we are going to use */
 		const SSL_CIPHER *new_cipher;
-#ifndef OPENSSL_NO_DH
 		DH *dh;
-#endif
 
-#ifndef OPENSSL_NO_ECDH
 		EC_KEY *ecdh; /* holds short lived ECDH key */
-#endif
 
 		/* used when SSL_ST_FLUSH_DATA is entered */
 		int next_state;			
@@ -477,6 +468,11 @@
 		/* Server-only: cert_request is true if a client certificate was
 		 * requested. */
 		int cert_request;
+
+		/* certificate_status_expected is true if OCSP stapling was
+		 * negotiated and the server is expected to send a
+		 * CertificateStatus message. */
+		char certificate_status_expected;
 		} tmp;
 
         /* Connection binding to prevent renegotiation attacks */
@@ -486,10 +482,8 @@
         unsigned char previous_server_finished_len;
         int send_connection_binding; /* TODOEKR */
 
-#ifndef OPENSSL_NO_NEXTPROTONEG
 	/* Set if we saw the Next Protocol Negotiation extension from our peer. */
 	int next_proto_neg_seen;
-#endif
 
 	/* ALPN information
 	 * (we are in the process of transitioning from NPN to ALPN.) */
@@ -552,10 +546,8 @@
 #define SSL3_ST_CW_CERT_VRFY_B		(0x191|SSL_ST_CONNECT)
 #define SSL3_ST_CW_CHANGE_A		(0x1A0|SSL_ST_CONNECT)
 #define SSL3_ST_CW_CHANGE_B		(0x1A1|SSL_ST_CONNECT)
-#ifndef OPENSSL_NO_NEXTPROTONEG
 #define SSL3_ST_CW_NEXT_PROTO_A		(0x200|SSL_ST_CONNECT)
 #define SSL3_ST_CW_NEXT_PROTO_B		(0x201|SSL_ST_CONNECT)
-#endif
 #define SSL3_ST_CW_CHANNEL_ID_A		(0x220|SSL_ST_CONNECT)
 #define SSL3_ST_CW_CHANNEL_ID_B		(0x221|SSL_ST_CONNECT)
 #define SSL3_ST_CW_FINISHED_A		(0x1B0|SSL_ST_CONNECT)
@@ -602,10 +594,8 @@
 #define SSL3_ST_SR_CERT_VRFY_A		(0x1A0|SSL_ST_ACCEPT)
 #define SSL3_ST_SR_CERT_VRFY_B		(0x1A1|SSL_ST_ACCEPT)
 #define SSL3_ST_SR_CHANGE		(0x1B0|SSL_ST_ACCEPT)
-#ifndef OPENSSL_NO_NEXTPROTONEG
 #define SSL3_ST_SR_NEXT_PROTO_A		(0x210|SSL_ST_ACCEPT)
 #define SSL3_ST_SR_NEXT_PROTO_B		(0x211|SSL_ST_ACCEPT)
-#endif
 #define SSL3_ST_SR_CHANNEL_ID_A		(0x230|SSL_ST_ACCEPT)
 #define SSL3_ST_SR_CHANNEL_ID_B		(0x231|SSL_ST_ACCEPT)
 #define SSL3_ST_SR_FINISHED_A		(0x1C0|SSL_ST_ACCEPT)
@@ -635,9 +625,7 @@
 #define SSL3_MT_FINISHED			20
 #define SSL3_MT_CERTIFICATE_STATUS		22
 #define SSL3_MT_SUPPLEMENTAL_DATA		23
-#ifndef OPENSSL_NO_NEXTPROTONEG
 #define SSL3_MT_NEXT_PROTO			67
-#endif
 #define SSL3_MT_ENCRYPTED_EXTENSIONS		203
 #define DTLS1_MT_HELLO_VERIFY_REQUEST    3
 
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index b075a20..08ad8e8 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -246,10 +246,11 @@
 /* ExtensionType value from RFC5746 */
 #define TLSEXT_TYPE_renegotiate                 0xff01
 
-#ifndef OPENSSL_NO_NEXTPROTONEG
+/* ExtensionType value from RFC6962 */
+#define TLSEXT_TYPE_certificate_timestamp	18
+
 /* This is not an IANA defined extension number */
 #define TLSEXT_TYPE_next_proto_neg		13172
-#endif
 
 /* This is not an IANA defined extension number */
 #define TLSEXT_TYPE_channel_id			30031
@@ -332,27 +333,6 @@
 #define SSL_set_tlsext_debug_arg(ssl, arg) \
 SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg)
 
-#define SSL_set_tlsext_status_type(ssl, type) \
-SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL)
-
-#define SSL_get_tlsext_status_exts(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
-
-#define SSL_set_tlsext_status_exts(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg)
-
-#define SSL_get_tlsext_status_ids(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
-
-#define SSL_set_tlsext_status_ids(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg)
-
-#define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \
-SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg)
-
-#define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \
-SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg)
-
 #define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
 SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb)
 
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 29fba40..1f277f3 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -259,9 +259,7 @@
 	STACK_OF(DIST_POINT) *crldp;
 	STACK_OF(GENERAL_NAME) *altname;
 	NAME_CONSTRAINTS *nc;
-#ifndef OPENSSL_NO_SHA
 	unsigned char sha1_hash[SHA_DIGEST_LENGTH];
-#endif
 	X509_CERT_AUX *aux;
 	} /* X509 */;
 
@@ -433,9 +431,7 @@
 	/* CRL and base CRL numbers for delta processing */
 	ASN1_INTEGER *crl_number;
 	ASN1_INTEGER *base_crl_number;
-#ifndef OPENSSL_NO_SHA
 	unsigned char sha1_hash[SHA_DIGEST_LENGTH];
-#endif
 	STACK_OF(GENERAL_NAMES) *issuers;
 	const X509_CRL_METHOD *meth;
 	void *meth_data;
@@ -664,12 +660,10 @@
 OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa);
 OPENSSL_EXPORT int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa);
 #endif
-#ifndef OPENSSL_NO_EC
 OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey);
 OPENSSL_EXPORT int   i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey);
 OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey);
 OPENSSL_EXPORT int   i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey);
-#endif
 OPENSSL_EXPORT X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8);
 OPENSSL_EXPORT int i2d_PKCS8_fp(FILE *fp,X509_SIG *p8);
 OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,
@@ -701,12 +695,10 @@
 OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa);
 OPENSSL_EXPORT int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa);
 #endif
-#ifndef OPENSSL_NO_EC
 OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey);
 OPENSSL_EXPORT int   i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey);
 OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey);
 OPENSSL_EXPORT int   i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey);
-#endif
 OPENSSL_EXPORT X509_SIG *d2i_PKCS8_bio(BIO *bp,X509_SIG **p8);
 OPENSSL_EXPORT int i2d_PKCS8_bio(BIO *bp,X509_SIG *p8);
 OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,
@@ -770,11 +762,9 @@
 OPENSSL_EXPORT DSA *		d2i_DSA_PUBKEY(DSA **a,const unsigned char **pp,
 			long length);
 #endif
-#ifndef OPENSSL_NO_EC
 OPENSSL_EXPORT int		i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp);
 OPENSSL_EXPORT EC_KEY 		*d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp,
 			long length);
-#endif
 
 DECLARE_ASN1_FUNCTIONS(X509_SIG)
 DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO)
@@ -946,10 +936,8 @@
 OPENSSL_EXPORT int		X509_subject_name_cmp(const X509 *a, const X509 *b);
 OPENSSL_EXPORT unsigned long	X509_subject_name_hash(X509 *x);
 
-#ifndef OPENSSL_NO_MD5
 OPENSSL_EXPORT unsigned long	X509_issuer_name_hash_old(X509 *a);
 OPENSSL_EXPORT unsigned long	X509_subject_name_hash_old(X509 *x);
-#endif
 
 OPENSSL_EXPORT int		X509_cmp(const X509 *a, const X509 *b);
 OPENSSL_EXPORT int		X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b);
diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
index 3db8607..49f7c3d 100644
--- a/ssl/CMakeLists.txt
+++ b/ssl/CMakeLists.txt
@@ -53,4 +53,4 @@
 	ssl_test.c
 )
 
-target_link_libraries(ssl_test crypto)
+target_link_libraries(ssl_test ssl crypto)
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index bcfcc47..2d944d8 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -420,7 +420,7 @@
  * Read an entire handshake message.  Handshake messages arrive in
  * fragments.
  */
-long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
+long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int hash_message, int *ok)
 	{
 	int i, al;
 	struct hm_header_st *msg_hdr;
@@ -431,6 +431,10 @@
 	 * by the absence of an optional handshake message */
 	if (s->s3->tmp.reuse_message)
 		{
+		/* A SSL_GET_MESSAGE_DONT_HASH_MESSAGE call cannot be combined
+		 * with reuse_message; the SSL_GET_MESSAGE_DONT_HASH_MESSAGE
+		 * would have to have been applied to the previous call. */
+		assert(hash_message != SSL_GET_MESSAGE_DONT_HASH_MESSAGE);
 		s->s3->tmp.reuse_message=0;
 		if ((mt >= 0) && (s->s3->tmp.message_type != mt))
 			{
@@ -467,7 +471,10 @@
 	p       -= DTLS1_HM_HEADER_LENGTH;
 	msg_len += DTLS1_HM_HEADER_LENGTH;
 
-	ssl3_finish_mac(s, p, msg_len);
+	s->init_msg = (uint8_t*)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+
+	if (hash_message != SSL_GET_MESSAGE_DONT_HASH_MESSAGE)
+		ssl3_hash_current_message(s);
 	if (s->msg_callback)
 		s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
 			p, msg_len,
@@ -479,7 +486,6 @@
 	if (!s->d1->listen)
 		s->d1->handshake_read_seq++;
 
-	s->init_msg = (uint8_t*)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
 	return s->init_num;
 
 f_err:
@@ -1159,7 +1165,6 @@
 	saved_state.write_hash = s->write_hash;
 	saved_state.session = s->session;
 	saved_state.epoch = s->d1->w_epoch;
-	saved_state.epoch = s->d1->w_epoch;
 	
 	s->d1->retransmitting = 1;
 	
diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c
index 99cfefd..b781d88 100644
--- a/ssl/d1_clnt.c
+++ b/ssl/d1_clnt.c
@@ -245,7 +245,7 @@
 			ssl3_init_finished_mac(s);
 
 			dtls1_start_timer(s);
-			ret=ssl3_client_hello(s);
+			ret=ssl3_send_client_hello(s);
 			if (ret <= 0) goto end;
 
 			if ( s->d1->send_cookie)
@@ -309,7 +309,7 @@
 				{
 				ret=ssl3_get_server_certificate(s);
 				if (ret <= 0) goto end;
-				if (s->tlsext_status_expected)
+				if (s->s3->tmp.certificate_status_expected)
 					s->state=SSL3_ST_CR_CERT_STATUS_A;
 				else
 					s->state=SSL3_ST_CR_KEY_EXCH_A;
@@ -393,7 +393,7 @@
 		case SSL3_ST_CW_CERT_VRFY_A:
 		case SSL3_ST_CW_CERT_VRFY_B:
 			dtls1_start_timer(s);
-			ret=ssl3_send_client_verify(s);
+			ret=ssl3_send_cert_verify(s);
 			if (ret <= 0) goto end;
 			s->state=SSL3_ST_CW_CHANGE_A;
 			s->init_num=0;
@@ -596,6 +596,7 @@
 		-1,
 		/* Use the same maximum size as ssl3_get_server_hello. */
 		20000,
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 	s->first_packet = 0;
 
diff --git a/ssl/d1_enc.c b/ssl/d1_enc.c
index 70b74b8..dec0ea5 100644
--- a/ssl/d1_enc.c
+++ b/ssl/d1_enc.c
@@ -202,11 +202,6 @@
 
 			/* we need to add 'i' padding bytes of value j */
 			j=i-1;
-			if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG)
-				{
-				if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
-					j++;
-				}
 			for (k=(int)l; k<(int)(l+i); k++)
 				rec->input[k]=j;
 			l+=i;
diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c
index 2652f84..1f909de 100644
--- a/ssl/d1_srtp.c
+++ b/ssl/d1_srtp.c
@@ -161,13 +161,13 @@
 							len))
 			{
 			*pptr=p;
-			return 0;
+			return 1;
 			}
 
 		p++;
 		}
 
-	return 1;
+	return 0;
 	}
 
 static int find_profile_by_num(unsigned profile_num,
@@ -181,12 +181,12 @@
 		if(p->id == profile_num)
 			{
 			*pptr=p;
-			return 0;
+			return 1;
 			}
 		p++;
 		}
 
-	return 1;
+	return 0;
 	}
 
 static int ssl_ctx_make_profiles(const char *profiles_string,STACK_OF(SRTP_PROTECTION_PROFILE) **out)
@@ -201,14 +201,14 @@
 	if(!(profiles=sk_SRTP_PROTECTION_PROFILE_new_null()))
 		{
 		OPENSSL_PUT_ERROR(SSL, ssl_ctx_make_profiles, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES);
-		return 1;
+		return 0;
 		}
     
 	do
 		{
 		col=strchr(ptr,':');
 
-		if(!find_profile_by_name(ptr,&p,
+		if(find_profile_by_name(ptr,&p,
 					 col ? col-ptr : (int)strlen(ptr)))
 			{
 			sk_SRTP_PROTECTION_PROFILE_push(profiles,p);
@@ -216,7 +216,7 @@
 		else
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl_ctx_make_profiles, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE);
-			return 1;
+			return 0;
 			}
 
 		if(col) ptr=col+1;
@@ -224,17 +224,19 @@
 
 	*out=profiles;
     
-	return 0;
+	return 1;
 	}
     
 int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx,const char *profiles)
 	{
-	return ssl_ctx_make_profiles(profiles,&ctx->srtp_profiles);
+	/* This API inverts its return value. */
+	return !ssl_ctx_make_profiles(profiles,&ctx->srtp_profiles);
 	}
 
 int SSL_set_tlsext_use_srtp(SSL *s,const char *profiles)
 	{
-	return ssl_ctx_make_profiles(profiles,&s->srtp_profiles);
+	/* This API inverts its return value. */
+	return !ssl_ctx_make_profiles(profiles,&s->srtp_profiles);
 	}
 
 
@@ -278,13 +280,13 @@
 		if(ct==0)
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_use_srtp_ext, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST);
-			return 1;
+			return 0;
 			}
 
 		if((2 + ct*2 + 1) > maxlen)
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_use_srtp_ext, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG);
-			return 1;
+			return 0;
 			}
 
                 /* Add the length */
@@ -301,7 +303,7 @@
 
 	*len=2 + ct*2 + 1;
     
-	return 0;
+	return 1;
 	}
 
 
@@ -335,7 +337,7 @@
 			goto done;
 			}
 
-		if (!find_profile_by_num(profile_id, &cprof))
+		if (find_profile_by_num(profile_id, &cprof))
 			{
 			sk_SRTP_PROTECTION_PROFILE_push(clnt, cprof);
 			}
@@ -381,13 +383,13 @@
 		if(maxlen < 5)
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_use_srtp_ext, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG);
-			return 1;
+			return 0;
 			}
 
 		if(s->srtp_profile==0)
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_use_srtp_ext, SSL_R_USE_SRTP_NOT_NEGOTIATED);
-			return 1;
+			return 0;
 			}
                 s2n(2, p);
 		s2n(s->srtp_profile->id,p);
@@ -395,7 +397,7 @@
 		}
 	*len=5;
     
-	return 0;
+	return 1;
 	}
     
 
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index fe8001d..79da484 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -359,7 +359,7 @@
 				dtls1_start_timer(s);
 				ret=ssl3_send_server_certificate(s);
 				if (ret <= 0) goto end;
-				if (s->tlsext_status_expected)
+				if (s->s3->tmp.certificate_status_expected)
 					s->state=SSL3_ST_SW_CERT_STATUS_A;
 				else
 					s->state=SSL3_ST_SW_KEY_EXCH_A;
@@ -485,37 +485,6 @@
 				goto end;
 			s->state=SSL3_ST_SR_CERT_VRFY_A;
 			s->init_num=0;
-
-			/* TODO(davidben): These two blocks are different
-			 * between SSL and DTLS. Resolve the difference and code
-			 * duplication. */
-			if (SSL_USE_SIGALGS(s))
-				{
-				if (!s->session->peer)
-					break;
-				/* For sigalgs freeze the handshake buffer
-				 * at this point and digest cached records.
-				 */
-				if (!s->s3->handshake_buffer)
-					{
-					OPENSSL_PUT_ERROR(SSL, dtls1_accept, ERR_R_INTERNAL_ERROR);
-					return -1;
-					}
-				s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
-				if (!ssl3_digest_cached_records(s))
-					return -1;
-				}
-			else
-				{
-				/* We need to get hashes here so if there is
-				 * a client cert, it can be verified */ 
-				s->method->ssl3_enc->cert_verify_mac(s,
-					NID_md5,
-					&(s->s3->tmp.cert_verify_md[0]));
-				s->method->ssl3_enc->cert_verify_mac(s,
-					NID_sha1,
-					&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
-				}
 			break;
 
 		case SSL3_ST_SR_CERT_VRFY_A:
@@ -547,12 +516,14 @@
 
 		case SSL3_ST_SW_SESSION_TICKET_A:
 		case SSL3_ST_SW_SESSION_TICKET_B:
-			ret=ssl3_send_newsession_ticket(s);
+			ret=ssl3_send_new_session_ticket(s);
 			if (ret <= 0) goto end;
 			s->state=SSL3_ST_SW_CHANGE_A;
 			s->init_num=0;
 			break;
 
+#if 0
+		// TODO(davidben): Implement OCSP stapling on the server.
 		case SSL3_ST_SW_CERT_STATUS_A:
 		case SSL3_ST_SW_CERT_STATUS_B:
 			ret=ssl3_send_cert_status(s);
@@ -560,7 +531,7 @@
 			s->state=SSL3_ST_SW_KEY_EXCH_A;
 			s->init_num=0;
 			break;
-
+#endif
 
 		case SSL3_ST_SW_CHANGE_A:
 		case SSL3_ST_SW_CHANGE_B:
diff --git a/ssl/pqueue/CMakeLists.txt b/ssl/pqueue/CMakeLists.txt
index 58963ff..b7166b4 100644
--- a/ssl/pqueue/CMakeLists.txt
+++ b/ssl/pqueue/CMakeLists.txt
@@ -7,3 +7,11 @@
 
 	pqueue.c
 )
+
+add_executable(
+	pqueue_test
+
+	pqueue_test.c
+)
+
+target_link_libraries(pqueue_test ssl crypto)
diff --git a/ssl/pqueue/pqueue.c b/ssl/pqueue/pqueue.c
index e8d0ac5..4c94355 100644
--- a/ssl/pqueue/pqueue.c
+++ b/ssl/pqueue/pqueue.c
@@ -87,7 +87,7 @@
   OPENSSL_free(item);
 }
 
-pqueue pqueue_new() {
+pqueue pqueue_new(void) {
   pqueue_s *pq = (pqueue_s *)OPENSSL_malloc(sizeof(pqueue_s));
   if (pq == NULL) {
     return NULL;
@@ -111,7 +111,7 @@
   pitem *curr;
 
   for (curr = pq->items; curr; curr = curr->next) {
-    if (memcmp(curr->priority, prio64be, 8) == 0) {
+    if (memcmp(curr->priority, prio64be, sizeof(curr->priority)) == 0) {
       return curr;
     }
   }
@@ -130,9 +130,9 @@
   return count;
 }
 
-pitem *pqueue_iterator(pqueue_s *pq) { return pq->items; }
+piterator pqueue_iterator(pqueue_s *pq) { return pq->items; }
 
-pitem *pqueue_next(pitem **item) {
+pitem *pqueue_next(piterator *item) {
   pitem *ret;
 
   if (item == NULL || *item == NULL) {
@@ -156,9 +156,9 @@
   for (curr = NULL, next = pq->items; next != NULL;
        curr = next, next = next->next) {
     /* we can compare 64-bit value in big-endian encoding with memcmp. */
-    int cmp = memcmp(next->priority, item->priority, 8);
-    if (cmp > 0) /* next > item */
-    {
+    int cmp = memcmp(next->priority, item->priority, sizeof(item->priority));
+    if (cmp > 0) {
+      /* next > item */
       item->next = next;
 
       if (curr == NULL) {
@@ -168,8 +168,10 @@
       }
 
       return item;
-    } else if (cmp == 0) /* duplicates not allowed */
+    } else if (cmp == 0) {
+      /* duplicates not allowed */
       return NULL;
+    }
   }
 
   item->next = NULL;
diff --git a/ssl/pqueue/pqueue_test.c b/ssl/pqueue/pqueue_test.c
new file mode 100644
index 0000000..16a9ad8
--- /dev/null
+++ b/ssl/pqueue/pqueue_test.c
@@ -0,0 +1,91 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/pqueue.h>
+#include <openssl/ssl.h>
+
+
+static int trivial() {
+  pqueue q = pqueue_new();
+  if (q == NULL) {
+    return 0;
+  }
+  int32_t data = 0xdeadbeef;
+  uint8_t priority[8] = {0};
+  pitem *item = pitem_new(priority, &data);
+  if (item == NULL ||
+      pqueue_insert(q, item) != item ||
+      pqueue_size(q) != 1 ||
+      pqueue_peek(q) != item ||
+      pqueue_pop(q) != item ||
+      pqueue_size(q) != 0 ||
+      pqueue_pop(q) != NULL) {
+    return 0;
+  }
+  pitem_free(item);
+  pqueue_free(q);
+  return 1;
+}
+
+#define NUM_ITEMS 10
+
+static int fixed_random() {
+  /* Random order of 10 elements, chosen by
+     random.choice(list(itertools.permutations(range(10)))) */
+  int ordering[NUM_ITEMS] = {9, 6, 3, 4, 0, 2, 7, 1, 8, 5};
+  int i;
+  pqueue q = pqueue_new();
+  if (q == NULL) {
+    return 0;
+  }
+  uint8_t priority[8] = {0};
+  /* Insert the elements */
+  for (i = 0; i < NUM_ITEMS; i++) {
+    priority[7] = ordering[i];
+    pitem *item = pitem_new(priority, &ordering[i]);
+    pqueue_insert(q, item);
+  }
+  piterator iter = pqueue_iterator(q);
+  pitem *curr = pqueue_next(&iter);
+  if (curr == NULL) {
+    return 0;
+  }
+  while (1) {
+    pitem *next = pqueue_next(&iter);
+    if (next == NULL) {
+      break;
+    }
+    int *curr_data = (int*)curr->data;
+    int *next_data = (int*)next->data;
+    if (*curr_data >= *next_data) {
+      return 0;
+    }
+    curr = next;
+  }
+  return 1;
+}
+
+int main(void) {
+  SSL_library_init();
+
+  if (!trivial() || !fixed_random()) {
+    return 1;
+  }
+
+  printf("PASS\n");
+  return 0;
+}
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index cfa6d00..ccb3e2c 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -121,16 +121,13 @@
 static int ssl23_get_server_hello(SSL *s);
 static const SSL_METHOD *ssl23_get_client_method(int ver)
 	{
-	if (ver == SSL3_VERSION)
-		return(SSLv3_client_method());
-	else if (ver == TLS1_VERSION)
-		return(TLSv1_client_method());
-	else if (ver == TLS1_1_VERSION)
-		return(TLSv1_1_client_method());
-	else if (ver == TLS1_2_VERSION)
-		return(TLSv1_2_client_method());
-	else
-		return(NULL);
+	/* When SSL_set_session is called, do NOT switch to the version-specific
+	 * method table. The server may still negotiate a different version when
+	 * rejecting the session.
+	 *
+	 * TODO(davidben): Clean this up. This duplicates logic from the
+	 * version-specific tables. https://crbug.com/403378 */
+	return SSLv23_client_method();
 	}
 
 IMPLEMENT_ssl23_meth_func(SSLv23_client_method,
@@ -167,12 +164,6 @@
 		case SSL_ST_BEFORE|SSL_ST_CONNECT:
 		case SSL_ST_OK|SSL_ST_CONNECT:
 
-			if (s->session != NULL)
-				{
-				OPENSSL_PUT_ERROR(SSL, ssl23_connect, SSL_R_SSL23_DOING_SESSION_ID_REUSE);
-				ret= -1;
-				goto end;
-				}
 			s->server=0;
 			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
 
@@ -288,39 +279,32 @@
 	 * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
 	 * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2.
 	 */
-	mask =	SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1
-#if !defined(OPENSSL_NO_SSL3)
-		|SSL_OP_NO_SSLv3
-#endif
-		;
-#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
+	mask = SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3;
 	version = TLS1_2_VERSION;
-
 	if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask)
 		version = TLS1_1_VERSION;
-#else
-	version = TLS1_1_VERSION;
-#endif
 	mask &= ~SSL_OP_NO_TLSv1_1;
 	if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
 		version = TLS1_VERSION;
 	mask &= ~SSL_OP_NO_TLSv1;
-#if !defined(OPENSSL_NO_SSL3)
 	if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
 		version = SSL3_VERSION;
 	mask &= ~SSL_OP_NO_SSLv3;
-#endif
 
 	buf=(unsigned char *)s->init_buf->data;
 	if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
 		{
-#if 0
-		/* don't reuse session-id's */
-		if (!ssl_get_new_session(s,0))
+		/* Check if the session is resumable. If not, drop it. */
+		if (s->session != NULL)
 			{
-			return(-1);
+			if (s->session->ssl_version > version ||
+				s->session->session_id_length == 0 ||
+				s->session->not_resumable)
+				{
+				SSL_SESSION_free(s->session);
+				s->session = NULL;
+				}
 			}
-#endif
 
 		p=s->s3->client_random;
 		if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0)
@@ -374,8 +358,22 @@
 		memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
 		p += SSL3_RANDOM_SIZE;
 
-		/* Session ID (zero since there is no reuse) */
-		*(p++) = 0;
+		/* Session ID */
+		if (s->new_session || s->session == NULL)
+			i=0;
+		else
+			i=s->session->session_id_length;
+		*(p++)=i;
+		if (i != 0)
+			{
+			if (i > (int)sizeof(s->session->session_id))
+				{
+				OPENSSL_PUT_ERROR(SSL, ssl23_client_hello, ERR_R_INTERNAL_ERROR);
+				return -1;
+				}
+			memcpy(p,s->session->session_id,i);
+			p+=i;
+			}
 
 		/* Ciphers supported (using SSL 3.0/TLS 1.0 format) */
 		i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2]);
@@ -572,9 +570,9 @@
 		}
 	s->init_num=0;
 
-	/* Since, if we are sending a ssl23 client hello, we are not
-	 * reusing a session-id */
-	if (!ssl_get_new_session(s,0))
+	/* If there was no session to resume, now that the final version is
+	 * determined, insert a fresh one. */
+	if (s->session == NULL && !ssl_get_new_session(s,0))
 		goto err;
 
 	return(SSL_connect(s));
diff --git a/ssl/s23_meth.c b/ssl/s23_meth.c
index 5f0f8b2..f3af959 100644
--- a/ssl/s23_meth.c
+++ b/ssl/s23_meth.c
@@ -65,11 +65,9 @@
 static const SSL_METHOD *ssl23_get_method(int ver);
 static const SSL_METHOD *ssl23_get_method(int ver)
 	{
-#ifndef OPENSSL_NO_SSL3
 	if (ver == SSL3_VERSION)
 		return(SSLv3_method());
 	else
-#endif
 	if (ver == TLS1_VERSION)
 		return(TLSv1_method());
 	else if (ver == TLS1_1_VERSION)
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 8ce6b3b..6604fc7 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -118,8 +118,10 @@
 #include <openssl/buf.h>
 #include <openssl/evp.h>
 #include <openssl/mem.h>
+#include <openssl/md5.h>
 #include <openssl/obj.h>
 #include <openssl/rand.h>
+#include <openssl/sha.h>
 #include <openssl/x509.h>
 
 #include "ssl_locl.h"
@@ -166,6 +168,14 @@
 		memcpy(p, s->s3->tmp.finish_md, i);
 		l=i;
 
+                /* Log the master secret, if logging is enabled. */
+                if (!ssl_ctx_log_master_secret(s->ctx,
+				s->s3->client_random, SSL3_RANDOM_SIZE,
+				s->session->master_key, s->session->master_key_length))
+			{
+			return 0;
+			}
+
                 /* Copy the finished so we can use it for
                    renegotiation checks */
                 if(s->type == SSL_ST_CONNECT)
@@ -191,7 +201,6 @@
 	return ssl_do_write(s);
 	}
 
-#ifndef OPENSSL_NO_NEXTPROTONEG
 /* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen to far. */
 static void ssl3_take_mac(SSL *s)
 	{
@@ -216,7 +225,6 @@
 	s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
 		sender,slen,s->s3->tmp.peer_finish_md);
 	}
-#endif
 
 int ssl3_get_finished(SSL *s, int a, int b)
 	{
@@ -224,21 +232,20 @@
 	long n;
 	unsigned char *p;
 
-#ifdef OPENSSL_NO_NEXTPROTONEG
-	/* the mac has already been generated when we received the
-	 * change cipher spec message and is in s->s3->tmp.peer_finish_md
-	 */ 
-#endif
-
 	n=s->method->ssl_get_message(s,
 		a,
 		b,
 		SSL3_MT_FINISHED,
 		64, /* should actually be 36+4 :-) */
+		SSL_GET_MESSAGE_DONT_HASH_MESSAGE,
 		&ok);
 
 	if (!ok) return((int)n);
 
+	/* Snapshot the finished hash before incorporating the new message. */
+	ssl3_take_mac(s);
+	ssl3_hash_current_message(s);
+
 	/* If this occurs, we have missed a message.
 	 * TODO(davidben): Is this check now redundant with
 	 * SSL3_FLAGS_EXPECT_CCS? */
@@ -337,7 +344,7 @@
  * The first four bytes (msg_type and length) are read in state 'st1',
  * the body is read in state 'stn'.
  */
-long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
+long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int hash_message, int *ok)
 	{
 	unsigned char *p;
 	unsigned long l;
@@ -346,6 +353,10 @@
 
 	if (s->s3->tmp.reuse_message)
 		{
+		/* A SSL_GET_MESSAGE_DONT_HASH_MESSAGE call cannot be combined
+		 * with reuse_message; the SSL_GET_MESSAGE_DONT_HASH_MESSAGE
+		 * would have to have been applied to the previous call. */
+		assert(hash_message != SSL_GET_MESSAGE_DONT_HASH_MESSAGE);
 		s->s3->tmp.reuse_message=0;
 		if ((mt >= 0) && (s->s3->tmp.message_type != mt))
 			{
@@ -461,16 +472,9 @@
 		n -= i;
 		}
 
-#ifndef OPENSSL_NO_NEXTPROTONEG
-	/* If receiving Finished, record MAC of prior handshake messages for
-	 * Finished verification. */
-	if (*s->init_buf->data == SSL3_MT_FINISHED)
-		ssl3_take_mac(s);
-#endif
-
 	/* Feed this message into MAC computation. */
-	if (*((unsigned char*) s->init_buf->data) != SSL3_MT_ENCRYPTED_EXTENSIONS)
-		ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num + 4);
+	if (hash_message != SSL_GET_MESSAGE_DONT_HASH_MESSAGE)
+		ssl3_hash_current_message(s);
 	if (s->msg_callback)
 		s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, (size_t)s->init_num + 4, s, s->msg_callback_arg);
 	*ok=1;
@@ -482,6 +486,73 @@
 	return(-1);
 	}
 
+void ssl3_hash_current_message(SSL *s)
+	{
+	/* The handshake header (different size between DTLS and TLS) is included in the hash. */
+	size_t header_len = s->init_msg - (uint8_t *)s->init_buf->data;
+	ssl3_finish_mac(s, (uint8_t *)s->init_buf->data, s->init_num + header_len);
+	}
+
+/* ssl3_cert_verify_hash is documented as needing EVP_MAX_MD_SIZE because that
+ * is sufficient pre-TLS1.2 as well. */
+OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE > MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH,
+	combined_tls_hash_fits_in_max);
+
+int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len, const EVP_MD **out_md, EVP_PKEY *pkey)
+	{
+	/* For TLS v1.2 send signature algorithm and signature using
+	 * agreed digest and cached handshake records. Otherwise, use
+	 * SHA1 or MD5 + SHA1 depending on key type.  */
+	if (SSL_USE_SIGALGS(s))
+		{
+		const uint8_t *hdata;
+		size_t hdatalen;
+		EVP_MD_CTX mctx;
+		unsigned len;
+
+		if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_INTERNAL_ERROR);
+			return 0;
+			}
+		EVP_MD_CTX_init(&mctx);
+		if (!EVP_DigestInit_ex(&mctx, *out_md, NULL)
+			|| !EVP_DigestUpdate(&mctx, hdata, hdatalen)
+			|| !EVP_DigestFinal(&mctx, out, &len))
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_EVP_LIB);
+			EVP_MD_CTX_cleanup(&mctx);
+			return 0;
+			}
+		*out_len = len;
+		}
+	else if (pkey->type == EVP_PKEY_RSA)
+		{
+		if (s->method->ssl3_enc->cert_verify_mac(s, NID_md5, out) == 0 ||
+			s->method->ssl3_enc->cert_verify_mac(s,
+				NID_sha1, out + MD5_DIGEST_LENGTH) == 0)
+			return 0;
+		*out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH;
+		/* Using a NULL signature MD makes EVP_PKEY_sign perform
+		 * a raw RSA signature, rather than wrapping in a
+		 * DigestInfo. */
+		*out_md = NULL;
+		}
+	else if (pkey->type == EVP_PKEY_EC)
+		{
+		if (s->method->ssl3_enc->cert_verify_mac(s, NID_sha1, out) == 0)
+			return 0;
+		*out_len = SHA_DIGEST_LENGTH;
+		*out_md = EVP_sha1();
+		}
+	else
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl3_cert_verify_hash, ERR_R_INTERNAL_ERROR);
+		return 0;
+		}
+	return 1;
+	}
+
 int ssl_cert_type(X509 *x, EVP_PKEY *pkey)
 	{
 	EVP_PKEY *pk;
@@ -498,12 +569,10 @@
 		{
 		ret=SSL_PKEY_RSA_ENC;
 		}
-#ifndef OPENSSL_NO_EC
 	else if (i == EVP_PKEY_EC)
 		{
 		ret = SSL_PKEY_ECC;
 		}	
-#endif
 		
 err:
 	if(!pkey) EVP_PKEY_free(pk);
@@ -627,8 +696,9 @@
 		len = s->max_send_fragment
 			+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD
 			+ headerlen + align;
-		if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS))
-			len += headerlen + align
+		/* Account for 1/n-1 record splitting. */
+		if (s->mode & SSL_MODE_CBC_RECORD_SPLITTING)
+			len += headerlen + align + 1
 				+ SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD;
 
 		if ((p=OPENSSL_malloc(len)) == NULL)
diff --git a/ssl/s3_cbc.c b/ssl/s3_cbc.c
index e80734e..6a0de9c 100644
--- a/ssl/s3_cbc.c
+++ b/ssl/s3_cbc.c
@@ -52,7 +52,6 @@
 
 #include <assert.h>
 
-#include <openssl/md5.h>
 #include <openssl/obj.h>
 #include <openssl/sha.h>
 
@@ -166,28 +165,6 @@
 
 	padding_length = rec->data[rec->length-1];
 
-	if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG)
-		{
-		/* First packet is even in size, so check */
-		if ((memcmp(s->s3->read_sequence, "\0\0\0\0\0\0\0\0",8) == 0) &&
-		    !(padding_length & 1))
-			{
-			s->s3->flags|=TLS1_FLAGS_TLS_PADDING_BUG;
-			}
-		if ((s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG) &&
-		    padding_length > 0)
-			{
-			padding_length--;
-			}
-		}
-
-	if (EVP_CIPHER_flags(s->enc_read_ctx->cipher)&EVP_CIPH_FLAG_AEAD_CIPHER)
-		{
-		/* padding is already verified */
-		rec->length -= padding_length + 1;
-		return 1;
-		}
-
 	good = constant_time_ge(rec->length, overhead+padding_length);
 	/* The padding consists of a length byte at the end of the record and
 	 * then that many bytes of padding, all with the same value as the
@@ -334,15 +311,6 @@
 /* These functions serialize the state of a hash and thus perform the standard
  * "final" operation without adding the padding and length that such a function
  * typically does. */
-static void tls1_md5_final_raw(void* ctx, unsigned char *md_out)
-	{
-	MD5_CTX *md5 = ctx;
-	u32toLE(md5->A, md_out);
-	u32toLE(md5->B, md_out);
-	u32toLE(md5->C, md_out);
-	u32toLE(md5->D, md_out);
-	}
-
 static void tls1_sha1_final_raw(void* ctx, unsigned char *md_out)
 	{
 	SHA_CTX *sha1 = ctx;
@@ -386,12 +354,9 @@
 	{
 	switch (EVP_MD_CTX_type(ctx))
 		{
-		case NID_md5:
 		case NID_sha1:
-		case NID_sha224:
 		case NID_sha256:
 		case NID_sha384:
-		case NID_sha512:
 			return 1;
 		default:
 			return 0;
@@ -448,7 +413,6 @@
 	/* mdLengthSize is the number of bytes in the length field that terminates
 	* the hash. */
 	unsigned md_length_size = 8;
-	char length_is_big_endian = 1;
 
 	/* This is a, hopefully redundant, check that allows us to forget about
 	 * many possible overflows later in this function. */
@@ -456,26 +420,12 @@
 
 	switch (EVP_MD_CTX_type(ctx))
 		{
-		case NID_md5:
-			MD5_Init((MD5_CTX*)md_state.c);
-			md_final_raw = tls1_md5_final_raw;
-			md_transform = (void(*)(void *ctx, const unsigned char *block)) MD5_Transform;
-			md_size = 16;
-			sslv3_pad_length = 48;
-			length_is_big_endian = 0;
-			break;
 		case NID_sha1:
 			SHA1_Init((SHA_CTX*)md_state.c);
 			md_final_raw = tls1_sha1_final_raw;
 			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA1_Transform;
 			md_size = 20;
 			break;
-		case NID_sha224:
-			SHA224_Init((SHA256_CTX*)md_state.c);
-			md_final_raw = tls1_sha256_final_raw;
-			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA256_Transform;
-			md_size = 224/8;
-			break;
 		case NID_sha256:
 			SHA256_Init((SHA256_CTX*)md_state.c);
 			md_final_raw = tls1_sha256_final_raw;
@@ -490,14 +440,6 @@
 			md_block_size = 128;
 			md_length_size = 16;
 			break;
-		case NID_sha512:
-			SHA512_Init((SHA512_CTX*)md_state.c);
-			md_final_raw = tls1_sha512_final_raw;
-			md_transform = (void(*)(void *ctx, const unsigned char *block)) SHA512_Transform;
-			md_size = 64;
-			md_block_size = 128;
-			md_length_size = 16;
-			break;
 		default:
 			/* ssl3_cbc_record_digest_supported should have been
 			 * called first to check that the hash function is
@@ -599,22 +541,11 @@
 		md_transform(md_state.c, hmac_pad);
 		}
 
-	if (length_is_big_endian)
-		{
-		memset(length_bytes,0,md_length_size-4);
-		length_bytes[md_length_size-4] = (unsigned char)(bits>>24);
-		length_bytes[md_length_size-3] = (unsigned char)(bits>>16);
-		length_bytes[md_length_size-2] = (unsigned char)(bits>>8);
-		length_bytes[md_length_size-1] = (unsigned char)bits;
-		}
-	else
-		{
-		memset(length_bytes,0,md_length_size);
-		length_bytes[md_length_size-5] = (unsigned char)(bits>>24);
-		length_bytes[md_length_size-6] = (unsigned char)(bits>>16);
-		length_bytes[md_length_size-7] = (unsigned char)(bits>>8);
-		length_bytes[md_length_size-8] = (unsigned char)bits;
-		}
+	memset(length_bytes,0,md_length_size-4);
+	length_bytes[md_length_size-4] = (unsigned char)(bits>>24);
+	length_bytes[md_length_size-3] = (unsigned char)(bits>>16);
+	length_bytes[md_length_size-2] = (unsigned char)(bits>>8);
+	length_bytes[md_length_size-1] = (unsigned char)bits;
 
 	if (k > 0)
 		{
@@ -622,8 +553,7 @@
 			{
 			/* The SSLv3 header is larger than a single block.
 			 * overhang is the number of bytes beyond a single
-			 * block that the header consumes: either 7 bytes
-			 * (SHA1) or 11 bytes (MD5). */
+			 * block that the header consumes: 7 bytes (SHA1). */
 			unsigned overhang = header_length-md_block_size;
 			md_transform(md_state.c, header);
 			memcpy(first_block, header + md_block_size, overhang);
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 9c2129c..cb9f95f 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -261,7 +261,7 @@
 		case SSL3_ST_CW_CLNT_HELLO_B:
 
 			s->shutdown=0;
-			ret=ssl3_client_hello(s);
+			ret=ssl3_send_client_hello(s);
 			if (ret <= 0) goto end;
 			s->state=SSL3_ST_CR_SRVR_HELLO_A;
 			s->init_num=0;
@@ -299,7 +299,7 @@
 				{
 				ret=ssl3_get_server_certificate(s);
 				if (ret <= 0) goto end;
-				if (s->tlsext_status_expected)
+				if (s->s3->tmp.certificate_status_expected)
 					s->state=SSL3_ST_CR_CERT_STATUS_A;
 				else
 					s->state=SSL3_ST_CR_KEY_EXCH_A;
@@ -379,7 +379,7 @@
 
 		case SSL3_ST_CW_CERT_VRFY_A:
 		case SSL3_ST_CW_CERT_VRFY_B:
-			ret=ssl3_send_client_verify(s);
+			ret=ssl3_send_cert_verify(s);
 			if (ret <= 0) goto end;
 			s->state=SSL3_ST_CW_CHANGE_A;
 			s->init_num=0;
@@ -395,10 +395,8 @@
  			s->state=SSL3_ST_CW_FINISHED_A;
 			if (s->s3->tlsext_channel_id_valid)
 				s->state=SSL3_ST_CW_CHANNEL_ID_A;
-# if !defined(OPENSSL_NO_NEXTPROTONEG)
 			if (s->s3->next_proto_neg_seen)
 				s->state=SSL3_ST_CW_NEXT_PROTO_A;
-# endif
 			s->init_num=0;
 
 			s->session->cipher=s->s3->tmp.new_cipher;
@@ -417,7 +415,6 @@
 
 			break;
 
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
 		case SSL3_ST_CW_NEXT_PROTO_A:
 		case SSL3_ST_CW_NEXT_PROTO_B:
 			ret=ssl3_send_next_proto(s);
@@ -427,7 +424,6 @@
 			else
 				s->state=SSL3_ST_CW_FINISHED_A;
 			break;
-#endif
 
 		case SSL3_ST_CW_CHANNEL_ID_A:
 		case SSL3_ST_CW_CHANNEL_ID_B:
@@ -616,7 +612,7 @@
 	}
 
 
-int ssl3_client_hello(SSL *s)
+int ssl3_send_client_hello(SSL *s)
 	{
 	unsigned char *buf;
 	unsigned char *p,*d;
@@ -647,7 +643,7 @@
 				 */
 				if (options & SSL_OP_NO_DTLSv1)
 					{
-					OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, SSL_R_WRONG_SSL_VERSION);
+					OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, SSL_R_WRONG_SSL_VERSION);
 					goto err;
 					}
 				/* Update method so we don't use any DTLS 1.2
@@ -735,7 +731,7 @@
 			{
 			if (i > (int)sizeof(s->session->session_id))
 				{
-				OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, ERR_R_INTERNAL_ERROR);
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, ERR_R_INTERNAL_ERROR);
 				goto err;
 				}
 			memcpy(p,s->session->session_id,i);
@@ -747,7 +743,7 @@
 			{
 			if ( s->d1->cookie_len > sizeof(s->d1->cookie))
 				{
-				OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, ERR_R_INTERNAL_ERROR);
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, ERR_R_INTERNAL_ERROR);
 				goto err;
 				}
 			*(p++) = s->d1->cookie_len;
@@ -759,7 +755,7 @@
 		i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2]);
 		if (i == 0)
 			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, SSL_R_NO_CIPHERS_AVAILABLE);
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, SSL_R_NO_CIPHERS_AVAILABLE);
 			goto err;
 			}
 		s2n(i,p);
@@ -772,12 +768,12 @@
 		/* TLS extensions*/
 		if (ssl_prepare_clienthello_tlsext(s) <= 0)
 			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, SSL_R_CLIENTHELLO_TLSEXT);
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, SSL_R_CLIENTHELLO_TLSEXT);
 			goto err;
 			}
 		if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH, p-buf)) == NULL)
 			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_client_hello, ERR_R_INTERNAL_ERROR);
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_hello, ERR_R_INTERNAL_ERROR);
 			goto err;
 			}
 		
@@ -802,12 +798,14 @@
 	CBS server_hello, server_random, session_id;
 	uint16_t server_version, cipher_suite;
 	uint8_t compression_method;
+	unsigned long mask_ssl;
 
 	n=s->method->ssl_get_message(s,
 		SSL3_ST_CR_SRVR_HELLO_A,
 		SSL3_ST_CR_SRVR_HELLO_B,
 		SSL3_MT_SERVER_HELLO,
 		20000, /* ?? */
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 
 	if (!ok) return((int)n);
@@ -916,10 +914,16 @@
 		OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_UNKNOWN_CIPHER_RETURNED);
 		goto f_err;
 		}
+	/* ct->mask_ssl was computed from client capabilities. Now
+	 * that the final version is known, compute a new mask_ssl. */
+	if (!SSL_USE_TLS1_2_CIPHERS(s))
+		mask_ssl = SSL_TLSV1_2;
+	else
+		mask_ssl = 0;
 	/* If it is a disabled cipher we didn't send it in client hello,
 	 * so return an error.
 	 */
-	if (c->algorithm_ssl & ct->mask_ssl ||
+	if (c->algorithm_ssl & mask_ssl ||
 		c->algorithm_mkey & ct->mask_k ||
 		c->algorithm_auth & ct->mask_a)
 		{
@@ -1002,6 +1006,7 @@
 		SSL3_ST_CR_CERT_B,
 		SSL3_MT_CERTIFICATE,
 		s->max_cert_list,
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 
 	if (!ok) return((int)n);
@@ -1145,14 +1150,10 @@
 	EVP_PKEY *pkey=NULL;
 	const EVP_MD *md = NULL;
 	RSA *rsa=NULL;
-#ifndef OPENSSL_NO_DH
 	DH *dh=NULL;
-#endif
-#ifndef OPENSSL_NO_ECDH
 	EC_KEY *ecdh = NULL;
 	BN_CTX *bn_ctx = NULL;
 	EC_POINT *srvr_ecpoint = NULL;
-#endif
 	CBS server_key_exchange, server_key_exchange_orig, parameter;
 
 	/* use same message size as in ssl3_get_certificate_request()
@@ -1162,6 +1163,7 @@
 		SSL3_ST_CR_KEY_EXCH_B,
 		-1,
 		s->max_cert_list,
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 	if (!ok) return((int)n);
 
@@ -1207,20 +1209,16 @@
 			RSA_free(s->session->sess_cert->peer_rsa_tmp);
 			s->session->sess_cert->peer_rsa_tmp=NULL;
 			}
-#ifndef OPENSSL_NO_DH
 		if (s->session->sess_cert->peer_dh_tmp)
 			{
 			DH_free(s->session->sess_cert->peer_dh_tmp);
 			s->session->sess_cert->peer_dh_tmp=NULL;
 			}
-#endif
-#ifndef OPENSSL_NO_ECDH
 		if (s->session->sess_cert->peer_ecdh_tmp)
 			{
 			EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
 			s->session->sess_cert->peer_ecdh_tmp=NULL;
 			}
-#endif
 		}
 	else
 		{
@@ -1269,8 +1267,7 @@
 			}
 		}
 
-	if (0) {}
-	else if (alg_k & SSL_kRSA)
+	if (alg_k & SSL_kRSA)
 		{
 		CBS rsa_modulus, rsa_exponent;
 
@@ -1318,7 +1315,6 @@
 		s->session->sess_cert->peer_rsa_tmp=rsa;
 		rsa=NULL;
 		}
-#ifndef OPENSSL_NO_DH
 	else if (alg_k & SSL_kEDH)
 		{
 		CBS dh_p, dh_g, dh_Ys;
@@ -1370,9 +1366,7 @@
 		s->session->sess_cert->peer_dh_tmp=dh;
 		dh=NULL;
 		}
-#endif /* !OPENSSL_NO_DH */
 
-#ifndef OPENSSL_NO_ECDH
 	else if (alg_k & SSL_kEECDH)
 		{
 		uint16_t curve_id;
@@ -1450,10 +1444,8 @@
 		if (0) ;
 		else if (alg_a & SSL_aRSA)
 			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
-#ifndef OPENSSL_NO_ECDSA
 		else if (alg_a & SSL_aECDSA)
 			pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_ECC].x509);
-#endif
 		/* else anonymous ECDH, so no certificate or pkey. */
 		EC_KEY_set_public_key(ecdh, srvr_ecpoint);
 		s->session->sess_cert->peer_ecdh_tmp=ecdh;
@@ -1463,7 +1455,6 @@
 		EC_POINT_free(srvr_ecpoint);
 		srvr_ecpoint = NULL;
 		}
-#endif /* !OPENSSL_NO_ECDH */
 
 	else if (!(alg_k & SSL_kPSK))
 		{
@@ -1573,16 +1564,12 @@
 	EVP_PKEY_free(pkey);
 	if (rsa != NULL)
 		RSA_free(rsa);
-#ifndef OPENSSL_NO_DH
 	if (dh != NULL)
 		DH_free(dh);
-#endif
-#ifndef OPENSSL_NO_ECDH
 	BN_CTX_free(bn_ctx);
 	EC_POINT_free(srvr_ecpoint);
 	if (ecdh != NULL)
 		EC_KEY_free(ecdh);
-#endif
 	EVP_MD_CTX_cleanup(&md_ctx);
 	return(-1);
 	}
@@ -1609,6 +1596,7 @@
 		SSL3_ST_CR_CERT_REQ_B,
 		-1,
 		s->max_cert_list,
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 
 	if (!ok) return((int)n);
@@ -1762,6 +1750,7 @@
 		SSL3_ST_CR_SESSION_TICKET_B,
 		SSL3_MT_NEWSESSION_TICKET,
 		16384,
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 
 	if (!ok)
@@ -1816,13 +1805,13 @@
 	long n;
 	CBS certificate_status, ocsp_response;
 	uint8_t status_type;
-	size_t resplen;
 
 	n=s->method->ssl_get_message(s,
 		SSL3_ST_CR_CERT_STATUS_A,
 		SSL3_ST_CR_CERT_STATUS_B,
 		SSL3_MT_CERTIFICATE_STATUS,
 		16384,
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 
 	if (!ok) return((int)n);
@@ -1839,34 +1828,13 @@
 		goto f_err;
 		}
 
-	/* TODO(davidben): Make tlsext_ocsp_resplen a
-	 * size_t. Currently it uses -1 to signal no response. The
-	 * spec does not allow ocsp_response to be zero-length, so
-	 * using 0 should be fine. */
-	if (!CBS_stow(&ocsp_response, &s->tlsext_ocsp_resp, &resplen))
+	if (!CBS_stow(&ocsp_response,
+			&s->session->ocsp_response, &s->session->ocsp_response_length))
 		{
 		al = SSL_AD_INTERNAL_ERROR;
 		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, ERR_R_MALLOC_FAILURE);
 		goto f_err;
 		}
-	s->tlsext_ocsp_resplen = resplen;
-	if (s->ctx->tlsext_status_cb)
-		{
-		int ret;
-		ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
-		if (ret == 0)
-			{
-			al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, SSL_R_INVALID_STATUS_RESPONSE);
-			goto f_err;
-			}
-		if (ret < 0)
-			{
-			al = SSL_AD_INTERNAL_ERROR;
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, ERR_R_MALLOC_FAILURE);
-			goto f_err;
-			}
-		}
 	return 1;
 f_err:
 	ssl3_send_alert(s,SSL3_AL_FATAL,al);
@@ -1883,6 +1851,7 @@
 		SSL3_ST_CR_SRVR_DONE_B,
 		SSL3_MT_SERVER_DONE,
 		30, /* should be very small, like 0 :-) */
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 
 	if (!ok) return((int)n);
@@ -1906,7 +1875,6 @@
 	unsigned long alg_a;
 	unsigned char *q;
 	EVP_PKEY *pkey=NULL;
-#ifndef OPENSSL_NO_ECDH
 	EC_KEY *clnt_ecdh = NULL;
 	const EC_POINT *srvr_ecpoint = NULL;
 	EVP_PKEY *srvr_pub_pkey = NULL;
@@ -1915,7 +1883,6 @@
 	BN_CTX * bn_ctx = NULL;
 	unsigned int psk_len = 0;
 	unsigned char psk[PSK_MAX_PSK_LEN];
-#endif /* OPENSSL_NO_ECDH */
 
 	if (s->state == SSL3_ST_CW_KEY_EXCH_A)
 		{
@@ -2001,9 +1968,7 @@
 				}
 			}
 
-		/* Fool emacs indentation */
-		if (0) {}
-		else if (alg_k & SSL_kRSA)
+		if (alg_k & SSL_kRSA)
 			{
 			RSA *rsa;
 			unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
@@ -2050,6 +2015,13 @@
 				goto err;
 				}
 
+			/* 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)))
+				{
+				goto err;
+				}
+
 			/* Fix buf for TLS and beyond */
 			if (s->version > SSL3_VERSION)
 				{
@@ -2063,7 +2035,6 @@
 					tmp_buf,sizeof tmp_buf);
 			OPENSSL_cleanse(tmp_buf,sizeof tmp_buf);
 			}
-#ifndef OPENSSL_NO_DH
 		else if (alg_k & SSL_kEDH)
 			{
 			DH *dh_srvr,*dh_clnt;
@@ -2124,9 +2095,7 @@
 
 			/* perhaps clean things up a bit EAY EAY EAY EAY*/
 			}
-#endif
 
-#ifndef OPENSSL_NO_ECDH
 		else if (alg_k & SSL_kEECDH)
 			{
 			const EC_GROUP *srvr_group = NULL;
@@ -2274,12 +2243,10 @@
 
 			/* Free allocated memory */
 			BN_CTX_free(bn_ctx);
-			if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
-			if (clnt_ecdh != NULL)
-				 EC_KEY_free(clnt_ecdh);
+			OPENSSL_free(encodedPoint);
+			EC_KEY_free(clnt_ecdh);
 			EVP_PKEY_free(srvr_pub_pkey);
 			}
-#endif /* !OPENSSL_NO_ECDH */
 		else if (!(alg_k & SSL_kPSK) || ((alg_k & SSL_kPSK) && !(alg_a & SSL_aPSK)))
 			{
 			ssl3_send_alert(s, SSL3_AL_FATAL,
@@ -2295,82 +2262,52 @@
 	/* SSL3_ST_CW_KEY_EXCH_B */
 	return ssl_do_write(s);
 err:
-#ifndef OPENSSL_NO_ECDH
 	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);
-#endif
 	return(-1);
 	}
 
-int ssl3_send_client_verify(SSL *s)
+int ssl3_send_cert_verify(SSL *s)
 	{
 	unsigned char *buf, *p;
-	const EVP_MD *md;
+	const EVP_MD *md = NULL;
 	uint8_t digest[EVP_MAX_MD_SIZE];
-	unsigned digest_length;
+	size_t digest_length;
 	EVP_PKEY *pkey;
 	EVP_PKEY_CTX *pctx = NULL;
-	EVP_MD_CTX mctx;
 	size_t signature_length = 0;
 	unsigned long n = 0;
 
-	EVP_MD_CTX_init(&mctx);
 	buf=(unsigned char *)s->init_buf->data;
 
 	if (s->state == SSL3_ST_CW_CERT_VRFY_A)
 		{
 		p= ssl_handshake_start(s);
 		pkey = s->cert->key->privatekey;
-		/* For TLS v1.2 send signature algorithm and signature using
-		 * agreed digest and cached handshake records. Otherwise, use
-		 * SHA1 or MD5 + SHA1 depending on key type.
-		 */
+
+		/* Write out the digest type if needbe. */
 		if (SSL_USE_SIGALGS(s))
 			{
-			const uint8_t *hdata;
-			size_t hdatalen;
 			md = s->cert->key->digest;
-			if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen) ||
-			    !tls12_get_sigandhash(p, pkey, md))
+			if (!tls12_get_sigandhash(p, pkey, md))
 				{
-				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_INTERNAL_ERROR);
+				OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_INTERNAL_ERROR);
 				goto err;
 				}
 			p += 2;
 			n += 2;
-			if (!EVP_DigestInit_ex(&mctx, md, NULL)
-				|| !EVP_DigestUpdate(&mctx, hdata, hdatalen)
-				|| !EVP_DigestFinal(&mctx, digest, &digest_length))
-				{
-				OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_EVP_LIB);
-				goto err;
-				}
 			}
-		else if (pkey->type == EVP_PKEY_RSA)
-			{
-			s->method->ssl3_enc->cert_verify_mac(s, NID_md5, digest);
-			s->method->ssl3_enc->cert_verify_mac(s,
-				NID_sha1, &digest[MD5_DIGEST_LENGTH]);
-			digest_length = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH;
-			/* Using a NULL signature MD makes EVP_PKEY_sign perform
-			 * a raw RSA signature, rather than wrapping in a
-			 * DigestInfo. */
-			md = NULL;
-			}
-		else if (pkey->type == EVP_PKEY_EC)
-			{
-			s->method->ssl3_enc->cert_verify_mac(s, NID_sha1, digest);
-			digest_length = SHA_DIGEST_LENGTH;
-			md = EVP_sha1();
-			}
-		else
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_INTERNAL_ERROR);
+
+		/* Compute the digest. */
+		if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey))
 			goto err;
-			}
+
+		/* The handshake buffer is no longer necessary. */
+		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+			goto err;
 
 		/* Sign the digest. */
 		pctx = EVP_PKEY_CTX_new(pkey, NULL);
@@ -2378,47 +2315,37 @@
 			goto err;
 
 		/* Initialize the EVP_PKEY_CTX and determine the size of the signature. */
-		if (EVP_PKEY_sign_init(pctx) != 1 ||
-			EVP_PKEY_CTX_set_signature_md(pctx, md) != 1 ||
-			EVP_PKEY_sign(pctx, NULL, &signature_length,
-				digest, digest_length) != 1)
+		if (!EVP_PKEY_sign_init(pctx) ||
+			!EVP_PKEY_CTX_set_signature_md(pctx, md) ||
+			!EVP_PKEY_sign(pctx, NULL, &signature_length,
+				digest, digest_length))
 			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_EVP_LIB);
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_EVP_LIB);
 			goto err;
 			}
 
 		if (p + 2 + signature_length > buf + SSL3_RT_MAX_PLAIN_LENGTH)
 			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, SSL_R_DATA_LENGTH_TOO_LONG);
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, SSL_R_DATA_LENGTH_TOO_LONG);
 			goto err;
 			}
 
-		if (EVP_PKEY_sign(pctx, &p[2], &signature_length,
-				digest, digest_length) != 1)
+		if (!EVP_PKEY_sign(pctx, &p[2], &signature_length,
+				digest, digest_length))
 			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_send_client_verify, ERR_R_EVP_LIB);
+			OPENSSL_PUT_ERROR(SSL, ssl3_send_cert_verify, ERR_R_EVP_LIB);
 			goto err;
 			}
 
 		s2n(signature_length, p);
 		n += signature_length + 2;
 
-		/* Now that client auth is completed, we no longer need cached
-		 * handshake records and can digest them. */
-		if (SSL_USE_SIGALGS(s))
-			{
-			if (!ssl3_digest_cached_records(s))
-				goto err;
-			}
-
 		ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n);
 		s->state=SSL3_ST_CW_CERT_VRFY_B;
 		}
-	EVP_MD_CTX_cleanup(&mctx);
 	EVP_PKEY_CTX_free(pctx);
 	return ssl_do_write(s);
 err:
-	EVP_MD_CTX_cleanup(&mctx);
 	EVP_PKEY_CTX_free(pctx);
 	return(-1);
 	}
@@ -2538,9 +2465,7 @@
 	EVP_PKEY *pkey=NULL;
 	SESS_CERT *sc;
 	RSA *rsa;
-#ifndef OPENSSL_NO_DH
 	DH *dh;
-#endif
 
 	/* we don't have a certificate */
 	if (!ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher))
@@ -2557,14 +2482,11 @@
 		}
 
 	rsa=s->session->sess_cert->peer_rsa_tmp;
-#ifndef OPENSSL_NO_DH
 	dh=s->session->sess_cert->peer_dh_tmp;
-#endif
 
 	/* This is the passed certificate */
 
 	idx=sc->peer_cert_type;
-#ifndef OPENSSL_NO_ECDH
 	if (idx == SSL_PKEY_ECC)
 		{
 		if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509,
@@ -2583,7 +2505,6 @@
 		OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, SSL_R_MISSING_ECDSA_SIGNING_CERT);
 		goto f_err;
 		}
-#endif
 	pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509);
 	i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey);
 	EVP_PKEY_free(pkey);
@@ -2601,14 +2522,12 @@
 		OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, SSL_R_MISSING_RSA_ENCRYPTING_CERT);
 		goto f_err;
 		}
-#ifndef OPENSSL_NO_DH
 	if ((alg_k & SSL_kEDH) && 
 		!(has_bits(i,EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL)))
 		{
 		OPENSSL_PUT_ERROR(SSL, ssl3_check_cert_and_algorithm, SSL_R_MISSING_DH_KEY);
 		goto f_err;
 		}
-#endif
 
 	return(1);
 f_err:
@@ -2617,7 +2536,6 @@
 	return(0);
 	}
 
-# if !defined(OPENSSL_NO_NEXTPROTONEG)
 int ssl3_send_next_proto(SSL *s)
 	{
 	unsigned int len, padding_len;
@@ -2642,7 +2560,6 @@
 	return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
 }
 
-# endif  /* !OPENSSL_NO_NEXTPROTONEG */
 
 int ssl3_send_channel_id(SSL *s)
 	{
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index b9e4026..d574b25 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -369,10 +369,8 @@
 
 		if (s->session->cipher != NULL)
 			{
-#ifndef OPENSSL_NO_RC4
 			if (s->session->cipher->algorithm_enc == SSL_RC4)
 				s->s3->need_record_splitting = 0;
-#endif
 			}
 		}
 
@@ -499,7 +497,7 @@
 
 void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len)
 	{
-	if (s->s3->handshake_buffer && !(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE)) 
+	if (s->s3->handshake_buffer)
 		{
 		BIO_write (s->s3->handshake_buffer,(void *)buf,len);
 		} 
@@ -546,12 +544,9 @@
 			s->s3->handshake_dgst[i]=NULL;
 			}
 		}
-	if (!(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE))
-		{
-		/* Free handshake_buffer BIO */
-		BIO_free(s->s3->handshake_buffer);
-		s->s3->handshake_buffer = NULL;
-		}
+	/* Free handshake_buffer BIO */
+	BIO_free(s->s3->handshake_buffer);
+	s->s3->handshake_buffer = NULL;
 
 	return 1;
 	}
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index cef94b1..5a1b48d 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -178,7 +178,7 @@
 	SSL_RC4,
 	SSL_MD5,
 	SSL_SSLV3,
-	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_MEDIUM,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF|SSL_CIPHER_ALGORITHM2_STATEFUL_AEAD,
 	128,
 	128,
@@ -194,7 +194,7 @@
 	SSL_RC4,
 	SSL_SHA1,
 	SSL_SSLV3,
-	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_MEDIUM,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -210,7 +210,7 @@
 	SSL_3DES,
 	SSL_SHA1,
 	SSL_SSLV3,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	112,
 	168,
@@ -228,7 +228,7 @@
 	SSL_RC4,
 	SSL_MD5,
 	SSL_SSLV3,
-	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_MEDIUM,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -245,7 +245,7 @@
 	SSL_AES128,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -260,7 +260,7 @@
 	SSL_AES128,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -275,7 +275,7 @@
 	SSL_AES128,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -291,7 +291,7 @@
 	SSL_AES256,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
@@ -307,7 +307,7 @@
 	SSL_AES256,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
@@ -323,7 +323,7 @@
 	SSL_AES256,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
@@ -340,7 +340,7 @@
 	SSL_AES128,
 	SSL_SHA256,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -356,7 +356,7 @@
 	SSL_AES256,
 	SSL_SHA256,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
@@ -374,7 +374,7 @@
 	SSL_AES128,
 	SSL_SHA256,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -390,7 +390,7 @@
 	SSL_AES256,
 	SSL_SHA256,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
@@ -406,7 +406,7 @@
 	SSL_AES128,
 	SSL_SHA256,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -422,7 +422,7 @@
 	SSL_AES256,
 	SSL_SHA256,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
@@ -439,7 +439,7 @@
 	SSL_RC4,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_MEDIUM,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -455,7 +455,7 @@
 	SSL_AES128,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -471,7 +471,7 @@
 	SSL_AES256,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
@@ -489,7 +489,7 @@
 	SSL_AES128GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	128,
 	128,
@@ -505,7 +505,7 @@
 	SSL_AES256GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|
 		SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	256,
@@ -522,7 +522,7 @@
 	SSL_AES128GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	128,
 	128,
@@ -538,7 +538,7 @@
 	SSL_AES256GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|
 		SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	256,
@@ -555,7 +555,7 @@
 	SSL_AES128GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	128,
 	128,
@@ -571,14 +571,13 @@
 	SSL_AES256GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|
 		SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	256,
 	256,
 	},
 
-#ifndef OPENSSL_NO_ECDH
 	/* Cipher C007 */
 	{
 	1,
@@ -589,7 +588,7 @@
 	SSL_RC4,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_MEDIUM,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -605,7 +604,7 @@
 	SSL_AES128,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -621,7 +620,7 @@
 	SSL_AES256,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
@@ -637,7 +636,7 @@
 	SSL_RC4,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_MEDIUM,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -653,7 +652,7 @@
 	SSL_AES128,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -669,7 +668,7 @@
 	SSL_AES256,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
@@ -685,7 +684,7 @@
 	SSL_RC4,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_MEDIUM,
+	SSL_MEDIUM,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -701,7 +700,7 @@
 	SSL_AES128,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	128,
 	128,
@@ -717,14 +716,12 @@
 	SSL_AES256,
 	SSL_SHA1,
 	SSL_TLSV1,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF,
 	256,
 	256,
 	},
-#endif	/* OPENSSL_NO_ECDH */
 
-#ifndef OPENSSL_NO_ECDH
 
 	/* HMAC based TLS v1.2 ciphersuites from RFC5289 */
 
@@ -738,7 +735,7 @@
 	SSL_AES128,
 	SSL_SHA256,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
 	128,
 	128,
@@ -754,7 +751,7 @@
 	SSL_AES256,
 	SSL_SHA384,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
 	256,
 	256,
@@ -770,7 +767,7 @@
 	SSL_AES128,
 	SSL_SHA256,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256,
 	128,
 	128,
@@ -786,7 +783,7 @@
 	SSL_AES256,
 	SSL_SHA384,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384,
 	256,
 	256,
@@ -804,7 +801,7 @@
 	SSL_AES128GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	128,
 	128,
@@ -820,7 +817,7 @@
 	SSL_AES256GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|
 		SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	256,
@@ -837,7 +834,7 @@
 	SSL_AES128GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	128,
 	128,
@@ -853,7 +850,7 @@
 	SSL_AES256GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH|SSL_FIPS,
+	SSL_HIGH|SSL_FIPS,
 	SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|
 		SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	256,
@@ -871,14 +868,13 @@
 	SSL_AES128GCM,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HIGH,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(4)|
 		SSL_CIPHER_ALGORITHM2_VARIABLE_NONCE_INCLUDED_IN_RECORD,
 	128,
 	128,
 	},
 
-#endif /* OPENSSL_NO_ECDH */
 
 	{
 	1,
@@ -889,7 +885,7 @@
 	SSL_CHACHA20POLY1305,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HIGH,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(0),
 	256,
 	0,
@@ -904,7 +900,7 @@
 	SSL_CHACHA20POLY1305,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HIGH,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(0),
 	256,
 	0,
@@ -919,7 +915,7 @@
 	SSL_CHACHA20POLY1305,
 	SSL_AEAD,
 	SSL_TLSV1_2,
-	SSL_NOT_EXP|SSL_HIGH,
+	SSL_HIGH,
 	SSL_HANDSHAKE_MAC_SHA256|TLS1_PRF_SHA256|SSL_CIPHER_ALGORITHM2_AEAD|FIXED_NONCE_LEN(0),
 	256,
 	0,
@@ -1014,14 +1010,10 @@
 		ssl3_release_read_buffer(s);
 	if (s->s3->wbuf.buf != NULL)
 		ssl3_release_write_buffer(s);
-#ifndef OPENSSL_NO_DH
 	if (s->s3->tmp.dh != NULL)
 		DH_free(s->s3->tmp.dh);
-#endif
-#ifndef OPENSSL_NO_ECDH
 	if (s->s3->tmp.ecdh != NULL)
 		EC_KEY_free(s->s3->tmp.ecdh);
-#endif
 
 	if (s->s3->tmp.ca_names != NULL)
 		sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free);
@@ -1052,20 +1044,16 @@
 		OPENSSL_free(s->s3->tmp.certificate_types);
 	s->s3->tmp.num_certificate_types = 0;
 
-#ifndef OPENSSL_NO_DH
 	if (s->s3->tmp.dh != NULL)
 		{
 		DH_free(s->s3->tmp.dh);
 		s->s3->tmp.dh = NULL;
 		}
-#endif
-#ifndef OPENSSL_NO_ECDH
 	if (s->s3->tmp.ecdh != NULL)
 		{
 		EC_KEY_free(s->s3->tmp.ecdh);
 		s->s3->tmp.ecdh = NULL;
 		}
-#endif
 	rp = s->s3->rbuf.buf;
 	wp = s->s3->wbuf.buf;
 	rlen = s->s3->rbuf.len;
@@ -1100,14 +1088,12 @@
 	s->s3->in_read_app_data=0;
 	s->version = s->method->version;
 
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
 	if (s->next_proto_negotiated)
 		{
 		OPENSSL_free(s->next_proto_negotiated);
 		s->next_proto_negotiated = NULL;
 		s->next_proto_negotiated_len = 0;
 		}
-#endif
 
 	s->s3->tlsext_channel_id_valid = 0;
 	}
@@ -1118,14 +1104,10 @@
 	{
 	int ret=0;
 
-	if (
-	    cmd == SSL_CTRL_SET_TMP_RSA ||
+	if (cmd == SSL_CTRL_SET_TMP_RSA ||
 	    cmd == SSL_CTRL_SET_TMP_RSA_CB ||
-#ifndef OPENSSL_NO_DSA
 	    cmd == SSL_CTRL_SET_TMP_DH ||
-	    cmd == SSL_CTRL_SET_TMP_DH_CB ||
-#endif
-		0)
+	    cmd == SSL_CTRL_SET_TMP_DH_CB)
 		{
 		if (!ssl_cert_inst(&s->cert))
 		    	{
@@ -1168,7 +1150,6 @@
 		return(ret);
 		}
 		break;
-#ifndef OPENSSL_NO_DH
 	case SSL_CTRL_SET_TMP_DH:
 		{
 			DH *dh = (DH *)parg;
@@ -1203,8 +1184,6 @@
 		return(ret);
 		}
 		break;
-#endif
-#ifndef OPENSSL_NO_ECDH
 	case SSL_CTRL_SET_TMP_ECDH:
 		{
 		EC_KEY *ecdh = NULL;
@@ -1241,7 +1220,6 @@
 		return(ret);
 		}
 		break;
-#endif /* !OPENSSL_NO_ECDH */
 	case SSL_CTRL_SET_TLSEXT_HOSTNAME:
  		if (larg == TLSEXT_NAMETYPE_host_name)
 			{
@@ -1274,44 +1252,6 @@
 		ret = 1;
 		break;
 
-	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE:
-		s->tlsext_status_type=larg;
-		ret = 1;
-		break;
-
-	case SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS:
-		*(STACK_OF(X509_EXTENSION) **)parg = s->tlsext_ocsp_exts;
-		ret = 1;
-		break;
-
-	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS:
-		s->tlsext_ocsp_exts = parg;
-		ret = 1;
-		break;
-
-	case SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS:
-		*(STACK_OF(OCSP_RESPID) **)parg = s->tlsext_ocsp_ids;
-		ret = 1;
-		break;
-
-	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS:
-		s->tlsext_ocsp_ids = parg;
-		ret = 1;
-		break;
-
-	case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP:
-		*(unsigned char **)parg = s->tlsext_ocsp_resp;
-		return s->tlsext_ocsp_resplen;
-		
-	case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP:
-		if (s->tlsext_ocsp_resp)
-			OPENSSL_free(s->tlsext_ocsp_resp);
-		s->tlsext_ocsp_resp = parg;
-		s->tlsext_ocsp_resplen = larg;
-		ret = 1;
-		break;
-
-
 	case SSL_CTRL_CHAIN:
 		if (larg)
 			return ssl_cert_set1_chain(s->cert,
@@ -1333,7 +1273,6 @@
 	case SSL_CTRL_SELECT_CURRENT_CERT:
 		return ssl_cert_select_current(s->cert, (X509 *)parg);
 
-#ifndef OPENSSL_NO_EC
 	case SSL_CTRL_GET_CURVES:
 		{
 		const uint16_t *clist;
@@ -1367,7 +1306,6 @@
 	case SSL_CTRL_SET_ECDH_AUTO:
 		s->cert->ecdh_tmp_auto = larg;
 		return 1;
-#endif
 	case SSL_CTRL_SET_SIGALGS:
 		return tls1_set_sigalgs(s->cert, parg, larg, 0);
 
@@ -1426,25 +1364,17 @@
 			EVP_PKEY *ptmp;
 			int rv = 0;
 			sc = s->session->sess_cert;
-#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DH) && !defined(OPENSSL_NO_EC)
-			if (!sc->peer_rsa_tmp && !sc->peer_dh_tmp
-							&& !sc->peer_ecdh_tmp)
+			if (!sc->peer_rsa_tmp && !sc->peer_dh_tmp && !sc->peer_ecdh_tmp)
 				return 0;
-#endif
 			ptmp = EVP_PKEY_new();
 			if (!ptmp)
 				return 0;
-			if (0);
-			else if (sc->peer_rsa_tmp)
+			if (sc->peer_rsa_tmp)
 				rv = EVP_PKEY_set1_RSA(ptmp, sc->peer_rsa_tmp);
-#ifndef OPENSSL_NO_DH
 			else if (sc->peer_dh_tmp)
 				rv = EVP_PKEY_set1_DH(ptmp, sc->peer_dh_tmp);
-#endif
-#ifndef OPENSSL_NO_ECDH
 			else if (sc->peer_ecdh_tmp)
 				rv = EVP_PKEY_set1_EC_KEY(ptmp, sc->peer_ecdh_tmp);
-#endif
 			if (rv)
 				{
 				*(EVP_PKEY **)parg = ptmp;
@@ -1453,7 +1383,6 @@
 			EVP_PKEY_free(ptmp);
 			return 0;
 			}
-#ifndef OPENSSL_NO_EC
 	case SSL_CTRL_GET_EC_POINT_FORMATS:
 		{
 		SSL_SESSION *sess = s->session;
@@ -1463,7 +1392,6 @@
 		*pformat = sess->tlsext_ecpointformatlist;
 		return (int)sess->tlsext_ecpointformatlist_length;
 		}
-#endif
 
 	case SSL_CTRL_CHANNEL_ID:
 		s->tlsext_channel_id_enabled = 1;
@@ -1510,12 +1438,7 @@
 	{
 	int ret=0;
 
-	if (
-	    cmd == SSL_CTRL_SET_TMP_RSA_CB ||
-#ifndef OPENSSL_NO_DSA
-	    cmd == SSL_CTRL_SET_TMP_DH_CB ||
-#endif
-		0)
+	if (cmd == SSL_CTRL_SET_TMP_RSA_CB || cmd == SSL_CTRL_SET_TMP_DH_CB)
 		{
 		if (!ssl_cert_inst(&s->cert))
 			{
@@ -1529,20 +1452,16 @@
 	case SSL_CTRL_SET_TMP_RSA_CB:
 		/* Ignore the callback; temporary RSA keys are never used. */
 		break;
-#ifndef OPENSSL_NO_DH
 	case SSL_CTRL_SET_TMP_DH_CB:
 		{
 		s->cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
 		}
 		break;
-#endif
-#ifndef OPENSSL_NO_ECDH
 	case SSL_CTRL_SET_TMP_ECDH_CB:
 		{
 		s->cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp;
 		}
 		break;
-#endif
 	case SSL_CTRL_SET_TLSEXT_DEBUG_CB:
 		s->tlsext_debug_cb=(void (*)(SSL *,int ,int,
 					unsigned char *, int, void *))fp;
@@ -1573,7 +1492,6 @@
 		return(0);
 		}
 		break;
-#ifndef OPENSSL_NO_DH
 	case SSL_CTRL_SET_TMP_DH:
 		{
 		DH *new=NULL,*dh;
@@ -1605,8 +1523,6 @@
 		return(0);
 		}
 		break;
-#endif
-#ifndef OPENSSL_NO_ECDH
 	case SSL_CTRL_SET_TMP_ECDH:
 		{
 		EC_KEY *ecdh = NULL;
@@ -1646,7 +1562,6 @@
 		return(0);
 		}
 		break;
-#endif /* !OPENSSL_NO_ECDH */
 	case SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG:
 		ctx->tlsext_servername_arg=parg;
 		break;
@@ -1681,7 +1596,6 @@
 		return 1;
 		break;
 
-#ifndef OPENSSL_NO_EC
 	case SSL_CTRL_SET_CURVES:
 		return tls1_set_curves(&ctx->tlsext_ellipticcurvelist,
 					&ctx->tlsext_ellipticcurvelist_length,
@@ -1690,7 +1604,6 @@
 	case SSL_CTRL_SET_ECDH_AUTO:
 		ctx->cert->ecdh_tmp_auto = larg;
 		return 1;
-#endif
 	case SSL_CTRL_SET_SIGALGS:
 		return tls1_set_sigalgs(ctx->cert, parg, larg, 0);
 
@@ -1792,20 +1705,16 @@
 	case SSL_CTRL_SET_TMP_RSA_CB:
 		/* Ignore the callback; temporary RSA keys are never used. */
 		break;
-#ifndef OPENSSL_NO_DH
 	case SSL_CTRL_SET_TMP_DH_CB:
 		{
 		cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp;
 		}
 		break;
-#endif
-#ifndef OPENSSL_NO_ECDH
 	case SSL_CTRL_SET_TMP_ECDH_CB:
 		{
 		cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp;
 		}
 		break;
-#endif
 	case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
 		ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
 		break;
@@ -1959,12 +1868,10 @@
 		       c->name);
 #endif
 
-#ifndef OPENSSL_NO_EC
 		/* if we are considering an ECC cipher suite that uses
 		 * an ephemeral EC key check it */
 		if (alg_k & SSL_kEECDH)
 			ok = ok && tls1_check_ec_tmp_key(s, c->id);
-#endif /* OPENSSL_NO_EC */
 
 		if (ok && sk_SSL_CIPHER_find(allow, &cipher_index, c))
 			{
@@ -2004,9 +1911,7 @@
 	const unsigned char *sig;
 	size_t i, siglen;
 	int have_rsa_sign = 0;
-#ifndef OPENSSL_NO_ECDSA
 	int have_ecdsa_sign = 0;
-#endif
 
 	/* If we have custom certificate types set, use them */
 	if (s->cert->client_certificate_types)
@@ -2025,18 +1930,15 @@
 			have_rsa_sign = 1;
 			break;
 
-#ifndef OPENSSL_NO_ECDSA
 		case TLSEXT_signature_ecdsa:
 			have_ecdsa_sign = 1;
 			break;
-#endif
 			}
 		}
 
 	if (have_rsa_sign)
 		p[ret++]=SSL3_CT_RSA_SIGN;
 
-#ifndef OPENSSL_NO_ECDSA
 	/* ECDSA certs can be used with RSA cipher suites as well 
 	 * so we don't need to check for SSL_kECDH or SSL_kEECDH
 	 */
@@ -2045,7 +1947,6 @@
 		if (have_ecdsa_sign)
 			p[ret++]=TLS_CT_ECDSA_SIGN;
 		}
-#endif	
 	return(ret);
 	}
 
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index 393d883..f5079a1 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -311,7 +311,7 @@
 		extra=0;
 	if (extra && !s->s3->init_extra)
 		{
-		/* An application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
+		/* An application error: SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
 		 * set after ssl3_setup_buffers() was done */
 		OPENSSL_PUT_ERROR(SSL, ssl3_get_record, ERR_R_INTERNAL_ERROR);
 		return -1;
@@ -760,9 +760,6 @@
 			if (eivlen <= 1)
 				eivlen = 0;
 			}
-		/* Need explicit part of IV for GCM mode */
-		else if (mode == EVP_CIPH_GCM_MODE)
-			eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
 		else
 			eivlen = 0;
 		}
@@ -1426,8 +1423,6 @@
 int ssl3_do_change_cipher_spec(SSL *s)
 	{
 	int i;
-	const char *sender;
-	int slen;
 
 	if (s->state & SSL_ST_ACCEPT)
 		i=SSL3_CHANGE_CIPHER_SERVER_READ;
@@ -1450,29 +1445,6 @@
 	if (!s->method->ssl3_enc->change_cipher_state(s,i))
 		return(0);
 
-	/* we have to record the message digest at
-	 * this point so we can get it before we read
-	 * the finished message */
-	if (s->state & SSL_ST_CONNECT)
-		{
-		sender=s->method->ssl3_enc->server_finished_label;
-		slen=s->method->ssl3_enc->server_finished_label_len;
-		}
-	else
-		{
-		sender=s->method->ssl3_enc->client_finished_label;
-		slen=s->method->ssl3_enc->client_finished_label_len;
-		}
-
-	i = s->method->ssl3_enc->final_finish_mac(s,
-		sender,slen,s->s3->tmp.peer_finish_md);
-	if (i == 0)
-		{
-		OPENSSL_PUT_ERROR(SSL, ssl3_do_change_cipher_spec, ERR_R_INTERNAL_ERROR);
-		return 0;
-		}
-	s->s3->tmp.peer_finish_md_len = i;
-
 	return(1);
 	}
 
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 9ec6885..0e9c7d5 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -148,6 +148,7 @@
 
 #define NETSCAPE_HANG_BUG
 
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -351,7 +352,7 @@
 				{
 				ret=ssl3_send_server_certificate(s);
 				if (ret <= 0) goto end;
-				if (s->tlsext_status_expected)
+				if (s->s3->tmp.certificate_status_expected)
 					s->state=SSL3_ST_SW_CERT_STATUS_A;
 				else
 					s->state=SSL3_ST_SW_KEY_EXCH_A;
@@ -485,54 +486,6 @@
 				goto end;
 			s->state=SSL3_ST_SR_CERT_VRFY_A;
 			s->init_num=0;
-
-			/* TODO(davidben): These two blocks are different
-			 * between SSL and DTLS. Resolve the difference and code
-			 * duplication. */
-			if (SSL_USE_SIGALGS(s))
-				{
-				if (!s->session->peer)
-					break;
-				/* For sigalgs freeze the handshake buffer
-				 * at this point and digest cached records.
-				 */
-				if (!s->s3->handshake_buffer)
-					{
-					OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR);
-					return -1;
-					}
-				s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
-				if (!ssl3_digest_cached_records(s))
-					return -1;
-				}
-			else
-				{
-				int offset=0;
-				int dgst_num;
-
-				/* We need to get hashes here so if there is
-				 * a client cert, it can be verified
-				 * FIXME - digest processing for CertificateVerify
-				 * should be generalized. But it is next step
-				 */
-				if (s->s3->handshake_buffer)
-					if (!ssl3_digest_cached_records(s))
-						return -1;
-				for (dgst_num=0; dgst_num<SSL_MAX_DIGEST;dgst_num++)	
-					if (s->s3->handshake_dgst[dgst_num]) 
-						{
-						int dgst_size;
-
-						s->method->ssl3_enc->cert_verify_mac(s,EVP_MD_CTX_type(s->s3->handshake_dgst[dgst_num]),&(s->s3->tmp.cert_verify_md[offset]));
-						dgst_size=EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
-						if (dgst_size < 0)
-							{
-							ret = -1;
-							goto end;
-							}
-						offset+=dgst_size;
-						}		
-				}
 			break;
 
 		case SSL3_ST_SR_CERT_VRFY_A:
@@ -547,9 +500,7 @@
 		case SSL3_ST_SR_CHANGE: {
 			char next_proto_neg = 0;
 			char channel_id = 0;
-# if !defined(OPENSSL_NO_NEXTPROTONEG)
 			next_proto_neg = s->s3->next_proto_neg_seen;
-# endif
 			channel_id = s->s3->tlsext_channel_id_valid;
 
 			/* At this point, the next message must be entirely
@@ -568,7 +519,6 @@
 			break;
 		}
 
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
 		case SSL3_ST_SR_NEXT_PROTO_A:
 		case SSL3_ST_SR_NEXT_PROTO_B:
 			ret=ssl3_get_next_proto(s);
@@ -579,7 +529,6 @@
 			else
 				s->state=SSL3_ST_SR_FINISHED_A;
 			break;
-#endif
 
 		case SSL3_ST_SR_CHANNEL_ID_A:
 		case SSL3_ST_SR_CHANNEL_ID_B:
@@ -614,12 +563,14 @@
 
 		case SSL3_ST_SW_SESSION_TICKET_A:
 		case SSL3_ST_SW_SESSION_TICKET_B:
-			ret=ssl3_send_newsession_ticket(s);
+			ret=ssl3_send_new_session_ticket(s);
 			if (ret <= 0) goto end;
 			s->state=SSL3_ST_SW_CHANGE_A;
 			s->init_num=0;
 			break;
 
+#if 0
+		// TODO(davidben): Implement OCSP stapling on the server.
 		case SSL3_ST_SW_CERT_STATUS_A:
 		case SSL3_ST_SW_CERT_STATUS_B:
 			ret=ssl3_send_cert_status(s);
@@ -627,6 +578,7 @@
 			s->state=SSL3_ST_SW_KEY_EXCH_A;
 			s->init_num=0;
 			break;
+#endif
 
 		case SSL3_ST_SW_CHANGE_A:
 		case SSL3_ST_SW_CHANGE_B:
@@ -778,6 +730,7 @@
 			SSL3_ST_SR_CLNT_HELLO_B,
 			SSL3_MT_CLIENT_HELLO,
 			SSL3_RT_MAX_PLAIN_LENGTH,
+			SSL_GET_MESSAGE_HASH_MESSAGE,
 			&ok);
 
 		if (!ok) return((int)n);
@@ -1187,16 +1140,6 @@
 	 * s->tmp.new_cipher	- the new cipher to use.
 	 */
 
-	/* Handles TLS extensions that we couldn't check earlier */
-	if (s->version >= SSL3_VERSION)
-		{
-		if (ssl_check_clienthello_tlsext_late(s) <= 0)
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CLIENTHELLO_TLSEXT);
-			goto err;
-			}
-		}
-
 	if (ret < 0) ret=-ret;
 	if (0)
 		{
@@ -1326,16 +1269,12 @@
 	int j,num;
 	unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
 	unsigned int u;
-#ifndef OPENSSL_NO_DH
 	DH *dh=NULL,*dhp;
-#endif
-#ifndef OPENSSL_NO_ECDH
 	EC_KEY *ecdh=NULL, *ecdhp;
 	unsigned char *encodedPoint = NULL;
 	int encodedlen = 0;
 	int curve_id = 0;
 	BN_CTX *bn_ctx = NULL; 
-#endif
 	const char* psk_identity_hint = NULL;
 	size_t psk_identity_hint_len = 0;
 	EVP_PKEY *pkey;
@@ -1372,7 +1311,6 @@
 				psk_identity_hint_len = 0;
 			n+=2+psk_identity_hint_len;
 			}
-#ifndef OPENSSL_NO_DH
 		if (alg_k & SSL_kEDH)
 			{
 			dhp=cert->dh_tmp;
@@ -1424,8 +1362,6 @@
 			r[2]=dh->pub_key;
 			}
 		else
-#endif
-#ifndef OPENSSL_NO_ECDH
 		if (alg_k & SSL_kEECDH)
 			{
 			const EC_GROUP *group;
@@ -1550,7 +1486,6 @@
 			r[3]=NULL;
 			}
 		else
-#endif /* !OPENSSL_NO_ECDH */
 		if (!(alg_k & SSL_kPSK))
 			{
 			al=SSL_AD_HANDSHAKE_FAILURE;
@@ -1607,7 +1542,6 @@
 				}
 			}
 
-#ifndef OPENSSL_NO_ECDH
 		if (alg_k & SSL_kEECDH)
 			{
 			/* XXX: For now, we only support named (not generic) curves.
@@ -1631,7 +1565,6 @@
 			encodedPoint = NULL;
 			p += encodedlen;
 			}
-#endif /* OPENSSL_NO_ECDH */
 
 		/* not anonymous */
 		if (pkey != NULL)
@@ -1715,10 +1648,8 @@
 f_err:
 	ssl3_send_alert(s,SSL3_AL_FATAL,al);
 err:
-#ifndef OPENSSL_NO_ECDH
 	if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
 	BN_CTX_free(bn_ctx);
-#endif
 	EVP_MD_CTX_cleanup(&md_ctx);
 	return(-1);
 	}
@@ -1823,25 +1754,22 @@
 	RSA *rsa=NULL;
 	uint8_t *decrypt_buf = NULL;
 	EVP_PKEY *pkey=NULL;
-#ifndef OPENSSL_NO_DH
 	BIGNUM *pub=NULL;
 	DH *dh_srvr;
-#endif
 
-#ifndef OPENSSL_NO_ECDH
 	EC_KEY *srvr_ecdh = NULL;
 	EVP_PKEY *clnt_pub_pkey = NULL;
 	EC_POINT *clnt_ecpoint = NULL;
 	BN_CTX *bn_ctx = NULL;
 	unsigned int psk_len = 0;
 	unsigned char psk[PSK_MAX_PSK_LEN];
-#endif
 
 	n=s->method->ssl_get_message(s,
 		SSL3_ST_SR_KEY_EXCH_A,
 		SSL3_ST_SR_KEY_EXCH_B,
 		SSL3_MT_CLIENT_KEY_EXCHANGE,
 		2048, /* ??? */
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 
 	if (!ok) return((int)n);
@@ -2063,7 +1991,6 @@
 
 		premaster_secret_len = sizeof(rand_premaster_secret);
 		}
-#ifndef OPENSSL_NO_DH
 	else if (alg_k & SSL_kEDH)
 		{
 		CBS dh_Yc;
@@ -2116,9 +2043,7 @@
 
 		premaster_secret_len = dh_len;
 		}
-#endif
 
-#ifndef OPENSSL_NO_ECDH
 	else if (alg_k & SSL_kEECDH)
 		{
 		int field_size = 0, ecdh_len;
@@ -2213,7 +2138,6 @@
 
 		premaster_secret_len = ecdh_len;
 		}
-#endif
 	else if (alg_k & SSL_kPSK)
 		{
 		/* For plain PSK, other_secret is a block of 0s with the same
@@ -2283,41 +2207,34 @@
 		}
 	if (decrypt_buf)
 		OPENSSL_free(decrypt_buf);
-#ifndef OPENSSL_NO_ECDH
 	EVP_PKEY_free(clnt_pub_pkey);
 	EC_POINT_free(clnt_ecpoint);
 	if (srvr_ecdh != NULL) 
 		EC_KEY_free(srvr_ecdh);
 	BN_CTX_free(bn_ctx);
-#endif
 	return(-1);
 	}
 
 int ssl3_get_cert_verify(SSL *s)
 	{
-	EVP_PKEY *pkey=NULL;
 	int al,ok,ret=0;
 	long n;
 	CBS certificate_verify, signature;
-	int type = 0;
 	X509 *peer = s->session->peer;
+	EVP_PKEY *pkey = NULL;
 	const EVP_MD *md = NULL;
-	EVP_MD_CTX mctx;
+	uint8_t digest[EVP_MAX_MD_SIZE];
+	size_t digest_length;
+	EVP_PKEY_CTX *pctx = NULL;
 
-	EVP_MD_CTX_init(&mctx);
-
-	/* Determine if a CertificateVerify message is expected at all. It is
-	 * important that this be determined before ssl_get_message is called,
-	 * so as not to process the ChangeCipherSpec message early. */
-	if (peer != NULL)
+	/* Only RSA and ECDSA client certificates are supported, so a
+	 * CertificateVerify is required if and only if there's a
+	 * client certificate. */
+	if (peer == NULL)
 		{
-		pkey = X509_get_pubkey(peer);
-		type = X509_certificate_type(peer,pkey);
-		}
-	if (!(type & EVP_PKT_SIGN))
-		{
-		ret = 1;
-		goto done_with_buffer;
+		if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+			return -1;
+		return 1;
 		}
 
 	n=s->method->ssl_get_message(s,
@@ -2325,26 +2242,42 @@
 		SSL3_ST_SR_CERT_VRFY_B,
 		SSL3_MT_CERTIFICATE_VERIFY,
 		SSL3_RT_MAX_PLAIN_LENGTH,
+		SSL_GET_MESSAGE_DONT_HASH_MESSAGE,
 		&ok);
 
 	if (!ok)
+		return (int)n;
+
+	/* Filter out unsupported certificate types. */
+	pkey = X509_get_pubkey(peer);
+	if (!(X509_certificate_type(peer, pkey) & EVP_PKT_SIGN) ||
+		(pkey->type != EVP_PKEY_RSA && pkey->type != EVP_PKEY_EC))
 		{
-		ret = (int)n;
-		goto done;
+		al = SSL_AD_UNSUPPORTED_CERTIFICATE;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE);
+		goto f_err;
 		}
 
 	CBS_init(&certificate_verify, s->init_msg, n);
 
-	/* We now have a signature that we need to verify. */
-	/* TODO(davidben): This should share code with
-	 * ssl3_get_server_key_exchange. */
-
+	/* Determine the digest type if needbe. */
 	if (SSL_USE_SIGALGS(s))
 		{
 		if (!tls12_check_peer_sigalg(&md, &al, s, &certificate_verify, pkey))
 			goto f_err;
 		}
 
+	/* Compute the digest. */
+	if (!ssl3_cert_verify_hash(s, digest, &digest_length, &md, pkey))
+		goto err;
+
+	/* The handshake buffer is no longer necessary, and we may hash the
+	 * current message.*/
+	if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+		goto err;
+	ssl3_hash_current_message(s);
+
+	/* Parse and verify the signature. */
 	if (!CBS_get_u16_length_prefixed(&certificate_verify, &signature) ||
 		CBS_len(&certificate_verify) != 0)
 		{
@@ -2353,87 +2286,27 @@
 		goto f_err;
 		}
 
-	if (SSL_USE_SIGALGS(s))
+	pctx = EVP_PKEY_CTX_new(pkey, NULL);
+	if (pctx == NULL)
+		goto err;
+	if (!EVP_PKEY_verify_init(pctx) ||
+		!EVP_PKEY_CTX_set_signature_md(pctx, md) ||
+		!EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature),
+			digest, digest_length))
 		{
-		size_t hdatalen;
-		const uint8_t *hdata;
-		if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen))
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR);
-			al=SSL_AD_INTERNAL_ERROR;
-			goto f_err;
-			}
-		if (!EVP_VerifyInit_ex(&mctx, md, NULL)
-			|| !EVP_VerifyUpdate(&mctx, hdata, hdatalen))
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_EVP_LIB);
-			al=SSL_AD_INTERNAL_ERROR;
-			goto f_err;
-			}
-
-		if (EVP_VerifyFinal(&mctx,
-				CBS_data(&signature), CBS_len(&signature),
-				pkey) <= 0)
-			{
-			al=SSL_AD_DECRYPT_ERROR;
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE);
-			goto f_err;
-			}
-		}
-	else
-	if (pkey->type == EVP_PKEY_RSA)
-		{
-		if (!RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
-				MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
-				CBS_data(&signature), CBS_len(&signature),
-				pkey->pkey.rsa))
-			{
-			al = SSL_AD_DECRYPT_ERROR;
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_RSA_SIGNATURE);
-			goto f_err;
-			}
-		}
-	else
-#ifndef OPENSSL_NO_ECDSA
-		if (pkey->type == EVP_PKEY_EC)
-		{
-		if (!ECDSA_verify(pkey->save_type,
-				&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-				SHA_DIGEST_LENGTH,
-				CBS_data(&signature), CBS_len(&signature),
-				pkey->pkey.ec))
-			{
-			/* bad signature */
-			al = SSL_AD_DECRYPT_ERROR;
-			OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_ECDSA_SIGNATURE);
-			goto f_err;
-			}
-		}
-	else
-#endif
-		{
-		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, ERR_R_INTERNAL_ERROR);
-		al=SSL_AD_UNSUPPORTED_CERTIFICATE;
+		al = SSL_AD_DECRYPT_ERROR;
+		OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_verify, SSL_R_BAD_SIGNATURE);
 		goto f_err;
 		}
 
-
-	ret=1;
+	ret = 1;
 	if (0)
 		{
 f_err:
 		ssl3_send_alert(s,SSL3_AL_FATAL,al);
 		}
-done_with_buffer:
-	/* There is no more need for the handshake buffer. */
-	if (s->s3->handshake_buffer)
-		{
-		BIO_free(s->s3->handshake_buffer);
-		s->s3->handshake_buffer = NULL;
-		s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
-		}
-done:
-	EVP_MD_CTX_cleanup(&mctx);
+err:
+	EVP_PKEY_CTX_free(pctx);
 	EVP_PKEY_free(pkey);
 	return(ret);
 	}
@@ -2453,6 +2326,7 @@
 		SSL3_ST_SR_CERT_B,
 		-1,
 		s->max_cert_list,
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 
 	if (!ok) return((int)n);
@@ -2643,7 +2517,7 @@
 	}
 
 /* send a new session ticket (not necessarily for a new session) */
-int ssl3_send_newsession_ticket(SSL *s)
+int ssl3_send_new_session_ticket(SSL *s)
 	{
 	if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
 		{
@@ -2770,6 +2644,7 @@
 	return ssl_do_write(s);
 	}
 
+#if 0
 int ssl3_send_cert_status(SSL *s)
 	{
 	if (s->state == SSL3_ST_SW_CERT_STATUS_A)
@@ -2804,8 +2679,8 @@
 	/* SSL3_ST_SW_CERT_STATUS_B */
 	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
 	}
+#endif
 
-# ifndef OPENSSL_NO_NEXTPROTONEG
 /* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
  * sets the next_proto member in s if found */
 int ssl3_get_next_proto(SSL *s)
@@ -2827,6 +2702,7 @@
 		SSL3_ST_SR_NEXT_PROTO_B,
 		SSL3_MT_NEXT_PROTO,
 		514,  /* See the payload format below */
+		SSL_GET_MESSAGE_HASH_MESSAGE,
 		&ok);
 
 	if (!ok)
@@ -2863,13 +2739,15 @@
 
 	return 1;
 	}
-# endif
 
 /* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
 int ssl3_get_channel_id(SSL *s)
 	{
 	int ret = -1, ok;
 	long n;
+	EVP_MD_CTX md_ctx;
+	uint8_t channel_id_hash[SHA256_DIGEST_LENGTH];
+	unsigned int channel_id_hash_len;
 	const uint8_t *p;
 	uint16_t extension_type, expected_extension_type;
 	EC_GROUP* p256 = NULL;
@@ -2879,33 +2757,32 @@
 	BIGNUM x, y;
 	CBS encrypted_extensions, extension;
 
-	if (s->state == SSL3_ST_SR_CHANNEL_ID_A && s->init_num == 0)
-		{
-		/* The first time that we're called we take the current
-		 * handshake hash and store it. */
-		EVP_MD_CTX md_ctx;
-		unsigned int len;
-
-		EVP_MD_CTX_init(&md_ctx);
-		EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL);
-		if (!tls1_channel_id_hash(&md_ctx, s))
-			return -1;
-		len = sizeof(s->s3->tlsext_channel_id);
-		EVP_DigestFinal(&md_ctx, s->s3->tlsext_channel_id, &len);
-		EVP_MD_CTX_cleanup(&md_ctx);
-		}
-
 	n = s->method->ssl_get_message(s,
 		SSL3_ST_SR_CHANNEL_ID_A,
 		SSL3_ST_SR_CHANNEL_ID_B,
 		SSL3_MT_ENCRYPTED_EXTENSIONS,
 		2 + 2 + TLSEXT_CHANNEL_ID_SIZE,
+		SSL_GET_MESSAGE_DONT_HASH_MESSAGE,
 		&ok);
 
 	if (!ok)
 		return((int)n);
 
-	ssl3_finish_mac(s, (unsigned char*)s->init_buf->data, s->init_num + 4);
+	/* Before incorporating the EncryptedExtensions message to the
+	 * handshake hash, compute the hash that should have been signed. */
+	channel_id_hash_len = sizeof(channel_id_hash);
+	EVP_MD_CTX_init(&md_ctx);
+	if (!EVP_DigestInit_ex(&md_ctx, EVP_sha256(), NULL) ||
+		!tls1_channel_id_hash(&md_ctx, s) ||
+		!EVP_DigestFinal(&md_ctx, channel_id_hash, &channel_id_hash_len))
+		{
+		EVP_MD_CTX_cleanup(&md_ctx);
+		return -1;
+		}
+	EVP_MD_CTX_cleanup(&md_ctx);
+	assert(channel_id_hash_len == SHA256_DIGEST_LENGTH);
+
+	ssl3_hash_current_message(s);
 
 	/* s->state doesn't reflect whether ChangeCipherSpec has been received
 	 * in this handshake, but s->s3->change_cipher_spec does (will be reset
@@ -2978,17 +2855,12 @@
 
 	/* We stored the handshake hash in |tlsext_channel_id| the first time
 	 * that we were called. */
-	switch (ECDSA_do_verify(s->s3->tlsext_channel_id, SHA256_DIGEST_LENGTH, &sig, key)) {
-	case 1:
-		break;
-	case 0:
+	if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key))
+		{
 		OPENSSL_PUT_ERROR(SSL, ssl3_get_channel_id, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
 		s->s3->tlsext_channel_id_valid = 0;
 		goto err;
-	default:
-		s->s3->tlsext_channel_id_valid = 0;
-		goto err;
-	}
+		}
 
 	memcpy(s->s3->tlsext_channel_id, p, 64);
 	ret = 1;
diff --git a/ssl/ssl_algs.c b/ssl/ssl_algs.c
index 8f7ede6..a1aa7b2 100644
--- a/ssl/ssl_algs.c
+++ b/ssl/ssl_algs.c
@@ -56,14 +56,14 @@
 
 #include "ssl_locl.h"
 
+#include <openssl/crypto.h>
 
 extern const ERR_STRING_DATA SSL_error_string_data[];
 
 int SSL_library_init(void)
 	{
-	ERR_load_crypto_strings();
-	ERR_load_strings(SSL_error_string_data);
-	ssl_load_ciphers();
+	CRYPTO_library_init();
+	SSL_load_error_strings();
 	return(1);
 	}
 
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 9f372f9..8acd0eb 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -119,12 +119,14 @@
 	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;
 
 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;
+	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;
@@ -259,6 +261,22 @@
 		a.original_handshake_hash.data = in->original_handshake_hash;
 		}
 
+	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->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;
+		}
+
 	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);
@@ -290,6 +308,11 @@
 		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);
 
 	M_ASN1_I2D_seq_total();
 
@@ -324,6 +347,11 @@
 		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);
 
 	M_ASN1_I2D_finish();
 	}
@@ -572,5 +600,30 @@
 		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);
 	}
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index bab0eff..5e9d41d 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -161,9 +161,7 @@
 	/* Set digest values to defaults */
 	cert->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
 	cert->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
-#ifndef OPENSSL_NO_ECDSA
 	cert->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
-#endif
 	}
 
 CERT *ssl_cert_new(void)
@@ -205,7 +203,6 @@
 	ret->mask_k = cert->mask_k;
 	ret->mask_a = cert->mask_a;
 
-#ifndef OPENSSL_NO_DH
 	if (cert->dh_tmp != NULL)
 		{
 		ret->dh_tmp = DHparams_dup(cert->dh_tmp);
@@ -236,9 +233,7 @@
 			}
 		}
 	ret->dh_tmp_cb = cert->dh_tmp_cb;
-#endif
 
-#ifndef OPENSSL_NO_ECDH
 	if (cert->ecdh_tmp)
 		{
 		ret->ecdh_tmp = EC_KEY_dup(cert->ecdh_tmp);
@@ -250,7 +245,6 @@
 		}
 	ret->ecdh_tmp_cb = cert->ecdh_tmp_cb;
 	ret->ecdh_tmp_auto = cert->ecdh_tmp_auto;
-#endif
 
 	for (i = 0; i < SSL_PKEY_NUM; i++)
 		{
@@ -366,17 +360,11 @@
 
 	return(ret);
 	
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH)
 err:
-#endif
-#ifndef OPENSSL_NO_DH
 	if (ret->dh_tmp != NULL)
 		DH_free(ret->dh_tmp);
-#endif
-#ifndef OPENSSL_NO_ECDH
 	if (ret->ecdh_tmp != NULL)
 		EC_KEY_free(ret->ecdh_tmp);
-#endif
 
 	ssl_cert_clear_certs(ret);
 
@@ -418,12 +406,8 @@
 	if(c == NULL)
 	    return;
 
-#ifndef OPENSSL_NO_DH
 	if (c->dh_tmp) DH_free(c->dh_tmp);
-#endif
-#ifndef OPENSSL_NO_ECDH
 	if (c->ecdh_tmp) EC_KEY_free(c->ecdh_tmp);
-#endif
 
 	ssl_cert_clear_certs(c);
 	if (c->peer_sigalgs)
@@ -591,14 +575,10 @@
 
 	if (sc->peer_rsa_tmp != NULL)
 		RSA_free(sc->peer_rsa_tmp);
-#ifndef OPENSSL_NO_DH
 	if (sc->peer_dh_tmp != NULL)
 		DH_free(sc->peer_dh_tmp);
-#endif
-#ifndef OPENSSL_NO_ECDH
 	if (sc->peer_ecdh_tmp != NULL)
 		EC_KEY_free(sc->peer_ecdh_tmp);
-#endif
 
 	OPENSSL_free(sc);
 	}
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index 0caed0b..fbed548 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -147,34 +147,18 @@
 
 #include "ssl_locl.h"
 
-#define SSL_ENC_3DES_IDX	0
-#define SSL_ENC_RC4_IDX		1
-#define SSL_ENC_AES128_IDX	2
-#define SSL_ENC_AES256_IDX	3
-#define SSL_ENC_NUM_IDX		4
-
-
-static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX]= { 0 };
-
-#define SSL_MD_MD5_IDX	0
-#define SSL_MD_SHA1_IDX	1
-#define SSL_MD_SHA256_IDX 2
-#define SSL_MD_SHA384_IDX 3
-/*Constant SSL_MAX_DIGEST equal to size of digests array should be 
- * defined in the
- * ssl_locl.h */
-#define SSL_MD_NUM_IDX	SSL_MAX_DIGEST 
-static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX] = { 0 };
-static const int ssl_mac_pkey_id[SSL_MD_NUM_IDX]={
-	EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC,
+struct handshake_digest
+	{
+	long mask;
+	const EVP_MD *(*md_func)(void);
 	};
 
-static int ssl_mac_secret_size[SSL_MD_NUM_IDX] = { 0 };
-
-static const int ssl_handshake_digest_flag[SSL_MD_NUM_IDX]={
-	SSL_HANDSHAKE_MAC_MD5, SSL_HANDSHAKE_MAC_SHA,
-	SSL_HANDSHAKE_MAC_SHA256, SSL_HANDSHAKE_MAC_SHA384,
-	};
+static const struct handshake_digest ssl_handshake_digests[SSL_MAX_DIGEST] = {
+	{ SSL_HANDSHAKE_MAC_MD5, EVP_md5 },
+	{ SSL_HANDSHAKE_MAC_SHA, EVP_sha1 },
+	{ SSL_HANDSHAKE_MAC_SHA256, EVP_sha256 },
+	{ SSL_HANDSHAKE_MAC_SHA384, EVP_sha384 },
+};
 
 #define CIPHER_ADD	1
 #define CIPHER_KILL	2
@@ -255,26 +239,6 @@
 	{0,SSL_TXT_FIPS,0,    0,0,0,0,0,SSL_FIPS,  0,0,0},
 	};
 
-void ssl_load_ciphers(void)
-	{
-	ssl_cipher_methods[SSL_ENC_3DES_IDX]= EVP_des_ede3_cbc();
-	ssl_cipher_methods[SSL_ENC_RC4_IDX]= EVP_rc4();
-	ssl_cipher_methods[SSL_ENC_AES128_IDX]= EVP_aes_128_cbc();
-	ssl_cipher_methods[SSL_ENC_AES256_IDX]= EVP_aes_256_cbc();
-
-	ssl_digest_methods[SSL_MD_MD5_IDX]= EVP_md5();
-	ssl_mac_secret_size[SSL_MD_MD5_IDX]= EVP_MD_size(EVP_md5());
-	assert(ssl_mac_secret_size[SSL_MD_MD5_IDX] >= 0);
-	ssl_digest_methods[SSL_MD_SHA1_IDX]=EVP_sha1();
-	ssl_mac_secret_size[SSL_MD_SHA1_IDX]= EVP_MD_size(EVP_sha1());
-	assert(ssl_mac_secret_size[SSL_MD_SHA1_IDX] >= 0);
-
-	ssl_digest_methods[SSL_MD_SHA256_IDX]= EVP_sha256();
-	ssl_mac_secret_size[SSL_MD_SHA256_IDX]= EVP_MD_size(EVP_sha256());
-	ssl_digest_methods[SSL_MD_SHA384_IDX]= EVP_sha384();
-	ssl_mac_secret_size[SSL_MD_SHA384_IDX]= EVP_MD_size(EVP_sha384());
-	}
-
 /* ssl_cipher_get_evp_aead sets |*aead| to point to the correct EVP_AEAD object
  * for |s->cipher|. It returns 1 on success and 0 on error. */
 int ssl_cipher_get_evp_aead(const SSL_SESSION *s, const EVP_AEAD **aead)
@@ -289,7 +253,6 @@
 	    (c->algorithm2 & SSL_CIPHER_ALGORITHM2_STATEFUL_AEAD) == 0)
 		return 0;
 
-#ifndef OPENSSL_NO_AES
 	switch (c->algorithm_enc)
 		{
 	case SSL_AES128GCM:
@@ -308,7 +271,6 @@
 			return 0;
 		return 1;
 	}
-#endif
 
 	return 0;
 	}
@@ -316,7 +278,6 @@
 int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc,
 	     const EVP_MD **md, int *mac_pkey_type, int *mac_secret_size)
 	{
-	int i;
 	const SSL_CIPHER *c;
 
 	c=s->cipher;
@@ -332,40 +293,32 @@
 	switch (c->algorithm_enc)
 		{
 	case SSL_3DES:
-		i=SSL_ENC_3DES_IDX;
+		*enc = EVP_des_ede3_cbc();
 		break;
 	case SSL_RC4:
-		i=SSL_ENC_RC4_IDX;
+		*enc = EVP_rc4();
 		break;
 	case SSL_AES128:
-		i=SSL_ENC_AES128_IDX;
+		*enc = EVP_aes_128_cbc();
 		break;
 	case SSL_AES256:
-		i=SSL_ENC_AES256_IDX;
+		*enc = EVP_aes_256_cbc();
 		break;
 	default:
-		i= -1;
-		break;
+		return 0;
 		}
 
-	if ((i < 0) || (i >= SSL_ENC_NUM_IDX))
-		*enc=NULL;
-	else
-		*enc=ssl_cipher_methods[i];
-
 	if (!ssl_cipher_get_mac(s, md, mac_pkey_type, mac_secret_size))
 		return 0;
 
-	if ((*enc != NULL) &&
-	    (*md != NULL || (EVP_CIPHER_flags(*enc)&EVP_CIPH_FLAG_AEAD_CIPHER)) &&
-	    (!mac_pkey_type||*mac_pkey_type != NID_undef))
-		{
+	assert(*enc != NULL && *md != NULL);
+
+	/* TODO(fork): enable the stitched cipher modes. */
+#if 0
 		if (s->ssl_version>>8 != TLS1_VERSION_MAJOR ||
 		    s->ssl_version < TLS1_VERSION)
 			return 1;
 
-		/* TODO(fork): enable the stitched cipher modes. */
-#if 0
 		if	(c->algorithm_enc == SSL_RC4 &&
 			 c->algorithm_mac == SSL_MD5 &&
 			 (evp=EVP_get_cipherbyname("RC4-HMAC-MD5")))
@@ -379,15 +332,12 @@
 			 (evp=EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA1")))
 			*enc = evp, *md = NULL;
 #endif
-		return(1);
-		}
-	else
-		return(0);
+
+	return 1;
 	}
 
 int ssl_cipher_get_mac(const SSL_SESSION *s, const EVP_MD **md, int *mac_pkey_type, int *mac_secret_size)
 	{
-	int i;
 	const SSL_CIPHER *c;
 
 	c=s->cipher;
@@ -396,49 +346,40 @@
 	switch (c->algorithm_mac)
 		{
 	case SSL_MD5:
-		i=SSL_MD_MD5_IDX;
+		*md = EVP_md5();
 		break;
 	case SSL_SHA1:
-		i=SSL_MD_SHA1_IDX;
+		*md = EVP_sha1();
 		break;
 	case SSL_SHA256:
-		i=SSL_MD_SHA256_IDX;
+		*md = EVP_sha256();
 		break;
 	case SSL_SHA384:
-		i=SSL_MD_SHA384_IDX;
+		*md = EVP_sha384();
 		break;
 	default:
-		i= -1;
-		break;
+		return 0;
 		}
 
-	if ((i < 0) || (i >= SSL_MD_NUM_IDX))
+	if (mac_pkey_type != NULL)
 		{
-		*md=NULL; 
-		if (mac_pkey_type!=NULL) *mac_pkey_type = NID_undef;
-		if (mac_secret_size!=NULL) *mac_secret_size = 0;
+		*mac_pkey_type = EVP_PKEY_HMAC;
 		}
-	else
+	if (mac_secret_size!=NULL)
 		{
-		*md=ssl_digest_methods[i];
-		if (mac_pkey_type!=NULL) *mac_pkey_type = ssl_mac_pkey_id[i];
-		if (mac_secret_size!=NULL) *mac_secret_size = ssl_mac_secret_size[i];
+		*mac_secret_size = EVP_MD_size(*md);
 		}
-
 	return 1;
 	}
 
 int ssl_get_handshake_digest(int idx, long *mask, const EVP_MD **md) 
 {
-	if (idx <0||idx>=SSL_MD_NUM_IDX) 
+	if (idx < 0 || idx >= SSL_MAX_DIGEST)
 		{
 		return 0;
 		}
-	*mask = ssl_handshake_digest_flag[idx];
-	if (*mask)
-		*md = ssl_digest_methods[idx];
-	else
-		*md = NULL;
+	*mask = ssl_handshake_digests[idx].mask;
+	*md = ssl_handshake_digests[idx].md_func();
 	return 1;
 }
 
@@ -477,31 +418,8 @@
 	*head=curr;
 	}
 
-static void ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, unsigned long *enc, unsigned long *mac, unsigned long *ssl)
-	{
-	*mkey = 0;
-	*auth = 0;
-	*enc = 0;
-	*mac = 0;
-	*ssl = 0;
-
-	*enc |= (ssl_cipher_methods[SSL_ENC_3DES_IDX] == NULL) ? SSL_3DES:0;
-	*enc |= (ssl_cipher_methods[SSL_ENC_RC4_IDX ] == NULL) ? SSL_RC4 :0;
-	*enc |= (ssl_cipher_methods[SSL_ENC_AES128_IDX] == NULL) ? SSL_AES128:0;
-	*enc |= (ssl_cipher_methods[SSL_ENC_AES256_IDX] == NULL) ? SSL_AES256:0;
-
-	*mac |= (ssl_digest_methods[SSL_MD_MD5_IDX ] == NULL) ? SSL_MD5 :0;
-	*mac |= (ssl_digest_methods[SSL_MD_SHA1_IDX] == NULL) ? SSL_SHA1:0;
-	*mac |= (ssl_digest_methods[SSL_MD_SHA256_IDX] == NULL) ? SSL_SHA256:0;
-	*mac |= (ssl_digest_methods[SSL_MD_SHA384_IDX] == NULL) ? SSL_SHA384:0;
-
-	}
-
 static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method,
                 int num_of_ciphers,
-                unsigned long disabled_mkey, unsigned long disabled_auth,
-                unsigned long disabled_enc, unsigned long disabled_mac,
-                unsigned long disabled_ssl,
                 CIPHER_ORDER *co_list,
                 CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p)
 	{
@@ -521,12 +439,7 @@
 		{
 		c = ssl_method->get_cipher(i);
 		/* drop those that use any of that is not available */
-		if ((c != NULL) && c->valid &&
-		    !(c->algorithm_mkey & disabled_mkey) &&
-		    !(c->algorithm_auth & disabled_auth) &&
-		    !(c->algorithm_enc & disabled_enc) &&
-		    !(c->algorithm_mac & disabled_mac) &&
-		    !(c->algorithm_ssl & disabled_ssl))
+		if ((c != NULL) && c->valid)
 			{
 			co_list[co_list_num].cipher = c;
 			co_list[co_list_num].next = NULL;
@@ -572,19 +485,11 @@
 
 static void ssl_cipher_collect_aliases(const SSL_CIPHER **ca_list,
                         int num_of_group_aliases,
-                        unsigned long disabled_mkey, unsigned long disabled_auth,
-                        unsigned long disabled_enc, unsigned long disabled_mac,
-                        unsigned long disabled_ssl,
 			CIPHER_ORDER *head)
 	{
 	CIPHER_ORDER *ciph_curr;
 	const SSL_CIPHER **ca_curr;
 	int i;
-	unsigned long mask_mkey = ~disabled_mkey;
-	unsigned long mask_auth = ~disabled_auth;
-	unsigned long mask_enc = ~disabled_enc;
-	unsigned long mask_mac = ~disabled_mac;
-	unsigned long mask_ssl = ~disabled_ssl;
 
 	/*
 	 * First, add the real ciphers as already collected
@@ -606,32 +511,6 @@
 	 */
 	for (i = 0; i < num_of_group_aliases; i++)
 		{
-		unsigned long algorithm_mkey = cipher_aliases[i].algorithm_mkey;
-		unsigned long algorithm_auth = cipher_aliases[i].algorithm_auth;
-		unsigned long algorithm_enc = cipher_aliases[i].algorithm_enc;
-		unsigned long algorithm_mac = cipher_aliases[i].algorithm_mac;
-		unsigned long algorithm_ssl = cipher_aliases[i].algorithm_ssl;
-
-		if (algorithm_mkey)
-			if ((algorithm_mkey & mask_mkey) == 0)
-				continue;
-	
-		if (algorithm_auth)
-			if ((algorithm_auth & mask_auth) == 0)
-				continue;
-		
-		if (algorithm_enc)
-			if ((algorithm_enc & mask_enc) == 0)
-				continue;
-		
-		if (algorithm_mac)
-			if ((algorithm_mac & mask_mac) == 0)
-				continue;
-		
-		if (algorithm_ssl)
-			if ((algorithm_ssl & mask_ssl) == 0)
-				continue;
-		
 		*ca_curr = cipher_aliases + i;
 		ca_curr++;
 		}
@@ -714,9 +593,7 @@
 				continue;
 			if (alg_ssl && !(alg_ssl & cp->algorithm_ssl))
 				continue;
-			if ((algo_strength & SSL_EXP_MASK) && !(algo_strength & SSL_EXP_MASK & cp->algo_strength))
-				continue;
-			if ((algo_strength & SSL_STRONG_MASK) && !(algo_strength & SSL_STRONG_MASK & cp->algo_strength))
+			if (algo_strength && !(algo_strength & cp->algo_strength))
 				continue;
 			}
 
@@ -884,20 +761,8 @@
 			{ rule = CIPHER_DEL; l++; }
 		else if (ch == '+')
 			{ rule = CIPHER_ORD; l++; }
-		else if (ch == '!' && has_group)
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS);
-			retval = found = in_group = 0;
-			break;
-			}
 		else if (ch == '!')
 			{ rule = CIPHER_KILL; l++; }
-		else if (ch == '@' && has_group)
-			{
-			OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS);
-			retval = found = in_group = 0;
-			break;
-			}
 		else if (ch == '@')
 			{ rule = CIPHER_SPECIAL; l++; }
 		else if (ch == '[')
@@ -916,6 +781,16 @@
 		else
 			{ rule = CIPHER_ADD; }
 
+		/* If preference groups are enabled, the only legal
+		 * operator is +. Otherwise the in_group bits will get
+		 * mixed up. */
+		if (has_group && rule != CIPHER_ADD)
+			{
+			OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS);
+			retval = found = in_group = 0;
+			break;
+			}
+
 		if (ITEM_SEP(ch))
 			{
 			l++;
@@ -1043,26 +918,15 @@
 					alg_mac = ca_list[j]->algorithm_mac;
 				}
 			
-			if (ca_list[j]->algo_strength & SSL_EXP_MASK)
+			if (ca_list[j]->algo_strength)
 				{
-				if (algo_strength & SSL_EXP_MASK)
+				if (algo_strength)
 					{
-					algo_strength &= (ca_list[j]->algo_strength & SSL_EXP_MASK) | ~SSL_EXP_MASK;
-					if (!(algo_strength & SSL_EXP_MASK)) { found = 0; break; }
+					algo_strength &= ca_list[j]->algo_strength;
+					if (!algo_strength) { found = 0; break; }
 					}
 				else
-					algo_strength |= ca_list[j]->algo_strength & SSL_EXP_MASK;
-				}
-
-			if (ca_list[j]->algo_strength & SSL_STRONG_MASK)
-				{
-				if (algo_strength & SSL_STRONG_MASK)
-					{
-					algo_strength &= (ca_list[j]->algo_strength & SSL_STRONG_MASK) | ~SSL_STRONG_MASK;
-					if (!(algo_strength & SSL_STRONG_MASK)) { found = 0; break; }
-					}
-				else
-					algo_strength |= ca_list[j]->algo_strength & SSL_STRONG_MASK;
+					algo_strength |= ca_list[j]->algo_strength;
 				}
 			
 			if (ca_list[j]->valid)
@@ -1125,7 +989,6 @@
 			while ((*l != '\0') && !ITEM_SEP(*l))
 				l++;
 			}
-		if (*l == '\0') break; /* done */
 		}
 
 	if (in_group)
@@ -1144,7 +1007,6 @@
 		const char *rule_str, CERT *c)
 	{
 	int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases;
-	unsigned long disabled_mkey, disabled_auth, disabled_enc, disabled_mac, disabled_ssl;
 	STACK_OF(SSL_CIPHER) *cipherstack = NULL, *tmp_cipher_list = NULL;
 	const char *rule_p;
 	CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
@@ -1160,12 +1022,6 @@
 		return NULL;
 
 	/*
-	 * To reduce the work to do we only want to process the compiled
-	 * in algorithms, so we first get the mask of disabled ciphers.
-	 */
-	ssl_cipher_get_disabled(&disabled_mkey, &disabled_auth, &disabled_enc, &disabled_mac, &disabled_ssl);
-
-	/*
 	 * Now we have to collect the available ciphers from the compiled
 	 * in ciphers. We cannot get more than the number compiled in, so
 	 * it is used for allocation.
@@ -1182,7 +1038,6 @@
 		}
 
 	ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers,
-	                           disabled_mkey, disabled_auth, disabled_enc, disabled_mac, disabled_ssl,
 	                           co_list, &head, &tail);
 
 
@@ -1245,13 +1100,10 @@
 	ca_list = OPENSSL_malloc(sizeof(SSL_CIPHER *) * num_of_alias_max);
 	if (ca_list == NULL)
 		{
-		OPENSSL_free(co_list);
 		OPENSSL_PUT_ERROR(SSL, ssl_create_cipher_list, ERR_R_MALLOC_FAILURE);
-		return(NULL);	/* Failure */
+		goto err;
 		}
-	ssl_cipher_collect_aliases(ca_list, num_of_group_aliases,
-	                           disabled_mkey, disabled_auth, disabled_enc,
-				   disabled_mac, disabled_ssl, head);
+	ssl_cipher_collect_aliases(ca_list, num_of_group_aliases, head);
 
 	/*
 	 * If the rule_string begins with DEFAULT, apply the default rule
diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c
index 12c1ffd..0ba125b 100644
--- a/ssl/ssl_error.c
+++ b/ssl/ssl_error.c
@@ -100,10 +100,10 @@
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_write, 0), "ssl23_write"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_accept, 0), "ssl3_accept"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_callback_ctrl, 0), "ssl3_callback_ctrl"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_cert_verify_hash, 0), "ssl3_cert_verify_hash"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_change_cipher_state, 0), "ssl3_change_cipher_state"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_check_cert_and_algorithm, 0), "ssl3_check_cert_and_algorithm"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_check_client_hello, 0), "ssl3_check_client_hello"},
-  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_client_hello, 0), "ssl3_client_hello"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_connect, 0), "ssl3_connect"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_ctrl, 0), "ssl3_ctrl"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_ctx_ctrl, 0), "ssl3_ctx_ctrl"},
@@ -130,11 +130,12 @@
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_handshake_mac, 0), "ssl3_handshake_mac"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_read_bytes, 0), "ssl3_read_bytes"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_read_n, 0), "ssl3_read_n"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_cert_verify, 0), "ssl3_send_cert_verify"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_certificate_request, 0), "ssl3_send_certificate_request"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_channel_id, 0), "ssl3_send_channel_id"},
   {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_client_verify, 0), "ssl3_send_client_verify"},
   {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"},
@@ -162,6 +163,8 @@
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cipher_process_rulestr, 0), "ssl_cipher_process_rulestr"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_cipher_strength_sort, 0), "ssl_cipher_strength_sort"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_create_cipher_list, 0), "ssl_create_cipher_list"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_ctx_log_master_secret, 0), "ssl_ctx_log_master_secret"},
+  {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_ctx_log_rsa_client_key_exchange, 0), "ssl_ctx_log_rsa_client_key_exchange"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_ctx_make_profiles, 0), "ssl_ctx_make_profiles"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_new_session, 0), "ssl_get_new_session"},
   {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl_get_prev_session, 0), "ssl_get_prev_session"},
@@ -450,6 +453,7 @@
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED), "SSLV3_ALERT_CERTIFICATE_EXPIRED"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED), "SSLV3_ALERT_CERTIFICATE_REVOKED"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN), "SSLV3_ALERT_CERTIFICATE_UNKNOWN"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CLOSE_NOTIFY), "SSLV3_ALERT_CLOSE_NOTIFY"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE), "SSLV3_ALERT_DECOMPRESSION_FAILURE"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE), "SSLV3_ALERT_HANDSHAKE_FAILURE"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER), "SSLV3_ALERT_ILLEGAL_PARAMETER"},
@@ -469,6 +473,7 @@
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED), "TLSV1_ALERT_DECRYPTION_FAILED"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPT_ERROR), "TLSV1_ALERT_DECRYPT_ERROR"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION), "TLSV1_ALERT_EXPORT_RESTRICTION"},
+  {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK), "TLSV1_ALERT_INAPPROPRIATE_FALLBACK"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY), "TLSV1_ALERT_INSUFFICIENT_SECURITY"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INTERNAL_ERROR), "TLSV1_ALERT_INTERNAL_ERROR"},
   {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION), "TLSV1_ALERT_NO_RENEGOTIATION"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 43ce97b..720ab54 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -172,6 +172,13 @@
 		 int use_context)) ssl_undefined_function,
 	};
 
+/* Some error codes are special. Ensure the make_errors.go script
+ * never regresses this. */
+OPENSSL_COMPILE_ASSERT(
+	SSL_R_TLSV1_ALERT_NO_RENEGOTIATION ==
+		SSL_AD_NO_RENEGOTIATION + SSL_AD_REASON_OFFSET,
+	ssl_alert_reason_code_mismatch);
+
 int SSL_clear(SSL *s)
 	{
 
@@ -336,15 +343,8 @@
 	s->tlsext_debug_cb = 0;
 	s->tlsext_debug_arg = NULL;
 	s->tlsext_ticket_expected = 0;
-	s->tlsext_status_type = -1;
-	s->tlsext_status_expected = 0;
-	s->tlsext_ocsp_ids = NULL;
-	s->tlsext_ocsp_exts = NULL;
-	s->tlsext_ocsp_resp = NULL;
-	s->tlsext_ocsp_resplen = -1;
 	CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
 	s->initial_ctx=ctx;
-#ifndef OPENSSL_NO_EC
 	if (ctx->tlsext_ecpointformatlist)
 		{
 		s->tlsext_ecpointformatlist =
@@ -365,10 +365,7 @@
 		s->tlsext_ellipticcurvelist_length = 
 					ctx->tlsext_ellipticcurvelist_length;
 		}
-#endif
-# ifndef OPENSSL_NO_NEXTPROTONEG
 	s->next_proto_negotiated = NULL;
-# endif
 
 	if (s->ctx->alpn_client_proto_list)
 		{
@@ -404,6 +401,12 @@
 	s->psk_client_callback=ctx->psk_client_callback;
 	s->psk_server_callback=ctx->psk_server_callback;
 
+	if (!s->server)
+		{
+		s->signed_cert_timestamps_enabled = s->ctx->signed_cert_timestamps_enabled;
+		s->ocsp_stapling_enabled = s->ctx->ocsp_stapling_enabled;
+		}
+
 	return(s);
 err:
 	if (s != NULL)
@@ -669,20 +672,8 @@
 	if (s->tlsext_hostname)
 		OPENSSL_free(s->tlsext_hostname);
 	if (s->initial_ctx) SSL_CTX_free(s->initial_ctx);
-#ifndef OPENSSL_NO_EC
 	if (s->tlsext_ecpointformatlist) OPENSSL_free(s->tlsext_ecpointformatlist);
 	if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist);
-#endif /* OPENSSL_NO_EC */
-	if (s->tlsext_ocsp_exts)
-		sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
-						X509_EXTENSION_free);
-        /* TODO(fork): OCSP support */
-#if 0
-	if (s->tlsext_ocsp_ids)
-		sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
-#endif
-	if (s->tlsext_ocsp_resp)
-		OPENSSL_free(s->tlsext_ocsp_resp);
 	if (s->alpn_client_proto_list)
 		OPENSSL_free(s->alpn_client_proto_list);
 	if (s->tlsext_channel_id_private)
@@ -698,10 +689,8 @@
 
 	if (s->ctx) SSL_CTX_free(s->ctx);
 
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
 	if (s->next_proto_negotiated)
 		OPENSSL_free(s->next_proto_negotiated);
-#endif
 
         if (s->srtp_profiles)
             sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles);
@@ -1097,7 +1086,7 @@
 		return -1;
 		}
 
-	if ((s != NULL) && !SSL_in_init(s))
+	if (!SSL_in_init(s))
 		return(s->method->ssl_shutdown(s));
 	else
 		return(1);
@@ -1162,11 +1151,8 @@
 		s->max_cert_list=larg;
 		return(l);
 	case SSL_CTRL_SET_MTU:
-#ifndef OPENSSL_NO_DTLS1
 		if (larg < (long)dtls1_min_mtu())
 			return 0;
-#endif
-
 		if (SSL_IS_DTLS(s))
 			{
 			s->d1->mtu = larg;
@@ -1675,6 +1661,63 @@
 	return -1;
 	}
 
+void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx)
+	{
+	ctx->signed_cert_timestamps_enabled = 1;
+	}
+
+int SSL_enable_signed_cert_timestamps(SSL *ssl)
+	{
+	/* Currently not implemented server-side. */
+	if (ssl->server)
+		return 0;
+
+	ssl->signed_cert_timestamps_enabled = 1;
+	return 1;
+	}
+
+void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx)
+	{
+	ctx->ocsp_stapling_enabled = 1;
+	}
+
+int SSL_enable_ocsp_stapling(SSL *ssl)
+	{
+	/* Currently not implemented server-side. */
+	if (ssl->server)
+		return 0;
+	ssl->ocsp_stapling_enabled = 1;
+	return 1;
+	}
+
+void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, uint8_t **out, size_t *out_len)
+	{
+	SSL_SESSION *session = ssl->session;
+
+	*out_len = 0;
+	*out = NULL;
+	if (ssl->server)
+		return;
+	if (!session || !session->tlsext_signed_cert_timestamp_list)
+		return;
+	*out = session->tlsext_signed_cert_timestamp_list;
+	*out_len = session->tlsext_signed_cert_timestamp_list_length;
+	}
+
+void SSL_get0_ocsp_response(const SSL *ssl, uint8_t **out, size_t *out_len)
+	{
+	SSL_SESSION *session = ssl->session;
+
+	*out_len = 0;
+	*out = NULL;
+	if (ssl->server)
+		return;
+	if (!session || !session->ocsp_response)
+		return;
+	*out = session->ocsp_response;
+	*out_len = session->ocsp_response_length;
+	}
+
 /* SSL_select_next_proto implements the standard protocol selection. It is
  * expected that this function is called from the callback set by
  * SSL_CTX_set_next_proto_select_cb.
@@ -1741,7 +1784,6 @@
 	return status;
 	}
 
-# ifndef OPENSSL_NO_NEXTPROTONEG
 /* SSL_get0_next_proto_negotiated sets *data and *len to point to the client's
  * requested protocol for this connection and returns 0. If the client didn't
  * request any protocol, then *data is set to NULL.
@@ -1790,7 +1832,6 @@
 	ctx->next_proto_select_cb = cb;
 	ctx->next_proto_select_cb_arg = arg;
 	}
-# endif
 
 /* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|.
  * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
@@ -2003,10 +2044,8 @@
 	ret->tlsext_status_cb = 0;
 	ret->tlsext_status_arg = NULL;
 
-# ifndef OPENSSL_NO_NEXTPROTONEG
 	ret->next_protos_advertised_cb = 0;
 	ret->next_proto_select_cb = 0;
-# endif
 	ret->psk_identity_hint=NULL;
 	ret->psk_client_callback=NULL;
 	ret->psk_server_callback=NULL;
@@ -2085,18 +2124,19 @@
 	if (a->psk_identity_hint)
 		OPENSSL_free(a->psk_identity_hint);
 
-# ifndef OPENSSL_NO_EC
 	if (a->tlsext_ecpointformatlist)
 		OPENSSL_free(a->tlsext_ecpointformatlist);
 	if (a->tlsext_ellipticcurvelist)
 		OPENSSL_free(a->tlsext_ellipticcurvelist);
-# endif /* OPENSSL_NO_EC */
 	if (a->alpn_client_proto_list != NULL)
 		OPENSSL_free(a->alpn_client_proto_list);
 
 	if (a->tlsext_channel_id_private)
 		EVP_PKEY_free(a->tlsext_channel_id_private);
 
+	if (a->keylog_bio)
+		BIO_free(a->keylog_bio);
+
 	OPENSSL_free(a);
 	}
 
@@ -2142,34 +2182,20 @@
 	CERT_PKEY *cpk;
 	int rsa_enc,rsa_sign,dh_tmp;
 	unsigned long mask_k,mask_a;
-#ifndef OPENSSL_NO_ECDSA
 	int have_ecc_cert, ecdsa_ok;
-#endif
-#ifndef OPENSSL_NO_ECDH
 	int have_ecdh_tmp;
-#endif
-#ifndef OPENSSL_NO_EC
 	X509 *x = NULL;
-#endif
 	if (c == NULL) return;
 
-#ifndef OPENSSL_NO_DH
 	dh_tmp=(c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
-#else
-	dh_tmp=0;
-#endif
 
-#ifndef OPENSSL_NO_ECDH
 	have_ecdh_tmp=(c->ecdh_tmp || c->ecdh_tmp_cb || c->ecdh_tmp_auto);
-#endif
 	cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
 	rsa_enc= cpk->valid_flags & CERT_PKEY_VALID;
 	cpk= &(c->pkeys[SSL_PKEY_RSA_SIGN]);
 	rsa_sign= cpk->valid_flags & CERT_PKEY_SIGN;
 	cpk= &(c->pkeys[SSL_PKEY_ECC]);
-#ifndef OPENSSL_NO_EC
 	have_ecc_cert= cpk->valid_flags & CERT_PKEY_VALID;
-#endif
 	mask_k=0;
 	mask_a=0;
 
@@ -2194,7 +2220,6 @@
 
 	/* An ECC certificate may be usable for ECDSA cipher suites depending on
          * the key usage extension. */
-#ifndef OPENSSL_NO_EC
 	if (have_ecc_cert)
 		{
 		cpk = &c->pkeys[SSL_PKEY_ECC];
@@ -2205,21 +2230,16 @@
 		    (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1;
 		if (!(cpk->valid_flags & CERT_PKEY_SIGN))
 			ecdsa_ok = 0;
-#ifndef OPENSSL_NO_ECDSA
 		if (ecdsa_ok)
 			{
 			mask_a|=SSL_aECDSA;
 			}
-#endif
 		}
-#endif
 
-#ifndef OPENSSL_NO_ECDH
 	if (have_ecdh_tmp)
 		{
 		mask_k|=SSL_kEECDH;
 		}
-#endif
 
 	mask_k |= SSL_kPSK;
 	mask_a |= SSL_aPSK;
@@ -2233,7 +2253,6 @@
 #define ku_reject(x, usage) \
 	(((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
 
-#ifndef OPENSSL_NO_EC
 
 int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
 	{
@@ -2263,7 +2282,6 @@
 	return 1;  /* all checks are ok */
 	}
 
-#endif
 
 static int ssl_get_server_cert_index(const SSL *s)
 	{
@@ -2348,14 +2366,14 @@
 	 * and it would be rather hard to do anyway :-) */
 	if (s->session->session_id_length == 0) return;
 
-	i=s->session_ctx->session_cache_mode;
+	i=s->initial_ctx->session_cache_mode;
 	if ((i & mode) && (!s->hit)
 		&& ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE)
-		    || SSL_CTX_add_session(s->session_ctx,s->session))
-		&& (s->session_ctx->new_session_cb != NULL))
+		    || SSL_CTX_add_session(s->initial_ctx,s->session))
+		&& (s->initial_ctx->new_session_cb != NULL))
 		{
 		CRYPTO_add(&s->session->references,1,CRYPTO_LOCK_SSL_SESSION);
-		if (!s->session_ctx->new_session_cb(s,s->session))
+		if (!s->initial_ctx->new_session_cb(s,s->session))
 			SSL_SESSION_free(s->session);
 		}
 
@@ -2364,10 +2382,10 @@
 		((i & mode) == mode))
 		{
 		if (  (((mode & SSL_SESS_CACHE_CLIENT)
-			?s->session_ctx->stats.sess_connect_good
-			:s->session_ctx->stats.sess_accept_good) & 0xff) == 0xff)
+			?s->initial_ctx->stats.sess_connect_good
+			:s->initial_ctx->stats.sess_accept_good) & 0xff) == 0xff)
 			{
-			SSL_CTX_flush_sessions(s->session_ctx,(unsigned long)time(NULL));
+			SSL_CTX_flush_sessions(s->initial_ctx,(unsigned long)time(NULL));
 			}
 		}
 	}
@@ -2932,7 +2950,6 @@
  * \param dh the callback
  */
 
-#ifndef OPENSSL_NO_DH
 void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,DH *(*dh)(SSL *ssl,int is_export,
                                                         int keylength))
 	{
@@ -2944,9 +2961,7 @@
 	{
 	SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_DH_CB,(void (*)(void))dh);
 	}
-#endif
 
-#ifndef OPENSSL_NO_ECDH
 void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,EC_KEY *(*ecdh)(SSL *ssl,int is_export,
                                                                 int keylength))
 	{
@@ -2958,7 +2973,6 @@
 	{
 	SSL_callback_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH_CB,(void (*)(void))ecdh);
 	}
-#endif
 
 int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint)
 	{
@@ -3081,6 +3095,122 @@
 	SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb);
 	}
 
+void SSL_CTX_set_keylog_bio(SSL_CTX *ctx, BIO *keylog_bio)
+	{
+	if (ctx->keylog_bio != NULL)
+		BIO_free(ctx->keylog_bio);
+	ctx->keylog_bio = keylog_bio;
+	}
+
+static int cbb_add_hex(CBB *cbb, const uint8_t *in, size_t in_len)
+	{
+	static const char hextable[] = "0123456789abcdef";
+	uint8_t *out;
+	size_t i;
+
+	if (!CBB_add_space(cbb, &out, in_len * 2))
+		{
+		return 0;
+		}
+
+	for (i = 0; i < in_len; i++)
+		{
+		*(out++) = (uint8_t)hextable[in[i] >> 4];
+		*(out++) = (uint8_t)hextable[in[i] & 0xf];
+		}
+	return 1;
+	}
+
+int ssl_ctx_log_rsa_client_key_exchange(SSL_CTX *ctx,
+	const uint8_t *encrypted_premaster, size_t encrypted_premaster_len,
+	const uint8_t *premaster, size_t premaster_len)
+	{
+	BIO *bio = ctx->keylog_bio;
+	CBB cbb;
+	uint8_t *out;
+	size_t out_len;
+	int ret;
+
+	if (bio == NULL)
+		{
+		return 1;
+		}
+
+	if (encrypted_premaster_len < 8)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_ctx_log_rsa_client_key_exchange, ERR_R_INTERNAL_ERROR);
+		return 0;
+		}
+
+	if (!CBB_init(&cbb, 4 + 16 + 1 + premaster_len*2 + 1))
+		{
+		return 0;
+		}
+	if (!CBB_add_bytes(&cbb, (const uint8_t*)"RSA ", 4) ||
+		/* Only the first 8 bytes of the encrypted premaster secret are
+		 * logged. */
+		!cbb_add_hex(&cbb, encrypted_premaster, 8) ||
+		!CBB_add_bytes(&cbb, (const uint8_t*)" ", 1) ||
+		!cbb_add_hex(&cbb, premaster, premaster_len) ||
+		!CBB_add_bytes(&cbb, (const uint8_t*)"\n", 1) ||
+		!CBB_finish(&cbb, &out, &out_len))
+		{
+		CBB_cleanup(&cbb);
+		return 0;
+		}
+
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+	ret = BIO_write(bio, out, out_len) >= 0 && BIO_flush(bio);
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+
+	OPENSSL_free(out);
+	return ret;
+	}
+
+int ssl_ctx_log_master_secret(SSL_CTX *ctx,
+	const uint8_t *client_random, size_t client_random_len,
+	const uint8_t *master, size_t master_len)
+	{
+	BIO *bio = ctx->keylog_bio;
+	CBB cbb;
+	uint8_t *out;
+	size_t out_len;
+	int ret;
+
+	if (bio == NULL)
+		{
+		return 1;
+		}
+
+	if (client_random_len != 32)
+		{
+		OPENSSL_PUT_ERROR(SSL, ssl_ctx_log_master_secret, ERR_R_INTERNAL_ERROR);
+		return 0;
+		}
+
+	if (!CBB_init(&cbb, 14 + 64 + 1 + master_len*2 + 1))
+		{
+		return 0;
+		}
+	if (!CBB_add_bytes(&cbb, (const uint8_t*)"CLIENT_RANDOM ", 14) ||
+		!cbb_add_hex(&cbb, client_random, 32) ||
+		!CBB_add_bytes(&cbb, (const uint8_t*)" ", 1) ||
+		!cbb_add_hex(&cbb, master, master_len) ||
+		!CBB_add_bytes(&cbb, (const uint8_t*)"\n", 1) ||
+		!CBB_finish(&cbb, &out, &out_len))
+		{
+		CBB_cleanup(&cbb);
+		return 0;
+		}
+
+	CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
+	ret = BIO_write(bio, out, out_len) >= 0 && BIO_flush(bio);
+	CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
+
+	OPENSSL_free(out);
+	return ret;
+	}
+
 int SSL_cutthrough_complete(const SSL *s)
 	{
 	return (!s->server &&                 /* cutthrough only applies to clients */
@@ -3112,11 +3242,7 @@
 		return 0;
 
 	/* require ALPN or NPN extension */
-	if (!s->s3->alpn_selected
-#ifndef OPENSSL_NO_NEXTPROTONEG
-		&& !s->s3->next_proto_neg_seen
-#endif
-	)
+	if (!s->s3->alpn_selected && !s->s3->next_proto_neg_seen)
 		{
 		return 0;
 		}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 55f1aaf..f9f3bed 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -359,14 +359,9 @@
 /*
  * Cipher strength information.
  */
-#define SSL_EXP_MASK		0x00000003L
-#define SSL_STRONG_MASK		0x000001fcL
-
-#define SSL_NOT_EXP		0x00000001L
-
-#define SSL_MEDIUM		0x00000040L
-#define SSL_HIGH		0x00000080L
-#define SSL_FIPS		0x00000100L
+#define SSL_MEDIUM		0x00000001L
+#define SSL_HIGH		0x00000002L
+#define SSL_FIPS		0x00000004L
 
 /* we have used 000001ff - 23 bits left to go */
 
@@ -415,14 +410,16 @@
 #define PENDING_SESSION -10000
 #define CERTIFICATE_SELECTION_PENDING -10001
 
-#ifndef OPENSSL_NO_EC
 /* From ECC-TLS draft, used in encoding the curve type in 
  * ECParameters
  */
 #define EXPLICIT_PRIME_CURVE_TYPE  1   
 #define EXPLICIT_CHAR2_CURVE_TYPE  2
 #define NAMED_CURVE_TYPE           3
-#endif  /* OPENSSL_NO_EC */
+
+/* Values for the |hash_message| parameter of |s->method->ssl_get_message|. */
+#define SSL_GET_MESSAGE_DONT_HASH_MESSAGE 0
+#define SSL_GET_MESSAGE_HASH_MESSAGE 1
 
 typedef struct cert_pkey_st
 	{
@@ -459,17 +456,13 @@
 	unsigned long mask_a;
 	/* Client only */
 	unsigned long mask_ssl;
-#ifndef OPENSSL_NO_DH
 	DH *dh_tmp;
 	DH *(*dh_tmp_cb)(SSL *ssl,int is_export,int keysize);
-#endif
-#ifndef OPENSSL_NO_ECDH
 	EC_KEY *ecdh_tmp;
 	/* Callback for generating ephemeral ECDH keys */
 	EC_KEY *(*ecdh_tmp_cb)(SSL *ssl,int is_export,int keysize);
 	/* Select ECDH parameters automatically */
 	int ecdh_tmp_auto;
-#endif
 	/* Flags related to certificates */
 	unsigned int cert_flags;
 	CERT_PKEY pkeys[SSL_PKEY_NUM];
@@ -545,12 +538,8 @@
 	 * so maybe we shouldn't even use the CERT_PKEY type here. */
 
 	RSA *peer_rsa_tmp; /* not used for SSL 2 */
-#ifndef OPENSSL_NO_DH
 	DH *peer_dh_tmp; /* not used for SSL 2 */
-#endif
-#ifndef OPENSSL_NO_ECDH
 	EC_KEY *peer_ecdh_tmp;
-#endif
 	} SESS_CERT;
 /* Structure containing decoded values of signature algorithms extension */
 struct tls_sigalgs_st
@@ -856,14 +845,13 @@
 void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher);
 STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s);
 int ssl_verify_alarm_type(long type);
-void ssl_load_ciphers(void);
 int ssl_fill_hello_random(SSL *s, int server, unsigned char *field, int len);
 
 const SSL_CIPHER *ssl3_get_cipher_by_value(uint16_t value);
 uint16_t ssl3_get_cipher_value(const SSL_CIPHER *c);
 void ssl3_init_finished_mac(SSL *s);
 int ssl3_send_server_certificate(SSL *s);
-int ssl3_send_newsession_ticket(SSL *s);
+int ssl3_send_new_session_ticket(SSL *s);
 int ssl3_send_cert_status(SSL *s);
 int ssl3_get_finished(SSL *s,int state_a,int state_b);
 int ssl3_setup_key_block(SSL *s);
@@ -875,7 +863,20 @@
 int ssl3_generate_master_secret(SSL *s, unsigned char *out,
 	unsigned char *p, int len);
 int ssl3_get_req_cert_type(SSL *s,unsigned char *p);
-long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok);
+long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int hash_message, int *ok);
+
+/* ssl3_hash_current_message incorporates the current handshake message into
+ * the handshake hash. */
+void ssl3_hash_current_message(SSL *s);
+
+/* ssl3_cert_verify_hash writes the CertificateVerify hash into the bytes
+ * pointed to by |out| and writes the number of bytes to |*out_len|. |out| must
+ * have room for EVP_MAX_MD_SIZE bytes. For TLS 1.2 and up, |*out_md| is used
+ * for the hash function, otherwise the hash function depends on the type of
+ * |pkey| and is written to |*out_md|. It returns one on success and zero on
+ * failure. */
+int ssl3_cert_verify_hash(SSL *s, uint8_t *out, size_t *out_len, const EVP_MD **out_md, EVP_PKEY *pkey);
+
 int ssl3_send_finished(SSL *s, int a, int b, const char *sender,int slen);
 int ssl3_num_ciphers(void);
 const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
@@ -957,27 +958,24 @@
 void dtls1_stop_timer(SSL *s);
 int dtls1_is_timer_expired(SSL *s);
 void dtls1_double_timeout(SSL *s);
-int dtls1_send_newsession_ticket(SSL *s);
 unsigned int dtls1_min_mtu(void);
 
 /* some client-only functions */
-int ssl3_client_hello(SSL *s);
+int ssl3_send_client_hello(SSL *s);
 int ssl3_get_server_hello(SSL *s);
 int ssl3_get_certificate_request(SSL *s);
 int ssl3_get_new_session_ticket(SSL *s);
 int ssl3_get_cert_status(SSL *s);
 int ssl3_get_server_done(SSL *s);
-int ssl3_send_client_verify(SSL *s);
+int ssl3_send_cert_verify(SSL *s);
 int ssl3_send_client_certificate(SSL *s);
 int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey);
 int ssl3_send_client_key_exchange(SSL *s);
 int ssl3_get_server_key_exchange(SSL *s);
 int ssl3_get_server_certificate(SSL *s);
 int ssl3_check_cert_and_algorithm(SSL *s);
-# ifndef OPENSSL_NO_NEXTPROTONEG
 int ssl3_send_next_proto(SSL *s);
 int ssl3_send_channel_id(SSL *s);
-# endif
 
 int dtls1_client_hello(SSL *s);
 
@@ -991,10 +989,8 @@
 int ssl3_get_client_certificate(SSL *s);
 int ssl3_get_client_key_exchange(SSL *s);
 int ssl3_get_cert_verify(SSL *s);
-#ifndef OPENSSL_NO_NEXTPROTONEG
 int ssl3_get_next_proto(SSL *s);
 int ssl3_get_channel_id(SSL *s);
-#endif
 
 int ssl23_accept(SSL *s);
 int ssl23_connect(SSL *s);
@@ -1009,7 +1005,7 @@
 long dtls1_ctrl(SSL *s,int cmd, long larg, void *parg);
 int dtls1_shutdown(SSL *s);
 
-long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok);
+long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int hash_message, int *ok);
 int dtls1_get_record(SSL *s);
 int dtls1_dispatch_alert(SSL *s);
 int dtls1_enc(SSL *s, int snd);
@@ -1034,12 +1030,9 @@
 int ssl3_alert_code(int code);
 int ssl_ok(SSL *s);
 
-#ifndef OPENSSL_NO_ECDH
 int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s);
-#endif
 
 char ssl_early_callback_init(struct ssl_early_callback_ctx *ctx);
-#ifndef OPENSSL_NO_EC
 int tls1_ec_curve_id2nid(uint16_t curve_id);
 uint16_t tls1_ec_nid2curve_id(int nid);
 
@@ -1062,7 +1055,6 @@
 	const int *curves, size_t ncurves);
 
 int tls1_check_ec_tmp_key(SSL *s, unsigned long id);
-#endif /* OPENSSL_NO_EC */
 
 int tls1_shared_list(SSL *s,
 			const unsigned char *l1, size_t l1len,
@@ -1071,7 +1063,6 @@
 unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit, size_t header_len);
 unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit); 
 int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs);
-int ssl_check_clienthello_tlsext_late(SSL *s);
 int ssl_parse_serverhello_tlsext(SSL *s, CBS *cbs);
 int ssl_prepare_clienthello_tlsext(SSL *s);
 int ssl_prepare_serverhello_tlsext(SSL *s);
@@ -1094,6 +1085,19 @@
 								int idx);
 void tls1_set_cert_validity(SSL *s);
 
+/* ssl_ctx_log_rsa_client_key_exchange logs |premaster| to |ctx|, if logging is
+ * enabled. It returns one on success and zero on failure. The entry is
+ * identified by the first 8 bytes of |encrypted_premaster|. */
+int ssl_ctx_log_rsa_client_key_exchange(SSL_CTX *ctx,
+	const uint8_t *encrypted_premaster, size_t encrypted_premaster_len,
+	const uint8_t *premaster, size_t premaster_len);
+
+/* ssl_ctx_log_master_secret logs |master| to |ctx|, if logging is enabled. It
+ * returns one on success and zero on failure. The entry is identified by
+ * |client_random|. */
+int ssl_ctx_log_master_secret(SSL_CTX *ctx,
+	const uint8_t *client_random, size_t client_random_len,
+	const uint8_t *master, size_t master_len);
 
 int ssl3_can_cutthrough(const SSL *s);
 int ssl_get_max_version(const SSL *s);
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index a9f7f9e..7fd1724 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -152,7 +152,7 @@
 static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s);
 static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
 
-SSL_SESSION *SSL_magic_pending_session_ptr()
+SSL_SESSION *SSL_magic_pending_session_ptr(void)
 	{
 	return (SSL_SESSION*) &g_pending_session_magic;
 	}
@@ -211,18 +211,7 @@
 	ss->references=1;
 	ss->timeout = SSL_DEFAULT_SESSION_TIMEOUT;
 	ss->time=(unsigned long)time(NULL);
-	ss->prev=NULL;
-	ss->next=NULL;
-	ss->tlsext_hostname = NULL; 
-#ifndef OPENSSL_NO_EC
-	ss->tlsext_ecpointformatlist_length = 0;
-	ss->tlsext_ecpointformatlist = NULL;
-	ss->tlsext_ellipticcurvelist_length = 0;
-	ss->tlsext_ellipticcurvelist = NULL;
-#endif
 	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
-	ss->psk_identity_hint=NULL;
-	ss->psk_identity=NULL;
 	return(ss);
 	}
 
@@ -283,8 +272,8 @@
 	if ((ss=SSL_SESSION_new()) == NULL) return(0);
 
 	/* If the context has a default timeout, use it over the default. */
-	if (s->session_ctx->session_timeout != 0)
-		ss->timeout=s->session_ctx->session_timeout;
+	if (s->initial_ctx->session_timeout != 0)
+		ss->timeout=s->initial_ctx->session_timeout;
 
 	if (s->session != NULL)
 		{
@@ -345,8 +334,8 @@
 		CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
 		if(s->generate_session_id)
 			cb = s->generate_session_id;
-		else if(s->session_ctx->generate_session_id)
-			cb = s->session_ctx->generate_session_id;
+		else if(s->initial_ctx->generate_session_id)
+			cb = s->initial_ctx->generate_session_id;
 		CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
 		/* Choose a session ID */
 		tmp = ss->session_id_length;
@@ -469,7 +458,7 @@
 
 	if (try_session_cache &&
 	    ret == NULL &&
-	    !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
+	    !(s->initial_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
 		{
 		SSL_SESSION data;
 		data.ssl_version=s->version;
@@ -478,7 +467,7 @@
 			return 0;
 		memcpy(data.session_id,ctx->session_id,ctx->session_id_len);
 		CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
-		ret=lh_SSL_SESSION_retrieve(s->session_ctx->sessions,&data);
+		ret=lh_SSL_SESSION_retrieve(s->initial_ctx->sessions,&data);
 		if (ret != NULL)
 			{
 			/* don't allow other threads to steal it: */
@@ -486,16 +475,16 @@
 			}
 		CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX);
 		if (ret == NULL)
-			s->session_ctx->stats.sess_miss++;
+			s->initial_ctx->stats.sess_miss++;
 		}
 
 	if (try_session_cache &&
 	    ret == NULL &&
-	    s->session_ctx->get_session_cb != NULL)
+	    s->initial_ctx->get_session_cb != NULL)
 		{
 		int copy=1;
 	
-		if ((ret=s->session_ctx->get_session_cb(s,(unsigned char *) ctx->session_id,ctx->session_id_len,&copy)))
+		if ((ret=s->initial_ctx->get_session_cb(s,(unsigned char *) ctx->session_id,ctx->session_id_len,&copy)))
 			{
 			if (ret == SSL_magic_pending_session_ptr())
 				{
@@ -504,7 +493,7 @@
 				 * figure out the session asynchronously. */
 				return PENDING_SESSION;
 				}
-			s->session_ctx->stats.sess_cb_hit++;
+			s->initial_ctx->stats.sess_cb_hit++;
 
 			/* Increment reference count now if the session callback
 			 * asks us to do so (note that if the session structures
@@ -516,10 +505,10 @@
 
 			/* Add the externally cached session to the internal
 			 * cache as well if and only if we are supposed to. */
-			if(!(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE))
+			if(!(s->initial_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_STORE))
 				/* The following should not return 1, otherwise,
 				 * things are very strange */
-				SSL_CTX_add_session(s->session_ctx,ret);
+				SSL_CTX_add_session(s->initial_ctx,ret);
 			}
 		}
 
@@ -555,16 +544,16 @@
 
 	if (ret->timeout < (long)(time(NULL) - ret->time)) /* timeout */
 		{
-		s->session_ctx->stats.sess_timeout++;
+		s->initial_ctx->stats.sess_timeout++;
 		if (try_session_cache)
 			{
 			/* session was from the cache, so remove it */
-			SSL_CTX_remove_session(s->session_ctx,ret);
+			SSL_CTX_remove_session(s->initial_ctx,ret);
 			}
 		goto err;
 		}
 
-	s->session_ctx->stats.sess_hit++;
+	s->initial_ctx->stats.sess_hit++;
 
 	if (s->session != NULL)
 		SSL_SESSION_free(s->session);
@@ -721,12 +710,14 @@
 	if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers);
 	if (ss->tlsext_hostname != NULL) OPENSSL_free(ss->tlsext_hostname);
 	if (ss->tlsext_tick != NULL) OPENSSL_free(ss->tlsext_tick);
-#ifndef OPENSSL_NO_EC
 	ss->tlsext_ecpointformatlist_length = 0;
 	if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist);
 	ss->tlsext_ellipticcurvelist_length = 0;
 	if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist);
-#endif /* OPENSSL_NO_EC */
+	if (ss->tlsext_signed_cert_timestamp_list != NULL)
+		OPENSSL_free(ss->tlsext_signed_cert_timestamp_list);
+	if (ss->ocsp_response != NULL)
+		OPENSSL_free(ss->ocsp_response);
 	if (ss->psk_identity_hint != NULL)
 		OPENSSL_free(ss->psk_identity_hint);
 	if (ss->psk_identity != NULL)
diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c
index 361a2fa..2f46b8c 100644
--- a/ssl/ssl_stat.c
+++ b/ssl/ssl_stat.c
@@ -101,7 +101,6 @@
 case SSL_ST_BEFORE|SSL_ST_ACCEPT: str="before/accept initialization"; break;
 case SSL_ST_OK|SSL_ST_ACCEPT: str="ok/accept SSL initialization"; break;
 
-#ifndef OPENSSL_NO_SSL3
 /* SSLv3 additions */
 case SSL3_ST_CW_CLNT_HELLO_A:	str="SSLv3 write client hello A"; break;
 case SSL3_ST_CW_CLNT_HELLO_B:	str="SSLv3 write client hello B"; break;
@@ -169,9 +168,7 @@
 case SSL3_ST_SR_KEY_EXCH_B:	str="SSLv3 read client key exchange B"; break;
 case SSL3_ST_SR_CERT_VRFY_A:	str="SSLv3 read certificate verify A"; break;
 case SSL3_ST_SR_CERT_VRFY_B:	str="SSLv3 read certificate verify B"; break;
-#endif
 
-#if !defined(OPENSSL_NO_SSL3)
 /* SSLv2/v3 compatibility states */
 /* client */
 case SSL23_ST_CW_CLNT_HELLO_A:	str="SSLv2/v3 write client hello A"; break;
@@ -182,7 +179,6 @@
 case SSL23_ST_SR_CLNT_HELLO:	str="SSLv2/v3 read client hello"; break;
 case SSL23_ST_SR_V2_CLNT_HELLO:	str="SSLv2/v3 read v2 client hello"; break;
 case SSL23_ST_SR_SWITCH_VERSION: str="SSLv2/v3 switch version"; break;
-#endif
 
 /* DTLS */
 case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: str="DTLS1 read hello verify request A"; break;
@@ -220,7 +216,6 @@
 case SSL_ST_CONNECT:				str="CINIT "; break;
 case SSL_ST_OK:			 		str="SSLOK "; break;
 
-#ifndef OPENSSL_NO_SSL3
 /* SSLv3 additions */
 case SSL3_ST_SW_FLUSH:
 case SSL3_ST_CW_FLUSH:				str="3FLUSH"; break;
@@ -283,9 +278,7 @@
 case SSL3_ST_SR_KEY_EXCH_B:			str="3RCKEB"; break;
 case SSL3_ST_SR_CERT_VRFY_A:			str="3RCV_A"; break;
 case SSL3_ST_SR_CERT_VRFY_B:			str="3RCV_B"; break;
-#endif
 
-#if !defined(OPENSSL_NO_SSL3)
 /* SSLv2/v3 compatibility states */
 /* client */
 case SSL23_ST_CW_CLNT_HELLO_A:			str="23WCHA"; break;
@@ -296,7 +289,6 @@
 case SSL23_ST_SR_CLNT_HELLO:			str="23RCH_"; break;
 case SSL23_ST_SR_V2_CLNT_HELLO:			str="23R2CH"; break;
 case SSL23_ST_SR_SWITCH_VERSION:		str="23RSW_"; break;
-#endif
 /* DTLS */
 case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: str="DRCHVA"; break;
 case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: str="DRCHVB"; break;
diff --git a/ssl/ssl_test.c b/ssl/ssl_test.c
index 4652e85..68889a0 100644
--- a/ssl/ssl_test.c
+++ b/ssl/ssl_test.c
@@ -14,14 +14,261 @@
 
 #include <stdio.h>
 
-#include "openssl/ssl.h"
+#include <openssl/err.h>
+#include <openssl/ssl.h>
 
-int main() {
-  /* Some error codes are special, but the make_errors.go script doesn't know
-   * this. This test will catch the case where something regenerates the error
-   * codes with the script but doesn't fix up the special ones. */
-  if (SSL_R_TLSV1_ALERT_NO_RENEGOTIATION != 100 + SSL_AD_REASON_OFFSET) {
-    fprintf(stderr, "SSL alert errors don't match up.\n");
+typedef struct {
+  int id;
+  int in_group_flag;
+} EXPECTED_CIPHER;
+
+typedef struct {
+  /* The rule string to apply. */
+  const char *rule;
+  /* The list of expected ciphers, in order, terminated with -1. */
+  const EXPECTED_CIPHER *expected;
+} CIPHER_TEST;
+
+/* Selecting individual ciphers should work. */
+static const char kRule1[] =
+    "ECDHE-ECDSA-CHACHA20-POLY1305:"
+    "ECDHE-RSA-CHACHA20-POLY1305:"
+    "ECDHE-ECDSA-AES128-GCM-SHA256:"
+    "ECDHE-RSA-AES128-GCM-SHA256";
+
+static const EXPECTED_CIPHER kExpected1[] = {
+  { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 },
+  { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
+  { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
+  { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
+  { -1, -1 },
+};
+
+/* + reorders selected ciphers to the end, keeping their relative
+ * order. */
+static const char kRule2[] =
+    "ECDHE-ECDSA-CHACHA20-POLY1305:"
+    "ECDHE-RSA-CHACHA20-POLY1305:"
+    "ECDHE-ECDSA-AES128-GCM-SHA256:"
+    "ECDHE-RSA-AES128-GCM-SHA256:"
+    "+aRSA";
+
+static const EXPECTED_CIPHER kExpected2[] = {
+  { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 },
+  { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
+  { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
+  { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
+  { -1, -1 },
+};
+
+/* ! banishes ciphers from future selections. */
+static const char kRule3[] =
+    "!aRSA:"
+    "ECDHE-ECDSA-CHACHA20-POLY1305:"
+    "ECDHE-RSA-CHACHA20-POLY1305:"
+    "ECDHE-ECDSA-AES128-GCM-SHA256:"
+    "ECDHE-RSA-AES128-GCM-SHA256";
+
+static const EXPECTED_CIPHER kExpected3[] = {
+  { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 },
+  { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
+  { -1, -1 },
+};
+
+/* Multiple masks can be ANDed in a single rule. */
+static const char kRule4[] = "kRSA+AESGCM+AES128";
+
+static const EXPECTED_CIPHER kExpected4[] = {
+  { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 },
+  { -1, -1 },
+};
+
+/* - removes selected ciphers, but preserves their order for future
+ * selections. Select AES_128_GCM, but order the key exchanges RSA,
+ * DHE_RSA, ECDHE_RSA. */
+static const char kRule5[] =
+    "ALL:-kEECDH:-kEDH:-kRSA:-ALL:"
+    "AESGCM+AES128+aRSA";
+
+static const EXPECTED_CIPHER kExpected5[] = {
+  { TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, 0 },
+  { TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
+  { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
+  { -1, -1 },
+};
+
+/* Unknown selectors are no-ops. */
+static const char kRule6[] =
+    "ECDHE-ECDSA-CHACHA20-POLY1305:"
+    "ECDHE-RSA-CHACHA20-POLY1305:"
+    "ECDHE-ECDSA-AES128-GCM-SHA256:"
+    "ECDHE-RSA-AES128-GCM-SHA256:"
+    "BOGUS1:-BOGUS2:+BOGUS3:!BOGUS4";
+
+static const EXPECTED_CIPHER kExpected6[] = {
+  { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 0 },
+  { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
+  { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
+  { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
+  { -1, -1 },
+};
+
+/* Square brackets specify equi-preference groups. */
+static const char kRule7[] =
+    "[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]:"
+    "[ECDHE-RSA-CHACHA20-POLY1305]:"
+    "ECDHE-RSA-AES128-GCM-SHA256";
+
+static const EXPECTED_CIPHER kExpected7[] = {
+  { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305, 1 },
+  { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 0 },
+  { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
+  { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0 },
+  { -1, -1 },
+};
+
+/* @STRENGTH performs a stable strength-sort of the selected
+ * ciphers and only the selected ciphers. */
+static const char kRule8[] =
+    /* To simplify things, banish all but {ECDHE_RSA,RSA} x
+     * {CHACHA20,AES_256_CBC,AES_128_CBC,RC4} x SHA1. */
+    "!kEDH:!AESGCM:!3DES:!SHA256:!MD5:!SHA384:"
+    /* Order some ciphers backwards by strength. */
+    "ALL:-CHACHA20:-AES256:-AES128:-RC4:-ALL:"
+    /* Select ECDHE ones and sort them by strength. Ties should resolve
+     * based on the order above. */
+    "kEECDH:@STRENGTH:-ALL:"
+    /* Now bring back everything uses RSA. ECDHE_RSA should be first,
+     * sorted by strength. Then RSA, backwards by strength. */
+    "aRSA";
+
+static const EXPECTED_CIPHER kExpected8[] = {
+  { TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, 0 },
+  { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305, 0 },
+  { TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, 0 },
+  { TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0 },
+  { SSL3_CK_RSA_RC4_128_SHA, 0 },
+  { TLS1_CK_RSA_WITH_AES_128_SHA, 0 },
+  { TLS1_CK_RSA_WITH_AES_256_SHA, 0 },
+  { -1, -1 },
+};
+
+static CIPHER_TEST kCipherTests[] = {
+  { kRule1, kExpected1 },
+  { kRule2, kExpected2 },
+  { kRule3, kExpected3 },
+  { kRule4, kExpected4 },
+  { kRule5, kExpected5 },
+  { kRule6, kExpected6 },
+  { kRule7, kExpected7 },
+  { kRule8, kExpected8 },
+  { NULL, NULL },
+};
+
+static const char *kBadRules[] = {
+  /* Invalid brackets. */
+  "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256",
+  "RSA]",
+  "[[RSA]]",
+  /* Operators inside brackets */
+  "[+RSA]",
+  /* Unknown directive. */
+  "@BOGUS",
+  /* Empty cipher lists error at SSL_CTX_set_cipher_list. */
+  "",
+  "BOGUS",
+  /* Invalid command. */
+  "?BAR",
+  /* Special operators are not allowed if groups are used. */
+  "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:+FOO",
+  "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:!FOO",
+  "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:-FOO",
+  "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH",
+  NULL,
+};
+
+static void print_cipher_preference_list(
+    struct ssl_cipher_preference_list_st *list) {
+  size_t i;
+  int in_group = 0;
+  for (i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) {
+    const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(list->ciphers, i);
+    if (!in_group && list->in_group_flags[i]) {
+      fprintf(stderr, "\t[\n");
+      in_group = 1;
+    }
+    fprintf(stderr, "\t");
+    if (in_group) {
+      fprintf(stderr, "  ");
+    }
+    fprintf(stderr, "%s\n", SSL_CIPHER_get_name(cipher));
+    if (in_group && !list->in_group_flags[i]) {
+      fprintf(stderr, "\t]\n");
+      in_group = 0;
+    }
+  }
+}
+
+static int test_cipher_rule(CIPHER_TEST *t) {
+  int ret = 0;
+  SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
+  size_t i;
+
+  if (!SSL_CTX_set_cipher_list(ctx, t->rule)) {
+    fprintf(stderr, "Error testing cipher rule '%s'\n", t->rule);
+    BIO_print_errors_fp(stderr);
+    goto done;
+  }
+
+  /* Compare the two lists. */
+  for (i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) {
+    const SSL_CIPHER *cipher =
+        sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i);
+    if (t->expected[i].id != SSL_CIPHER_get_id(cipher) ||
+        t->expected[i].in_group_flag != ctx->cipher_list->in_group_flags[i]) {
+      fprintf(stderr, "Error: cipher rule '%s' evaluted to:\n", t->rule);
+      print_cipher_preference_list(ctx->cipher_list);
+      goto done;
+    }
+  }
+
+  if (t->expected[i].id != -1) {
+    fprintf(stderr, "Error: cipher rule '%s' evaluted to:\n", t->rule);
+    print_cipher_preference_list(ctx->cipher_list);
+    goto done;
+  }
+
+  ret = 1;
+done:
+  SSL_CTX_free(ctx);
+  return ret;
+}
+
+static int test_cipher_rules(void) {
+  size_t i;
+  for (i = 0; kCipherTests[i].rule != NULL; i++) {
+    if (!test_cipher_rule(&kCipherTests[i])) {
+      return 0;
+    }
+  }
+
+  for (i = 0; kBadRules[i] != NULL; i++) {
+    SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
+    if (SSL_CTX_set_cipher_list(ctx, kBadRules[i])) {
+      fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", kBadRules[i]);
+      return 0;
+    }
+    ERR_clear_error();
+    SSL_CTX_free(ctx);
+  }
+
+  return 1;
+}
+
+int main(void) {
+  SSL_library_init();
+
+  if (!test_cipher_rules()) {
     return 1;
   }
 
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 743c359..ca6bf6c 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -495,9 +495,8 @@
 	unsigned key_len, iv_len, mac_secret_len;
 	const unsigned char *key_data;
 
-	/* Reset sequence number to zero.
-	 * TODO(davidben): Is this redundant with dtls1_reset_seq_numbers? */
-	if (SSL_IS_DTLS(s))
+	/* Reset sequence number to zero. */
+	if (!SSL_IS_DTLS(s))
 		memset(is_read ? s->s3->read_sequence : s->s3->write_sequence, 0, 8);
 
 	/* key_arg is used for SSLv2. We don't need it for TLS. */
@@ -522,11 +521,7 @@
 	else
 		{
 		key_len = EVP_CIPHER_key_length(cipher);
-
-		if (EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE)
-			iv_len = EVP_GCM_TLS_FIXED_IV_LEN;
-		else
-			iv_len = EVP_CIPHER_iv_length(cipher);
+		iv_len = EVP_CIPHER_iv_length(cipher);
 		}
 
 	key_data = s->s3->tmp.key_block;
@@ -601,7 +596,9 @@
 			goto cipher_unavailable_err;
 		key_len = EVP_AEAD_key_length(aead);
 		iv_len = SSL_CIPHER_AEAD_FIXED_NONCE_LEN(s->session->cipher);
-		if (!ssl_cipher_get_mac(s->session, &hash, &mac_type, &mac_secret_size))
+		if ((s->session->cipher->algorithm2 &
+				SSL_CIPHER_ALGORITHM2_STATEFUL_AEAD) &&
+			!ssl_cipher_get_mac(s->session, &hash, &mac_type, &mac_secret_size))
 			goto cipher_unavailable_err;
 		/* For "stateful" AEADs (i.e. compatibility with pre-AEAD
 		 * cipher suites) the key length reported by
@@ -618,11 +615,7 @@
 		if (!ssl_cipher_get_evp(s->session,&c,&hash,&mac_type,&mac_secret_size))
 			goto cipher_unavailable_err;
 		key_len = EVP_CIPHER_key_length(c);
-
-		if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE)
-			iv_len = EVP_GCM_TLS_FIXED_IV_LEN;
-		else
-			iv_len = EVP_CIPHER_iv_length(c);
+		iv_len = EVP_CIPHER_iv_length(c);
 		}
 
 	s->s3->tmp.new_aead=aead;
@@ -676,10 +669,8 @@
 
 		if (s->session->cipher != NULL)
 			{
-#ifndef OPENSSL_NO_RC4
 			if (s->session->cipher->algorithm_enc == SSL_RC4)
 				s->s3->need_record_splitting = 0;
-#endif
 			}
 		}
 		
@@ -914,11 +905,6 @@
 
 			/* we need to add 'i' padding bytes of value j */
 			j=i-1;
-			if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG)
-				{
-				if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
-					j++;
-				}
 			for (k=(int)l; k<(int)(l+i); k++)
 				rec->input[k]=j;
 			l+=i;
@@ -954,12 +940,6 @@
 						?(i<0)
 						:(i==0))
 			return -1;	/* AEAD can fail to verify MAC */
-		if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE && !send)
-			{
-			rec->data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
-			rec->input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
-			rec->length -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
-			}
 
 #ifdef KSSL_DEBUG
 		{
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 855d1d0..eccf875 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -121,8 +121,8 @@
 static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
 				const unsigned char *sess_id, int sesslen,
 				SSL_SESSION **psess);
-static int ssl_check_clienthello_tlsext_early(SSL *s);
-int ssl_check_serverhello_tlsext(SSL *s);
+static int ssl_check_clienthello_tlsext(SSL *s);
+static int ssl_check_serverhello_tlsext(SSL *s);
 
 SSL3_ENC_METHOD TLSv1_enc_data={
 	tls1_enc,
@@ -365,7 +365,6 @@
 	return 0;
 	}
 
-#ifndef OPENSSL_NO_EC
 
 static const int nid_list[] =
 	{
@@ -704,14 +703,6 @@
 #endif
 	}
 
-#else
-
-static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
-	{
-	return 1;
-	}
-
-#endif /* OPENSSL_NO_EC */
 
 
 /* List of supported signature algorithms and hashes. Should make this
@@ -720,11 +711,7 @@
 
 #define tlsext_sigalg_rsa(md) md, TLSEXT_signature_rsa,
 
-#ifdef OPENSSL_NO_ECDSA
-#define tlsext_sigalg_ecdsa(md) /* */
-#else
 #define tlsext_sigalg_ecdsa(md) md, TLSEXT_signature_ecdsa,
-#endif
 
 #define tlsext_sigalg(md) \
 		tlsext_sigalg_rsa(md) \
@@ -735,9 +722,7 @@
 	tlsext_sigalg(TLSEXT_hash_sha384)
 	tlsext_sigalg(TLSEXT_hash_sha256)
 	tlsext_sigalg(TLSEXT_hash_sha224)
-#ifndef OPENSSL_NO_SHA
 	tlsext_sigalg(TLSEXT_hash_sha1)
-#endif
 };
 size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs)
 	{
@@ -793,7 +778,6 @@
 		*out_alert = SSL_AD_ILLEGAL_PARAMETER;
 		return 0;
 		}
-#ifndef OPENSSL_NO_EC
 	if (pkey->type == EVP_PKEY_EC)
 		{
 		uint16_t curve_id;
@@ -811,7 +795,6 @@
 			return 0;
 			}
 		}
-#endif
 
 	/* Check signature matches a type we sent */
 	sent_sigslen = tls12_get_psigalgs(s, &sent_sigs);
@@ -872,11 +855,9 @@
 		case TLSEXT_signature_rsa:
 			have_rsa = 1;
 			break;
-#ifndef OPENSSL_NO_ECDSA
 		case TLSEXT_signature_ecdsa:
 			have_ecdsa = 1;
 			break;
-#endif
 			}
 		}
 	/* Disable auth if we don't include any appropriate signature
@@ -907,7 +888,6 @@
 	int extdatalen=0;
 	unsigned char *ret = buf;
 	unsigned char *orig = buf;
-#ifndef OPENSSL_NO_EC
 	/* See if we support any ECC ciphersuites */
 	int using_ecc = 0;
 	if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s))
@@ -929,7 +909,6 @@
 				}
 			}
 		}
-#endif
 
 	/* don't add extensions for SSLv3 unless doing secure renegotiation */
 	if (s->client_version == SSL3_VERSION
@@ -1046,58 +1025,24 @@
 		ret += salglen;
 		}
 
-        /* TODO(fork): we probably want OCSP stapling, but it currently pulls in a lot of code. */
-#if 0
-	if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+	if (s->ocsp_stapling_enabled)
 		{
-		int i;
-		long extlen, idlen, itmp;
-		OCSP_RESPID *id;
+		/* The status_request extension is excessively extensible at
+		 * every layer. On the client, only support requesting OCSP
+		 * responses with an empty responder_id_list and no
+		 * extensions. */
+		if (limit - ret - 4 - 1 - 2 - 2 < 0) return NULL;
 
-		idlen = 0;
-		for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
-			{
-			id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
-			itmp = i2d_OCSP_RESPID(id, NULL);
-			if (itmp <= 0)
-				return NULL;
-			idlen += itmp + 2;
-			}
-
-		if (s->tlsext_ocsp_exts)
-			{
-			extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
-			if (extlen < 0)
-				return NULL;
-			}
-		else
-			extlen = 0;
-			
-		if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL;
 		s2n(TLSEXT_TYPE_status_request, ret);
-		if (extlen + idlen > 0xFFF0)
-			return NULL;
-		s2n(extlen + idlen + 5, ret);
+		s2n(1 + 2 + 2, ret);
+		/* status_type */
 		*(ret++) = TLSEXT_STATUSTYPE_ocsp;
-		s2n(idlen, ret);
-		for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++)
-			{
-			/* save position of id len */
-			unsigned char *q = ret;
-			id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
-			/* skip over id len */
-			ret += 2;
-			itmp = i2d_OCSP_RESPID(id, &ret);
-			/* write id len */
-			s2n(itmp, q);
-			}
-		s2n(extlen, ret);
-		if (extlen > 0)
-			i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
+		/* responder_id_list - empty */
+		s2n(0, ret);
+		/* request_extensions - empty */
+		s2n(0, ret);
 		}
-#endif
 
-#ifndef OPENSSL_NO_NEXTPROTONEG
 	if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len)
 		{
 		/* The client advertises an emtpy extension to indicate its
@@ -1107,7 +1052,16 @@
 		s2n(TLSEXT_TYPE_next_proto_neg,ret);
 		s2n(0,ret);
 		}
-#endif
+
+	if (s->signed_cert_timestamps_enabled && !s->s3->tmp.finish_md_len)
+		{
+		/* The client advertises an empty extension to indicate its support for
+		 * certificate timestamps. */
+		if (limit - ret - 4 < 0)
+			return NULL;
+		s2n(TLSEXT_TYPE_certificate_timestamp,ret);
+		s2n(0,ret);
+		}
 
 	if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len)
 		{
@@ -1145,7 +1099,7 @@
                 s2n(TLSEXT_TYPE_use_srtp,ret);
                 s2n(el,ret);
 
-                if(ssl_add_clienthello_use_srtp_ext(s, ret, &el, el))
+                if(!ssl_add_clienthello_use_srtp_ext(s, ret, &el, el))
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR);
 			return NULL;
@@ -1153,7 +1107,6 @@
                 ret += el;
                 }
 
-#ifndef OPENSSL_NO_EC
 	if (using_ecc)
 		{
 		/* Add TLS extension ECPointFormats to the ClientHello message */
@@ -1203,7 +1156,6 @@
 			s2n(curves[i], ret);
 			}
 		}
-#endif /* OPENSSL_NO_EC */
 
 #ifdef TLSEXT_TYPE_padding
 	/* Add padding to workaround bugs in F5 terminators.
@@ -1248,15 +1200,11 @@
 	int extdatalen=0;
 	unsigned char *orig = buf;
 	unsigned char *ret = buf;
-#ifndef OPENSSL_NO_NEXTPROTONEG
 	int next_proto_neg_seen;
-#endif
-#ifndef OPENSSL_NO_EC
 	unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 	unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
 	int using_ecc = (alg_k & SSL_kEECDH) || (alg_a & SSL_aECDSA);
 	using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
-#endif
 	/* don't add extensions for SSLv3, unless doing secure renegotiation */
 	if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
 		return orig;
@@ -1264,7 +1212,7 @@
 	ret+=2;
 	if (ret>=limit) return NULL; /* this really never occurs, but ... */
 
-	if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
+	if (!s->hit && s->should_ack_sni && s->session->tlsext_hostname != NULL)
 		{ 
 		if ((long)(limit - ret - 4) < 0) return NULL; 
 
@@ -1296,7 +1244,6 @@
           ret += el;
         }
 
-#ifndef OPENSSL_NO_EC
 	if (using_ecc)
 		{
 		const unsigned char *plist;
@@ -1322,7 +1269,6 @@
 
 		}
 	/* Currently the server should not respond with a SupportedCurves extension */
-#endif /* OPENSSL_NO_EC */
 
 	if (s->tlsext_ticket_expected
 		&& !(SSL_get_options(s) & SSL_OP_NO_TICKET)) 
@@ -1332,7 +1278,7 @@
 		s2n(0,ret);
 		}
 
-	if (s->tlsext_status_expected)
+	if (s->s3->tmp.certificate_status_expected)
 		{ 
 		if ((long)(limit - ret - 4) < 0) return NULL; 
 		s2n(TLSEXT_TYPE_status_request,ret);
@@ -1350,7 +1296,7 @@
                 s2n(TLSEXT_TYPE_use_srtp,ret);
                 s2n(el,ret);
 
-                if(ssl_add_serverhello_use_srtp_ext(s, ret, &el, el))
+                if(!ssl_add_serverhello_use_srtp_ext(s, ret, &el, el))
 			{
 			OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR);
 			return NULL;
@@ -1358,7 +1304,6 @@
                 ret+=el;
                 }
 
-#ifndef OPENSSL_NO_NEXTPROTONEG
 	next_proto_neg_seen = s->s3->next_proto_neg_seen;
 	s->s3->next_proto_neg_seen = 0;
 	if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb)
@@ -1378,7 +1323,6 @@
 			s->s3->next_proto_neg_seen = 1;
 			}
 		}
-#endif
 
 	if (s->s3->alpn_selected)
 		{
@@ -1474,11 +1418,9 @@
 	CBS extensions;
 	size_t i;
 
-	s->servername_done = 0;
-	s->tlsext_status_type = -1;
-#ifndef OPENSSL_NO_NEXTPROTONEG
+	s->should_ack_sni = 0;
 	s->s3->next_proto_neg_seen = 0;
-#endif
+	s->s3->tmp.certificate_status_expected = 0;
 
 	if (s->s3->alpn_selected)
 		{
@@ -1505,23 +1447,6 @@
 		s->cert->pkeys[i].valid_flags = 0;
 		}
 
-	/* TODO(fork): we probably want OCSP stapling support, but this pulls in
-	 * a lot of code. */
-#if 0
-	/* Clear OCSP state. */
-	s->tlsext_status_type = -1;
-	if (s->tlsext_ocsp_ids)
-		{
-		sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
-		s->tlsext_ocsp_ids = NULL;
-		}
-	if (s->tlsext_ocsp_exts)
-		{
-		sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, X509_EXTENSION_free);
-		s->tlsext_ocsp_exts = NULL;
-		}
-#endif
-
 	/* There may be no extensions. */
 	if (CBS_len(cbs) == 0)
 		{
@@ -1581,6 +1506,7 @@
 		if (type == TLSEXT_TYPE_server_name)
 			{
 			CBS server_name_list;
+			char have_seen_host_name = 0;
 
 			if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) ||
 				CBS_len(&server_name_list) < 1 ||
@@ -1607,50 +1533,53 @@
 				if (name_type != TLSEXT_NAMETYPE_host_name)
 					continue;
 
+				if (have_seen_host_name)
+					{
+					/* The ServerNameList MUST NOT contain
+					 * more than one name of the same
+					 * name_type. */
+					*out_alert = SSL_AD_DECODE_ERROR;
+					return 0;
+					}
+
+				have_seen_host_name = 1;
+
+				if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
+					CBS_len(&host_name) < 1)
+					{
+					*out_alert = SSL_AD_DECODE_ERROR;
+					return 0;
+					}
+
+				if (CBS_len(&host_name) > TLSEXT_MAXLEN_host_name ||
+					CBS_contains_zero_byte(&host_name))
+					{
+					*out_alert = SSL_AD_UNRECOGNIZED_NAME;
+					return 0;
+					}
+
 				if (!s->hit)
 					{
+					assert(s->session->tlsext_hostname == NULL);
 					if (s->session->tlsext_hostname)
 						{
-						/* The ServerNameList MUST NOT
-						   contain more than one name of
-						   the same name_type. */
+						/* This should be impossible. */
 						*out_alert = SSL_AD_DECODE_ERROR;
 						return 0;
 						}
 
-					if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
-						CBS_len(&host_name) < 1)
-						{
-						*out_alert = SSL_AD_DECODE_ERROR;
-						return 0;
-						}
-
-					if (CBS_len(&host_name) > TLSEXT_MAXLEN_host_name ||
-						CBS_contains_zero_byte(&host_name))
-						{
-						*out_alert = SSL_AD_UNRECOGNIZED_NAME;
-						return 0;
-						}
-
 					/* Copy the hostname as a string. */
 					if (!CBS_strdup(&host_name, &s->session->tlsext_hostname))
 						{
 						*out_alert = SSL_AD_INTERNAL_ERROR;
 						return 0;
 						}
-					s->servername_done = 1;
-					}
-				else
-					{
-					s->servername_done = s->session->tlsext_hostname
-						&& strlen(s->session->tlsext_hostname) == CBS_len(&host_name)
-						&& strncmp(s->session->tlsext_hostname,
-							(char *)CBS_data(&host_name), CBS_len(&host_name)) == 0;
+
+					s->should_ack_sni = 1;
 					}
 				}
 			}
 
-#ifndef OPENSSL_NO_EC
 		else if (type == TLSEXT_TYPE_ec_point_formats)
 			{
 			CBS ec_point_format_list;
@@ -1719,7 +1648,6 @@
 				s->session->tlsext_ellipticcurvelist_length = num_curves;
 				}
 			}
-#endif /* OPENSSL_NO_EC */
 		else if (type == TLSEXT_TYPE_session_ticket)
 			{
 			if (s->tls_session_ticket_ext_cb &&
@@ -1772,120 +1700,6 @@
 				}
 			}
 
-                /* TODO(fork): we probably want OCSP stapling support, but this pulls in a lot of code. */
-#if 0
-		else if (type == TLSEXT_TYPE_status_request)
-			{
-			uint8_t status_type;
-			CBS responder_id_list;
-			CBS request_extensions;
-
-			if (!CBS_get_u8(&extension, &status_type))
-				{
-				*out_alert = SSL_AD_DECODE_ERROR;
-				return 0;
-				}
-
-			/* Only OCSP is supported. */
-			if (status_type != TLSEXT_STATUSTYPE_ocsp)
-				continue;
-
-			s->tlsext_status_type = status_type;
-
-			/* Extension consists of a responder_id_list and
-			 * request_extensions. */
-			if (!CBS_get_u16_length_prefixed(&extension, &responder_id_list) ||
-				!CBS_get_u16_length_prefixed(&extension, &request_extensions) ||
-				CBS_len(&extension) != 0)
-				{
-				*out_alert = SSL_AD_DECODE_ERROR;
-				return 0;
-				}
-
-			if (CBS_len(&responder_id_list) > 0)
-				{
-				s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null();
-				if (s->tlsext_ocsp_ids == NULL)
-					{
-					*out_alert = SSL_AD_INTERNAL_ERROR;
-					return 0;
-					}
-				}
-
-			/* Parse out the responder IDs. */
-			while (CBS_len(&responder_id_list) > 0)
-				{
-				CBS responder_id;
-				OCSP_RESPID *id;
-				const uint8_t *data;
-
-				/* Each ResponderID must have size at least 1. */
-				if (!CBS_get_u16_length_prefixed(&responder_id_list, &responder_id) ||
-					CBS_len(&responder_id) < 1)
-					{
-					*out_alert = SSL_AD_DECODE_ERROR;
-					return 0;
-					}
-
-				/* TODO(fork): Add CBS versions of d2i_FOO_BAR. */
-				data = CBS_data(&responder_id);
-				id = d2i_OCSP_RESPID(NULL, &data, CBS_len(&responder_id));
-				if (!id)
-					{
-					*out_alert = SSL_AD_DECODE_ERROR;
-					return 0;
-					}
-				if (!CBS_skip(&responder_id, data - CBS_data(&responder_id)))
-					{
-					/* This should never happen. */
-					*out_alert = SSL_AD_INTERNAL_ERROR;
-					OCSP_RESPID_free(id);
-					return 0;
-					}
-				if (CBS_len(&responder_id) != 0)
-					{
-					*out_alert = SSL_AD_DECODE_ERROR;
-					OCSP_RESPID_free(id);
-					return 0;
-					}
-
-				if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id))
-					{
-					*out_alert = SSL_AD_INTERNAL_ERROR;
-					OCSP_RESPID_free(id);
-					return 0;
-					}
-				}
-
-			/* Parse out request_extensions. */
-			if (CBS_len(&request_extensions) > 0)
-				{
-				const uint8_t *data;
-
-				data = CBS_data(&request_extensions);
-				s->tlsext_ocsp_exts = d2i_X509_EXTENSIONS(NULL,
-					&data, CBS_len(&request_extensions));
-				if (s->tlsext_ocsp_exts == NULL)
-					{
-					*out_alert = SSL_AD_DECODE_ERROR;
-					return 0;
-					}
-				if (!CBS_skip(&request_extensions, data - CBS_data(&request_extensions)))
-					{
-					/* This should never happen. */
-					*out_alert = SSL_AD_INTERNAL_ERROR;
-					return 0;
-					}
-				if (CBS_len(&request_extensions) != 0)
-					{
-					*out_alert = SSL_AD_DECODE_ERROR;
-					return 0;
-					}
-				}
-			}
-#endif
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
 		else if (type == TLSEXT_TYPE_next_proto_neg &&
 			 s->s3->tmp.finish_md_len == 0 &&
 			 s->s3->alpn_selected == NULL)
@@ -1914,7 +1728,6 @@
 			 * Finished message could have been computed.) */
 			s->s3->next_proto_neg_seen = 1;
 			}
-#endif
 
 		else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation &&
 			 s->ctx->alpn_select_cb &&
@@ -1922,10 +1735,8 @@
 			{
 			if (!tls1_alpn_handle_client_hello(s, &extension, out_alert))
 				return 0;
-#ifndef OPENSSL_NO_NEXTPROTONEG
 			/* ALPN takes precedence over NPN. */
 			s->s3->next_proto_neg_seen = 0;
-#endif
 			}
 
 		else if (type == TLSEXT_TYPE_channel_id &&
@@ -1972,7 +1783,7 @@
 		!(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
 		{
 		*out_alert = SSL_AD_HANDSHAKE_FAILURE;
-	 	OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+		OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
 		return 0;
 		}
 	/* If no signature algorithms extension set default values */
@@ -1991,7 +1802,7 @@
 		return 0;
 		}
 
-	if (ssl_check_clienthello_tlsext_early(s) <= 0) 
+	if (ssl_check_clienthello_tlsext(s) <= 0)
 		{
 		OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_tlsext, SSL_R_CLIENTHELLO_TLSEXT);
 		return 0;
@@ -1999,7 +1810,6 @@
 	return 1;
 	}
 
-#ifndef OPENSSL_NO_NEXTPROTONEG
 /* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
  * elements of zero length are allowed and the set of elements must exactly fill
  * the length of the block. */
@@ -2018,7 +1828,6 @@
 		}
 	return 1;
 	}
-#endif
 
 static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert)
 	{
@@ -2026,11 +1835,13 @@
 	int renegotiate_seen = 0;
 	CBS extensions;
 
-#ifndef OPENSSL_NO_NEXTPROTONEG
+	/* TODO(davidben): Move all of these to some per-handshake state that
+	 * gets systematically reset on a new handshake; perhaps allocate it
+	 * fresh each time so it's not even kept around post-handshake. */
 	s->s3->next_proto_neg_seen = 0;
-#endif
 
-        s->tlsext_ticket_expected = 0;
+	s->tlsext_ticket_expected = 0;
+	s->s3->tmp.certificate_status_expected = 0;
 
 	if (s->s3->alpn_selected)
 		{
@@ -2087,7 +1898,6 @@
 				}
 			tlsext_servername = 1;
 			}
-#ifndef OPENSSL_NO_EC
 		else if (type == TLSEXT_TYPE_ec_point_formats)
 			{
 			CBS ec_point_format_list;
@@ -2110,7 +1920,6 @@
 					}
 				}
 			}
-#endif /* OPENSSL_NO_EC */
 		else if (type == TLSEXT_TYPE_session_ticket)
 			{
 			if (s->tls_session_ticket_ext_cb &&
@@ -2138,15 +1947,14 @@
 				*out_alert = SSL_AD_DECODE_ERROR;
 				return 0;
 				}
-			if (s->tlsext_status_type == -1)
+			if (!s->ocsp_stapling_enabled)
 				{
 				*out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
 				return 0;
 				}
 			/* Set a flag to expect a CertificateStatus message */
-			s->tlsext_status_expected = 1;
+			s->s3->tmp.certificate_status_expected = 1;
 			}
-#ifndef OPENSSL_NO_NEXTPROTONEG
 		else if (type == TLSEXT_TYPE_next_proto_neg && s->s3->tmp.finish_md_len == 0) {
 		unsigned char *selected;
 		unsigned char selected_len;
@@ -2182,7 +1990,6 @@
 		s->next_proto_negotiated_len = selected_len;
 		s->s3->next_proto_neg_seen = 1;
 		}
-#endif
 		else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation)
 			{
 			CBS protocol_name_list, protocol_name;
@@ -2234,7 +2041,26 @@
 			s->s3->tlsext_channel_id_valid = 1;
 			s->s3->tlsext_channel_id_new = 1;
 			}
+		else if (type == TLSEXT_TYPE_certificate_timestamp)
+			{
+			if (CBS_len(&extension) == 0)
+				{
+				*out_alert = SSL_AD_DECODE_ERROR;
+				return 0;
+				}
 
+			/* Session resumption uses the original session information. */
+			if (!s->hit)
+				{
+				if (!CBS_stow(&extension,
+					&s->session->tlsext_signed_cert_timestamp_list,
+					&s->session->tlsext_signed_cert_timestamp_list_length))
+					{
+					*out_alert = SSL_AD_INTERNAL_ERROR;
+					return 0;
+					}
+				}
+			}
 		else if (type == TLSEXT_TYPE_renegotiate)
 			{
 			if (!ssl_parse_serverhello_renegotiate_ext(s, &extension, out_alert))
@@ -2301,19 +2127,17 @@
 	return 1;
 	}
 
-static int ssl_check_clienthello_tlsext_early(SSL *s)
+static int ssl_check_clienthello_tlsext(SSL *s)
 	{
 	int ret=SSL_TLSEXT_ERR_NOACK;
 	int al = SSL_AD_UNRECOGNIZED_NAME;
 
-#ifndef OPENSSL_NO_EC
 	/* The handling of the ECPointFormats extension is done elsewhere, namely in 
 	 * ssl3_choose_cipher in s3_lib.c.
 	 */
 	/* The handling of the EllipticCurves extension is done elsewhere, namely in 
 	 * ssl3_choose_cipher in s3_lib.c.
 	 */
-#endif
 
 	if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
 		ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
@@ -2328,86 +2152,22 @@
 
 		case SSL_TLSEXT_ERR_ALERT_WARNING:
 			ssl3_send_alert(s,SSL3_AL_WARNING,al);
-			return 1; 
-					
-		case SSL_TLSEXT_ERR_NOACK:
-			s->servername_done=0;
-			default:
-		return 1;
-		}
-	}
-
-int ssl_check_clienthello_tlsext_late(SSL *s)
-	{
-	int ret = SSL_TLSEXT_ERR_OK;
-	int al;
-
-	/* If status request then ask callback what to do.
- 	 * Note: this must be called after servername callbacks in case
- 	 * the certificate has changed, and must be called after the cipher
-	 * has been chosen because this may influence which certificate is sent
- 	 */
-	if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
-		{
-		int r;
-		CERT_PKEY *certpkey;
-		certpkey = ssl_get_server_send_pkey(s);
-		/* If no certificate can't return certificate status */
-		if (certpkey == NULL)
-			{
-			s->tlsext_status_expected = 0;
 			return 1;
-			}
-		/* Set current certificate to one we will use so
-		 * SSL_get_certificate et al can pick it up.
-		 */
-		s->cert->key = certpkey;
-		r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
-		switch (r)
-			{
-			/* We don't want to send a status request response */
-			case SSL_TLSEXT_ERR_NOACK:
-				s->tlsext_status_expected = 0;
-				break;
-			/* status request response should be sent */
-			case SSL_TLSEXT_ERR_OK:
-				if (s->tlsext_ocsp_resp)
-					s->tlsext_status_expected = 1;
-				else
-					s->tlsext_status_expected = 0;
-				break;
-			/* something bad happened */
-			case SSL_TLSEXT_ERR_ALERT_FATAL:
-				ret = SSL_TLSEXT_ERR_ALERT_FATAL;
-				al = SSL_AD_INTERNAL_ERROR;
-				goto err;
-			}
-		}
-	else
-		s->tlsext_status_expected = 0;
 
- err:
-	switch (ret)
-		{
-		case SSL_TLSEXT_ERR_ALERT_FATAL:
-			ssl3_send_alert(s, SSL3_AL_FATAL, al);
-			return -1;
-
-		case SSL_TLSEXT_ERR_ALERT_WARNING:
-			ssl3_send_alert(s, SSL3_AL_WARNING, al);
-			return 1; 
+		case SSL_TLSEXT_ERR_NOACK:
+			s->should_ack_sni = 0;
+			return 1;
 
 		default:
 			return 1;
 		}
 	}
 
-int ssl_check_serverhello_tlsext(SSL *s)
+static int ssl_check_serverhello_tlsext(SSL *s)
 	{
 	int ret=SSL_TLSEXT_ERR_NOACK;
 	int al = SSL_AD_UNRECOGNIZED_NAME;
 
-#ifndef OPENSSL_NO_EC
 	/* If we are client and using an elliptic curve cryptography cipher
 	 * suite, then if server returns an EC point formats lists extension
 	 * it must contain uncompressed.
@@ -2433,61 +2193,29 @@
 			}
 		if (!found_uncompressed)
 			{
-			OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+			OPENSSL_PUT_ERROR(SSL, ssl_check_serverhello_tlsext, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
 			return -1;
 			}
 		}
 	ret = SSL_TLSEXT_ERR_OK;
-#endif /* OPENSSL_NO_EC */
 
 	if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
 		ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
 	else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) 		
 		ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
 
-	/* If we've requested certificate status and we wont get one
- 	 * tell the callback
- 	 */
-	if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
-			&& s->ctx && s->ctx->tlsext_status_cb)
-		{
-		int r;
-		/* Set resp to NULL, resplen to -1 so callback knows
- 		 * there is no response.
- 		 */
-		if (s->tlsext_ocsp_resp)
-			{
-			OPENSSL_free(s->tlsext_ocsp_resp);
-			s->tlsext_ocsp_resp = NULL;
-			}
-		s->tlsext_ocsp_resplen = -1;
-		r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
-		if (r == 0)
-			{
-			al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
-			ret = SSL_TLSEXT_ERR_ALERT_FATAL;
-			}
-		if (r < 0)
-			{
-			al = SSL_AD_INTERNAL_ERROR;
-			ret = SSL_TLSEXT_ERR_ALERT_FATAL;
-			}
-		}
-
 	switch (ret)
 		{
 		case SSL_TLSEXT_ERR_ALERT_FATAL:
-			ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+			ssl3_send_alert(s,SSL3_AL_FATAL,al);
 			return -1;
 
 		case SSL_TLSEXT_ERR_ALERT_WARNING:
 			ssl3_send_alert(s,SSL3_AL_WARNING,al);
-			return 1; 
-					
-		case SSL_TLSEXT_ERR_NOACK:
-			s->servername_done=0;
-			default:
-		return 1;
+			return 1;
+
+		default:
+			return 1;
 		}
 	}
 
@@ -2783,14 +2511,10 @@
 	{
 	switch(hash_alg)
 		{
-#ifndef OPENSSL_NO_MD5
 		case TLSEXT_hash_md5:
 		return EVP_md5();
-#endif
-#ifndef OPENSSL_NO_SHA
 		case TLSEXT_hash_sha1:
 		return EVP_sha1();
-#endif
 		case TLSEXT_hash_sha224:
 		return EVP_sha224();
 
@@ -2813,10 +2537,8 @@
 		{
 	case TLSEXT_signature_rsa:
 		return SSL_PKEY_RSA_SIGN;
-#ifndef OPENSSL_NO_ECDSA
 	case TLSEXT_signature_ecdsa:
 		return SSL_PKEY_ECC;
-#endif
 		}
 	return -1;
 	}
@@ -3021,10 +2743,8 @@
 			c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
 			c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
 			}
-#ifndef OPENSSL_NO_ECDSA
 		if (!c->pkeys[SSL_PKEY_ECC].digest)
 			c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
-#endif
 		}
 	return 1;
 	}
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index c976e7c..5ee7c65 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -48,6 +48,20 @@
   return (const TestConfig *)SSL_get_ex_data(ssl, g_ex_data_index);
 }
 
+static EVP_PKEY *LoadPrivateKey(const std::string &file) {
+  BIO *bio = BIO_new(BIO_s_file());
+  if (bio == NULL) {
+    return NULL;
+  }
+  if (!BIO_read_filename(bio, file.c_str())) {
+    BIO_free(bio);
+    return NULL;
+  }
+  EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+  BIO_free(bio);
+  return pkey;
+}
+
 static int early_callback_called = 0;
 
 static int select_certificate_callback(const struct ssl_early_callback_ctx *ctx) {
@@ -125,6 +139,29 @@
   return SSL_TLSEXT_ERR_OK;
 }
 
+static int alpn_select_callback(SSL* ssl,
+                                const uint8_t** out,
+                                uint8_t* outlen,
+                                const uint8_t* in,
+                                unsigned inlen,
+                                void* arg) {
+  const TestConfig *config = GetConfigPtr(ssl);
+  if (config->select_alpn.empty())
+    return SSL_TLSEXT_ERR_NOACK;
+
+  if (!config->expected_advertised_alpn.empty() &&
+      (config->expected_advertised_alpn.size() != inlen ||
+       memcmp(config->expected_advertised_alpn.data(),
+              in, inlen) != 0)) {
+    fprintf(stderr, "bad ALPN select callback inputs\n");
+    exit(1);
+  }
+
+  *out = (const uint8_t*)config->select_alpn.data();
+  *outlen = config->select_alpn.size();
+  return SSL_TLSEXT_ERR_OK;
+}
+
 static int cookie_generate_callback(SSL *ssl, uint8_t *cookie, size_t *cookie_len) {
   *cookie_len = 32;
   memset(cookie, 42, *cookie_len);
@@ -199,12 +236,19 @@
 
   SSL_CTX_set_next_protos_advertised_cb(
       ssl_ctx, next_protos_advertised_callback, NULL);
-  SSL_CTX_set_next_proto_select_cb(
-      ssl_ctx, next_proto_select_callback, NULL);
+  if (!config->select_next_proto.empty()) {
+    SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_callback, NULL);
+  }
+
+  if (!config->select_alpn.empty()) {
+    SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_callback, NULL);
+  }
 
   SSL_CTX_set_cookie_generate_cb(ssl_ctx, cookie_generate_callback);
   SSL_CTX_set_cookie_verify_cb(ssl_ctx, cookie_verify_callback);
 
+  ssl_ctx->tlsext_channel_id_enabled_new = 1;
+
   DH_free(dh);
   return ssl_ctx;
 
@@ -300,6 +344,33 @@
   if (config->cookie_exchange) {
     SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
   }
+  if (config->tls_d5_bug) {
+    SSL_set_options(ssl, SSL_OP_TLS_D5_BUG);
+  }
+  if (!config->expected_channel_id.empty()) {
+    SSL_enable_tls_channel_id(ssl);
+  }
+  if (!config->send_channel_id.empty()) {
+    EVP_PKEY *pkey = LoadPrivateKey(config->send_channel_id);
+    if (pkey == NULL) {
+      BIO_print_errors_fp(stdout);
+      return 1;
+    }
+    SSL_enable_tls_channel_id(ssl);
+    if (!SSL_set1_tls_channel_id(ssl, pkey)) {
+      EVP_PKEY_free(pkey);
+      BIO_print_errors_fp(stdout);
+      return 1;
+    }
+    EVP_PKEY_free(pkey);
+  }
+  if (!config->host_name.empty()) {
+    SSL_set_tlsext_host_name(ssl, config->host_name.c_str());
+  }
+  if (!config->advertise_alpn.empty()) {
+    SSL_set_alpn_protos(ssl, (const uint8_t *)config->advertise_alpn.data(),
+                        config->advertise_alpn.size());
+  }
 
   BIO *bio = BIO_new_fd(fd, 1 /* take ownership */);
   if (bio == NULL) {
@@ -340,8 +411,9 @@
     return 2;
   }
 
-  if (is_resume && !SSL_session_reused(ssl)) {
-    fprintf(stderr, "session was not reused\n");
+  if (is_resume && (SSL_session_reused(ssl) == config->expect_session_miss)) {
+    fprintf(stderr, "session was%s reused\n",
+            SSL_session_reused(ssl) ? "" : " not");
     return 2;
   }
 
@@ -363,7 +435,7 @@
   if (!config->expected_certificate_types.empty()) {
     uint8_t *certificate_types;
     int num_certificate_types =
-      SSL_get0_certificate_types(ssl, &certificate_types);
+        SSL_get0_certificate_types(ssl, &certificate_types);
     if (num_certificate_types !=
         (int)config->expected_certificate_types.size() ||
         memcmp(certificate_types,
@@ -386,6 +458,32 @@
     }
   }
 
+  if (!config->expected_alpn.empty()) {
+    const uint8_t *alpn_proto;
+    unsigned alpn_proto_len;
+    SSL_get0_alpn_selected(ssl, &alpn_proto, &alpn_proto_len);
+    if (alpn_proto_len != config->expected_alpn.size() ||
+        memcmp(alpn_proto, config->expected_alpn.data(),
+               alpn_proto_len) != 0) {
+      fprintf(stderr, "negotiated alpn proto mismatch\n");
+      return 2;
+    }
+  }
+
+  if (!config->expected_channel_id.empty()) {
+    uint8_t channel_id[64];
+    if (!SSL_get_tls_channel_id(ssl, channel_id, sizeof(channel_id))) {
+      fprintf(stderr, "no channel id negotiated\n");
+      return 2;
+    }
+    if (config->expected_channel_id.size() != 64 ||
+        memcmp(config->expected_channel_id.data(),
+               channel_id, 64) != 0) {
+      fprintf(stderr, "channel id mismatch\n");
+      return 2;
+    }
+  }
+
   if (config->write_different_record_sizes) {
     if (config->is_dtls) {
       fprintf(stderr, "write_different_record_sizes not supported for DTLS\n");
@@ -423,6 +521,12 @@
       }
     }
   } else {
+    if (config->shim_writes_first) {
+      int w;
+      do {
+        w = SSL_write(ssl, "hello", 5);
+      } while (config->async && retry_async(ssl, w, bio));
+    }
     for (;;) {
       uint8_t buf[512];
       int n;
diff --git a/ssl/test/runner/channel_id_key.pem b/ssl/test/runner/channel_id_key.pem
new file mode 100644
index 0000000..604752b
--- /dev/null
+++ b/ssl/test/runner/channel_id_key.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIPwxu50c7LEhVNRYJFRWBUnoaz7JSos96T5hBp4rjyptoAoGCCqGSM49
+AwEHoUQDQgAEzFSVTE5guxJRQ0VbZ8dicPs5e/DT7xpW7Yc9hq0VOchv7cbXuI/T
+CwadDjGWX/oaz0ftFqrVmfkwZu+C58ioWg==
+-----END EC PRIVATE KEY-----
diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go
index ed26f09..6cd0de9 100644
--- a/ssl/test/runner/cipher_suites.go
+++ b/ssl/test/runner/cipher_suites.go
@@ -12,6 +12,8 @@
 	"crypto/md5"
 	"crypto/rc4"
 	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/sha512"
 	"crypto/x509"
 	"hash"
 )
@@ -79,20 +81,29 @@
 	{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
 	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
 	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
 	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteNoDTLS, cipherRC4, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteNoDTLS, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
+	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, cipherAES, macSHA256, nil},
 	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, 32, 48, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, cipherAES, macSHA384, nil},
+	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, 32, 48, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, cipherAES, macSHA384, nil},
 	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
 	{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, dheRSAKA, suiteTLS12, nil, nil, aeadAESGCM},
 	{TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, dheRSAKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, dheRSAKA, suiteTLS12, cipherAES, macSHA256, nil},
+	{TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, 32, 32, 16, dheRSAKA, suiteTLS12, cipherAES, macSHA256, nil},
 	{TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, dheRSAKA, 0, cipherAES, macSHA1, nil},
 	{TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, dheRSAKA, 0, cipherAES, macSHA1, nil},
 	{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
 	{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
 	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteNoDTLS, cipherRC4, macSHA1, nil},
 	{TLS_RSA_WITH_RC4_128_MD5, 16, 16, 0, rsaKA, suiteNoDTLS, cipherRC4, macMD5, nil},
+	{TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
+	{TLS_RSA_WITH_AES_256_CBC_SHA256, 32, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
 	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
 	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
@@ -146,6 +157,30 @@
 	return tls10MAC{hmac.New(md5.New, key)}
 }
 
+func macSHA256(version uint16, key []byte) macFunction {
+	if version == VersionSSL30 {
+		mac := ssl30MAC{
+			h:   sha256.New(),
+			key: make([]byte, len(key)),
+		}
+		copy(mac.key, key)
+		return mac
+	}
+	return tls10MAC{hmac.New(sha256.New, key)}
+}
+
+func macSHA384(version uint16, key []byte) macFunction {
+	if version == VersionSSL30 {
+		mac := ssl30MAC{
+			h:   sha512.New384(),
+			key: make([]byte, len(key)),
+		}
+		copy(mac.key, key)
+		return mac
+	}
+	return tls10MAC{hmac.New(sha512.New384, key)}
+}
+
 type macFunction interface {
 	Size() int
 	MAC(digestBuf, seq, header, length, data []byte) []byte
@@ -304,6 +339,10 @@
 	TLS_DHE_RSA_WITH_AES_128_CBC_SHA        uint16 = 0x0033
 	TLS_RSA_WITH_AES_256_CBC_SHA            uint16 = 0x0035
 	TLS_DHE_RSA_WITH_AES_256_CBC_SHA        uint16 = 0x0039
+	TLS_RSA_WITH_AES_128_CBC_SHA256         uint16 = 0x003c
+	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_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
@@ -315,8 +354,13 @@
 	TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA     uint16 = 0xc012
 	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA      uint16 = 0xc013
 	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA      uint16 = 0xc014
-	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   uint16 = 0xc02f
+	TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
+	TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xc024
+	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256   uint16 = 0xc027
+	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384   uint16 = 0xc028
 	TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+	TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
+	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   uint16 = 0xc02f
 	TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384   uint16 = 0xc030
 	fallbackSCSV                            uint16 = 0x5600
 )
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index f14f4e9..cf244bc 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -7,6 +7,7 @@
 import (
 	"container/list"
 	"crypto"
+	"crypto/ecdsa"
 	"crypto/rand"
 	"crypto/x509"
 	"fmt"
@@ -47,19 +48,20 @@
 
 // TLS handshake message types.
 const (
-	typeClientHello        uint8 = 1
-	typeServerHello        uint8 = 2
-	typeHelloVerifyRequest uint8 = 3
-	typeNewSessionTicket   uint8 = 4
-	typeCertificate        uint8 = 11
-	typeServerKeyExchange  uint8 = 12
-	typeCertificateRequest uint8 = 13
-	typeServerHelloDone    uint8 = 14
-	typeCertificateVerify  uint8 = 15
-	typeClientKeyExchange  uint8 = 16
-	typeFinished           uint8 = 20
-	typeCertificateStatus  uint8 = 22
-	typeNextProtocol       uint8 = 67 // Not IANA assigned
+	typeClientHello         uint8 = 1
+	typeServerHello         uint8 = 2
+	typeHelloVerifyRequest  uint8 = 3
+	typeNewSessionTicket    uint8 = 4
+	typeCertificate         uint8 = 11
+	typeServerKeyExchange   uint8 = 12
+	typeCertificateRequest  uint8 = 13
+	typeServerHelloDone     uint8 = 14
+	typeCertificateVerify   uint8 = 15
+	typeClientKeyExchange   uint8 = 16
+	typeFinished            uint8 = 20
+	typeCertificateStatus   uint8 = 22
+	typeNextProtocol        uint8 = 67  // Not IANA assigned
+	typeEncryptedExtensions uint8 = 203 // Not IANA assigned
 )
 
 // TLS compression types.
@@ -74,9 +76,11 @@
 	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
 )
 
 // TLS signaling cipher suite values
@@ -135,24 +139,24 @@
 // signatureAndHash mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See
 // RFC 5246, section A.4.1.
 type signatureAndHash struct {
-	hash, signature uint8
+	signature, hash uint8
 }
 
 // supportedSKXSignatureAlgorithms contains the signature and hash algorithms
 // that the code advertises as supported in a TLS 1.2 ClientHello.
 var supportedSKXSignatureAlgorithms = []signatureAndHash{
-	{hashSHA256, signatureRSA},
-	{hashSHA256, signatureECDSA},
-	{hashSHA1, signatureRSA},
-	{hashSHA1, signatureECDSA},
+	{signatureRSA, hashSHA256},
+	{signatureECDSA, hashSHA256},
+	{signatureRSA, hashSHA1},
+	{signatureECDSA, hashSHA1},
 }
 
 // supportedClientCertSignatureAlgorithms contains the signature and hash
 // algorithms that the code advertises as supported in a TLS 1.2
 // CertificateRequest.
 var supportedClientCertSignatureAlgorithms = []signatureAndHash{
-	{hashSHA256, signatureRSA},
-	{hashSHA256, signatureECDSA},
+	{signatureRSA, hashSHA256},
+	{signatureECDSA, hashSHA256},
 }
 
 // ConnectionState records basic TLS details about the connection.
@@ -163,9 +167,11 @@
 	CipherSuite                uint16                // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
 	NegotiatedProtocol         string                // negotiated next protocol (from Config.NextProtos)
 	NegotiatedProtocolIsMutual bool                  // negotiated protocol was advertised by server
+	NegotiatedProtocolFromALPN bool                  // protocol negotiated with ALPN
 	ServerName                 string                // server name requested by client, if any (server side only)
 	PeerCertificates           []*x509.Certificate   // certificate chain presented by remote peer
 	VerifiedChains             [][]*x509.Certificate // verified chains built from PeerCertificates
+	ChannelID                  *ecdsa.PublicKey      // the channel ID for this connection
 }
 
 // ClientAuthType declares the policy the server will follow for
@@ -187,6 +193,7 @@
 	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
 }
 
@@ -307,6 +314,15 @@
 	// be used.
 	CurvePreferences []CurveID
 
+	// ChannelID contains the ECDSA key for the client to use as
+	// its TLS Channel ID.
+	ChannelID *ecdsa.PrivateKey
+
+	// RequestChannelID controls whether the server requests a TLS
+	// Channel ID. If negotiated, the client's public key is
+	// returned in the ConnectionState.
+	RequestChannelID bool
+
 	// Bugs specifies optional misbehaviour to be used for testing other
 	// implementations.
 	Bugs ProtocolBugs
@@ -420,6 +436,34 @@
 	// SkipHelloVerifyRequest causes a DTLS server to skip the
 	// HelloVerifyRequest message.
 	SkipHelloVerifyRequest bool
+
+	// ExpectFalseStart causes the server to, on full handshakes,
+	// expect the peer to False Start; the server Finished message
+	// isn't sent until we receive an application data record
+	// from the peer.
+	ExpectFalseStart bool
+
+	// SSL3RSAKeyExchange causes the client to always send an RSA
+	// ClientKeyExchange message without the two-byte length
+	// prefix, as if it were SSL3.
+	SSL3RSAKeyExchange bool
+
+	// SkipCipherVersionCheck causes the server to negotiate
+	// TLS 1.2 ciphers in earlier versions of TLS.
+	SkipCipherVersionCheck bool
+
+	// ExpectServerName, if not empty, is the hostname the client
+	// must specify in the server_name extension.
+	ExpectServerName string
+
+	// SwapNPNAndALPN switches the relative order between NPN and
+	// ALPN on the server. This is to test that server preference
+	// of ALPN works regardless of their relative order.
+	SwapNPNAndALPN bool
+
+	// AllowSessionVersionMismatch causes the server to resume sessions
+	// regardless of the version associated with the session.
+	AllowSessionVersionMismatch bool
 }
 
 func (c *Config) serverInit() {
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 5371a64..9f0c328 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -9,6 +9,7 @@
 import (
 	"bytes"
 	"crypto/cipher"
+	"crypto/ecdsa"
 	"crypto/subtle"
 	"crypto/x509"
 	"errors"
@@ -46,6 +47,9 @@
 
 	clientProtocol         string
 	clientProtocolFallback bool
+	usedALPN               bool
+
+	channelID *ecdsa.PublicKey
 
 	// input/output
 	in, out  halfConn     // in.Mutex < out.Mutex
@@ -657,7 +661,7 @@
 			return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete"))
 		}
 	case recordTypeApplicationData:
-		if !c.handshakeComplete {
+		if !c.handshakeComplete && !c.config.Bugs.ExpectFalseStart {
 			c.sendAlert(alertInternalError)
 			return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
 		}
@@ -937,6 +941,8 @@
 		m = new(finishedMsg)
 	case typeHelloVerifyRequest:
 		m = new(helloVerifyRequestMsg)
+	case typeEncryptedExtensions:
+		m = new(encryptedExtensionsMsg)
 	default:
 		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 	}
@@ -1100,10 +1106,12 @@
 		state.NegotiatedProtocol = c.clientProtocol
 		state.DidResume = c.didResume
 		state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
+		state.NegotiatedProtocolFromALPN = c.usedALPN
 		state.CipherSuite = c.cipherSuite
 		state.PeerCertificates = c.peerCertificates
 		state.VerifiedChains = c.verifiedChains
 		state.ServerName = c.serverName
+		state.ChannelID = c.channelID
 	}
 
 	return state
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index ecc2bed..d78e767 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -8,6 +8,7 @@
 	"bytes"
 	"crypto"
 	"crypto/ecdsa"
+	"crypto/elliptic"
 	"crypto/rsa"
 	"crypto/subtle"
 	"crypto/x509"
@@ -42,6 +43,18 @@
 	c.sendHandshakeSeq = 0
 	c.recvHandshakeSeq = 0
 
+	nextProtosLength := 0
+	for _, proto := range c.config.NextProtos {
+		if l := len(proto); l == 0 || l > 255 {
+			return errors.New("tls: invalid NextProtos value")
+		} else {
+			nextProtosLength += 1 + l
+		}
+	}
+	if nextProtosLength > 0xffff {
+		return errors.New("tls: NextProtos values too large")
+	}
+
 	hello := &clientHelloMsg{
 		isDTLS:              c.isDTLS,
 		vers:                c.config.maxVersion(),
@@ -53,7 +66,10 @@
 		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,
 	}
 
 	if c.config.Bugs.SendClientVersion != 0 {
@@ -238,7 +254,7 @@
 		if err := hs.readFinished(); err != nil {
 			return err
 		}
-		if err := hs.sendFinished(); err != nil {
+		if err := hs.sendFinished(isResume); err != nil {
 			return err
 		}
 	} else {
@@ -248,7 +264,7 @@
 		if err := hs.establishKeys(); err != nil {
 			return err
 		}
-		if err := hs.sendFinished(); err != nil {
+		if err := hs.sendFinished(isResume); err != nil {
 			return err
 		}
 		if err := hs.readSessionTicket(); err != nil {
@@ -472,6 +488,8 @@
 		c.writeRecord(recordTypeHandshake, ckx.marshal())
 	}
 
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+
 	if chainToSend != nil {
 		var signed []byte
 		certVerify := &certificateVerifyMsg{
@@ -485,7 +503,7 @@
 				break
 			}
 			var digest []byte
-			digest, _, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash)
+			digest, _, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret)
 			if err != nil {
 				break
 			}
@@ -501,7 +519,7 @@
 			}
 			var digest []byte
 			var hashFunc crypto.Hash
-			digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash)
+			digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret)
 			if err != nil {
 				break
 			}
@@ -519,7 +537,8 @@
 		c.writeRecord(recordTypeHandshake, certVerify.marshal())
 	}
 
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+	hs.finishedHash.discardHandshakeBuffer()
+
 	return nil
 }
 
@@ -560,15 +579,42 @@
 		return false, errors.New("tls: server selected unsupported compression format")
 	}
 
-	if !hs.hello.nextProtoNeg && hs.serverHello.nextProtoNeg {
+	clientDidNPN := hs.hello.nextProtoNeg
+	clientDidALPN := len(hs.hello.alpnProtocols) > 0
+	serverHasNPN := hs.serverHello.nextProtoNeg
+	serverHasALPN := len(hs.serverHello.alpnProtocol) > 0
+
+	if !clientDidNPN && serverHasNPN {
 		c.sendAlert(alertHandshakeFailure)
 		return false, errors.New("server advertised unrequested NPN extension")
 	}
 
+	if !clientDidALPN && serverHasALPN {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("server advertised unrequested ALPN extension")
+	}
+
+	if serverHasNPN && serverHasALPN {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("server advertised both NPN and ALPN extensions")
+	}
+
+	if serverHasALPN {
+		c.clientProtocol = hs.serverHello.alpnProtocol
+		c.clientProtocolFallback = false
+		c.usedALPN = true
+	}
+
+	if !hs.hello.channelIDSupported && hs.serverHello.channelIDRequested {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("server advertised unrequested Channel ID extension")
+	}
+
 	if hs.serverResumedSession() {
 		// Restore masterSecret and peerCerts from previous state
 		hs.masterSecret = hs.session.masterSecret
 		c.peerCertificates = hs.session.serverCertificates
+		hs.finishedHash.discardHandshakeBuffer()
 		return true, nil
 	}
 	return false, nil
@@ -619,20 +665,22 @@
 		c.sendAlert(alertUnexpectedMessage)
 		return unexpectedMessageError(sessionTicketMsg, msg)
 	}
-	hs.writeServerHash(sessionTicketMsg.marshal())
 
 	hs.session = &ClientSessionState{
 		sessionTicket:      sessionTicketMsg.ticket,
 		vers:               c.vers,
 		cipherSuite:        hs.suite.id,
 		masterSecret:       hs.masterSecret,
+		handshakeHash:      hs.finishedHash.server.Sum(nil),
 		serverCertificates: c.peerCertificates,
 	}
 
+	hs.writeServerHash(sessionTicketMsg.marshal())
+
 	return nil
 }
 
-func (hs *clientHandshakeState) sendFinished() error {
+func (hs *clientHandshakeState) sendFinished(isResume bool) error {
 	c := hs.c
 
 	var postCCSBytes []byte
@@ -650,6 +698,34 @@
 		postCCSBytes = append(postCCSBytes, nextProtoBytes...)
 	}
 
+	if hs.serverHello.channelIDRequested {
+		encryptedExtensions := new(encryptedExtensionsMsg)
+		if c.config.ChannelID.Curve != elliptic.P256() {
+			return fmt.Errorf("tls: Channel ID is not on P-256.")
+		}
+		var resumeHash []byte
+		if isResume {
+			resumeHash = hs.session.handshakeHash
+		}
+		r, s, err := ecdsa.Sign(c.config.rand(), c.config.ChannelID, hs.finishedHash.hashForChannelID(resumeHash))
+		if err != nil {
+			return err
+		}
+		channelID := make([]byte, 128)
+		writeIntPadded(channelID[0:32], c.config.ChannelID.X)
+		writeIntPadded(channelID[32:64], c.config.ChannelID.Y)
+		writeIntPadded(channelID[64:96], r)
+		writeIntPadded(channelID[96:128], s)
+		encryptedExtensions.channelID = channelID
+
+		c.channelID = &c.config.ChannelID.PublicKey
+
+		encryptedExtensionsBytes := encryptedExtensions.marshal()
+		hs.writeHash(encryptedExtensionsBytes, seqno)
+		seqno++
+		postCCSBytes = append(postCCSBytes, encryptedExtensionsBytes...)
+	}
+
 	finished := new(finishedMsg)
 	if c.config.Bugs.EarlyChangeCipherSpec == 2 {
 		finished.verifyData = hs.finishedHash.clientSum(nil)
@@ -709,18 +785,28 @@
 	return serverAddr.String()
 }
 
-// mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
-// set of client and server supported protocols. The set of client supported
-// protocols must not be empty. It returns the resulting protocol and flag
+// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol
+// given list of possible protocols and a list of the preference order. The
+// first list must not be empty. It returns the resulting protocol and flag
 // indicating if the fallback case was reached.
-func mutualProtocol(clientProtos, serverProtos []string) (string, bool) {
-	for _, s := range serverProtos {
-		for _, c := range clientProtos {
+func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
+	for _, s := range preferenceProtos {
+		for _, c := range protos {
 			if s == c {
 				return s, false
 			}
 		}
 	}
 
-	return clientProtos[0], true
+	return protos[0], true
+}
+
+// writeIntPadded writes x into b, padded up with leading zeros as
+// needed.
+func writeIntPadded(b []byte, x *big.Int) {
+	for i := range b {
+		b[i] = 0
+	}
+	xb := x.Bytes()
+	copy(b[len(b)-len(xb):], xb)
 }
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 7fe8bf5..136360d 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -24,7 +24,10 @@
 	sessionTicket       []uint8
 	signatureAndHashes  []signatureAndHash
 	secureRenegotiation bool
+	alpnProtocols       []string
 	duplicateExtension  bool
+	channelIDSupported  bool
+	npnLast             bool
 }
 
 func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -49,7 +52,11 @@
 		m.ticketSupported == m1.ticketSupported &&
 		bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
 		eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
-		m.secureRenegotiation == m1.secureRenegotiation
+		m.secureRenegotiation == m1.secureRenegotiation &&
+		eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
+		m.duplicateExtension == m1.duplicateExtension &&
+		m.channelIDSupported == m1.channelIDSupported &&
+		m.npnLast == m1.npnLast
 }
 
 func (m *clientHelloMsg) marshal() []byte {
@@ -97,6 +104,20 @@
 	if m.duplicateExtension {
 		numExtensions += 2
 	}
+	if m.channelIDSupported {
+		numExtensions++
+	}
+	if len(m.alpnProtocols) > 0 {
+		extensionsLength += 2
+		for _, s := range m.alpnProtocols {
+			if l := len(s); l == 0 || l > 255 {
+				panic("invalid ALPN protocol")
+			}
+			extensionsLength++
+			extensionsLength += len(s)
+		}
+		numExtensions++
+	}
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
 		length += 2 + extensionsLength
@@ -141,7 +162,7 @@
 		z[1] = 0xff
 		z = z[4:]
 	}
-	if m.nextProtoNeg {
+	if m.nextProtoNeg && !m.npnLast {
 		z[0] = byte(extensionNextProtoNeg >> 8)
 		z[1] = byte(extensionNextProtoNeg & 0xff)
 		// The length is always 0
@@ -260,6 +281,38 @@
 		z[3] = 1
 		z = z[5:]
 	}
+	if len(m.alpnProtocols) > 0 {
+		z[0] = byte(extensionALPN >> 8)
+		z[1] = byte(extensionALPN & 0xff)
+		lengths := z[2:]
+		z = z[6:]
+
+		stringsLength := 0
+		for _, s := range m.alpnProtocols {
+			l := len(s)
+			z[0] = byte(l)
+			copy(z[1:], s)
+			z = z[1+l:]
+			stringsLength += 1 + l
+		}
+
+		lengths[2] = byte(stringsLength >> 8)
+		lengths[3] = byte(stringsLength)
+		stringsLength += 2
+		lengths[0] = byte(stringsLength >> 8)
+		lengths[1] = byte(stringsLength)
+	}
+	if m.channelIDSupported {
+		z[0] = byte(extensionChannelID >> 8)
+		z[1] = byte(extensionChannelID & 0xff)
+		z = z[4:]
+	}
+	if m.nextProtoNeg && m.npnLast {
+		z[0] = byte(extensionNextProtoNeg >> 8)
+		z[1] = byte(extensionNextProtoNeg & 0xff)
+		// The length is always 0
+		z = z[4:]
+	}
 	if m.duplicateExtension {
 		// Add a duplicate bogus extension at the beginning and end.
 		z[0] = 0xff
@@ -331,6 +384,7 @@
 	m.ticketSupported = false
 	m.sessionTicket = nil
 	m.signatureAndHashes = nil
+	m.alpnProtocols = nil
 
 	if len(data) == 0 {
 		// ClientHello is optionally followed by extension data
@@ -440,6 +494,29 @@
 				return false
 			}
 			m.secureRenegotiation = true
+		case extensionALPN:
+			if length < 2 {
+				return false
+			}
+			l := int(data[0])<<8 | int(data[1])
+			if l != length-2 {
+				return false
+			}
+			d := data[2:length]
+			for len(d) != 0 {
+				stringLen := int(d[0])
+				d = d[1:]
+				if stringLen == 0 || stringLen > len(d) {
+					return false
+				}
+				m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
+				d = d[stringLen:]
+			}
+		case extensionChannelID:
+			if length > 0 {
+				return false
+			}
+			m.channelIDSupported = true
 		}
 		data = data[length:]
 	}
@@ -460,7 +537,9 @@
 	ocspStapling        bool
 	ticketSupported     bool
 	secureRenegotiation bool
+	alpnProtocol        string
 	duplicateExtension  bool
+	channelIDRequested  bool
 }
 
 func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -480,7 +559,10 @@
 		eqStrings(m.nextProtos, m1.nextProtos) &&
 		m.ocspStapling == m1.ocspStapling &&
 		m.ticketSupported == m1.ticketSupported &&
-		m.secureRenegotiation == m1.secureRenegotiation
+		m.secureRenegotiation == m1.secureRenegotiation &&
+		m.alpnProtocol == m1.alpnProtocol &&
+		m.duplicateExtension == m1.duplicateExtension &&
+		m.channelIDRequested == m1.channelIDRequested
 }
 
 func (m *serverHelloMsg) marshal() []byte {
@@ -514,6 +596,17 @@
 	if m.duplicateExtension {
 		numExtensions += 2
 	}
+	if m.channelIDRequested {
+		numExtensions++
+	}
+	if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
+		if alpnLen >= 256 {
+			panic("invalid ALPN protocol")
+		}
+		extensionsLength += 2 + 1 + alpnLen
+		numExtensions++
+	}
+
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
 		length += 2 + extensionsLength
@@ -581,6 +674,25 @@
 		z[3] = 1
 		z = z[5:]
 	}
+	if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
+		z[0] = byte(extensionALPN >> 8)
+		z[1] = byte(extensionALPN & 0xff)
+		l := 2 + 1 + alpnLen
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		l -= 2
+		z[4] = byte(l >> 8)
+		z[5] = byte(l)
+		l -= 1
+		z[6] = byte(l)
+		copy(z[7:], []byte(m.alpnProtocol))
+		z = z[7+alpnLen:]
+	}
+	if m.channelIDRequested {
+		z[0] = byte(extensionChannelID >> 8)
+		z[1] = byte(extensionChannelID & 0xff)
+		z = z[4:]
+	}
 	if m.duplicateExtension {
 		// Add a duplicate bogus extension at the beginning and end.
 		z[0] = 0xff
@@ -617,6 +729,7 @@
 	m.nextProtos = nil
 	m.ocspStapling = false
 	m.ticketSupported = false
+	m.alpnProtocol = ""
 
 	if len(data) == 0 {
 		// ServerHello is optionally followed by extension data
@@ -671,6 +784,27 @@
 				return false
 			}
 			m.secureRenegotiation = true
+		case extensionALPN:
+			d := data[:length]
+			if len(d) < 3 {
+				return false
+			}
+			l := int(d[0])<<8 | int(d[1])
+			if l != len(d)-2 {
+				return false
+			}
+			d = d[2:]
+			l = int(d[0])
+			if l != len(d)-1 {
+				return false
+			}
+			d = d[1:]
+			m.alpnProtocol = string(d)
+		case extensionChannelID:
+			if length > 0 {
+				return false
+			}
+			m.channelIDRequested = true
 		}
 		data = data[length:]
 	}
@@ -1407,7 +1541,8 @@
 		return false
 	}
 
-	return m.vers == m1.vers &&
+	return bytes.Equal(m.raw, m1.raw) &&
+		m.vers == m1.vers &&
 		bytes.Equal(m.cookie, m1.cookie)
 }
 
@@ -1447,6 +1582,58 @@
 	return true
 }
 
+type encryptedExtensionsMsg struct {
+	raw       []byte
+	channelID []byte
+}
+
+func (m *encryptedExtensionsMsg) equal(i interface{}) bool {
+	m1, ok := i.(*encryptedExtensionsMsg)
+	if !ok {
+		return false
+	}
+
+	return bytes.Equal(m.raw, m1.raw) &&
+		bytes.Equal(m.channelID, m1.channelID)
+}
+
+func (m *encryptedExtensionsMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	length := 2 + 2 + len(m.channelID)
+
+	x := make([]byte, 4+length)
+	x[0] = typeEncryptedExtensions
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	x[4] = uint8(extensionChannelID >> 8)
+	x[5] = uint8(extensionChannelID & 0xff)
+	x[6] = uint8(len(m.channelID) >> 8)
+	x[7] = uint8(len(m.channelID) & 0xff)
+	copy(x[8:], m.channelID)
+
+	return x
+}
+
+func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
+	if len(data) != 4+2+2+128 {
+		return false
+	}
+	m.raw = data
+	if (uint16(data[4])<<8)|uint16(data[5]) != extensionChannelID {
+		return false
+	}
+	if int(data[6])<<8|int(data[7]) != 128 {
+		return false
+	}
+	m.channelID = data[4+2+2:]
+
+	return true
+}
+
 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 d5a660a..1eb3f11 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -8,6 +8,7 @@
 	"bytes"
 	"crypto"
 	"crypto/ecdsa"
+	"crypto/elliptic"
 	"crypto/rsa"
 	"crypto/subtle"
 	"crypto/x509"
@@ -15,6 +16,7 @@
 	"errors"
 	"fmt"
 	"io"
+	"math/big"
 )
 
 // serverHandshakeState contains details of a server handshake in progress.
@@ -69,7 +71,7 @@
 		if err := hs.sendFinished(); err != nil {
 			return err
 		}
-		if err := hs.readFinished(); err != nil {
+		if err := hs.readFinished(isResume); err != nil {
 			return err
 		}
 		c.didResume = true
@@ -82,9 +84,14 @@
 		if err := hs.establishKeys(); err != nil {
 			return err
 		}
-		if err := hs.readFinished(); err != nil {
+		if err := hs.readFinished(isResume); err != nil {
 			return err
 		}
+		if c.config.Bugs.ExpectFalseStart {
+			if err := c.readRecord(recordTypeApplicationData); err != nil {
+				return err
+			}
+		}
 		if err := hs.sendSessionTicket(); err != nil {
 			return err
 		}
@@ -213,13 +220,22 @@
 	if len(hs.clientHello.serverName) > 0 {
 		c.serverName = hs.clientHello.serverName
 	}
-	// Although sending an empty NPN extension is reasonable, Firefox has
-	// had a bug around this. Best to send nothing at all if
-	// config.NextProtos is empty. See
-	// https://code.google.com/p/go/issues/detail?id=5445.
-	if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
-		hs.hello.nextProtoNeg = true
-		hs.hello.nextProtos = config.NextProtos
+
+	if len(hs.clientHello.alpnProtocols) > 0 {
+		if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
+			hs.hello.alpnProtocol = selectedProto
+			c.clientProtocol = selectedProto
+			c.usedALPN = true
+		}
+	} else {
+		// Although sending an empty NPN extension is reasonable, Firefox has
+		// had a bug around this. Best to send nothing at all if
+		// config.NextProtos is empty. See
+		// https://code.google.com/p/go/issues/detail?id=5445.
+		if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
+			hs.hello.nextProtoNeg = true
+			hs.hello.nextProtos = config.NextProtos
+		}
 	}
 
 	if len(config.Certificates) == 0 {
@@ -230,6 +246,13 @@
 	if len(hs.clientHello.serverName) > 0 {
 		hs.cert = config.getCertificateForName(hs.clientHello.serverName)
 	}
+	if expected := c.config.Bugs.ExpectServerName; expected != "" && expected != hs.clientHello.serverName {
+		return false, errors.New("tls: unexpected server name")
+	}
+
+	if hs.clientHello.channelIDSupported && config.RequestChannelID {
+		hs.hello.channelIDRequested = true
+	}
 
 	_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
 
@@ -279,16 +302,22 @@
 func (hs *serverHandshakeState) checkForResumption() bool {
 	c := hs.c
 
+	if c.config.SessionTicketsDisabled {
+		return false
+	}
+
 	var ok bool
 	if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok {
 		return false
 	}
 
-	if hs.sessionState.vers > hs.clientHello.vers {
-		return false
-	}
-	if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
-		return false
+	if !c.config.Bugs.AllowSessionVersionMismatch {
+		if hs.sessionState.vers > hs.clientHello.vers {
+			return false
+		}
+		if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
+			return false
+		}
 	}
 
 	cipherSuiteOk := false
@@ -331,6 +360,7 @@
 	hs.hello.ticketSupported = c.config.Bugs.RenewTicketOnResume
 
 	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash.discardHandshakeBuffer()
 	hs.writeClientHash(hs.clientHello.marshal())
 	hs.writeServerHash(hs.hello.marshal())
 
@@ -467,6 +497,13 @@
 	}
 	hs.writeClientHash(ckx.marshal())
 
+	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	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
 	// clientKeyExchangeMsg.  This message is a digest of all preceding
@@ -515,7 +552,7 @@
 				break
 			}
 			var digest []byte
-			digest, _, err = hs.finishedHash.hashForClientCertificate(signatureAndHash)
+			digest, _, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret)
 			if err != nil {
 				break
 			}
@@ -530,7 +567,7 @@
 			}
 			var digest []byte
 			var hashFunc crypto.Hash
-			digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(signatureAndHash)
+			digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret)
 			if err != nil {
 				break
 			}
@@ -544,12 +581,7 @@
 		hs.writeClientHash(certVerify.marshal())
 	}
 
-	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
-	if err != nil {
-		c.sendAlert(alertHandshakeFailure)
-		return err
-	}
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+	hs.finishedHash.discardHandshakeBuffer()
 
 	return nil
 }
@@ -579,7 +611,7 @@
 	return nil
 }
 
-func (hs *serverHandshakeState) readFinished() error {
+func (hs *serverHandshakeState) readFinished(isResume bool) error {
 	c := hs.c
 
 	c.readRecord(recordTypeChangeCipherSpec)
@@ -601,6 +633,36 @@
 		c.clientProtocol = nextProto.proto
 	}
 
+	if hs.hello.channelIDRequested {
+		msg, err := c.readHandshake()
+		if err != nil {
+			return err
+		}
+		encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(encryptedExtensions, msg)
+		}
+		x := new(big.Int).SetBytes(encryptedExtensions.channelID[0:32])
+		y := new(big.Int).SetBytes(encryptedExtensions.channelID[32:64])
+		r := new(big.Int).SetBytes(encryptedExtensions.channelID[64:96])
+		s := new(big.Int).SetBytes(encryptedExtensions.channelID[96:128])
+		if !elliptic.P256().IsOnCurve(x, y) {
+			return errors.New("tls: invalid channel ID public key")
+		}
+		channelID := &ecdsa.PublicKey{elliptic.P256(), x, y}
+		var resumeHash []byte
+		if isResume {
+			resumeHash = hs.sessionState.handshakeHash
+		}
+		if !ecdsa.Verify(channelID, hs.finishedHash.hashForChannelID(resumeHash), r, s) {
+			return errors.New("tls: invalid channel ID signature")
+		}
+		c.channelID = channelID
+
+		hs.writeClientHash(encryptedExtensions.marshal())
+	}
+
 	msg, err := c.readHandshake()
 	if err != nil {
 		return err
@@ -632,10 +694,11 @@
 
 	var err error
 	state := sessionState{
-		vers:         c.vers,
-		cipherSuite:  hs.suite.id,
-		masterSecret: hs.masterSecret,
-		certificates: hs.certsFromClient,
+		vers:          c.vers,
+		cipherSuite:   hs.suite.id,
+		masterSecret:  hs.masterSecret,
+		certificates:  hs.certsFromClient,
+		handshakeHash: hs.finishedHash.server.Sum(nil),
 	}
 	m.ticket, err = c.encryptTicket(&state)
 	if err != nil {
@@ -787,7 +850,7 @@
 			if (candidate.flags&suiteECDSA != 0) != ecdsaOk {
 				continue
 			}
-			if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
+			if !c.config.Bugs.SkipCipherVersionCheck && version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
 				continue
 			}
 			if c.isDTLS && candidate.flags&suiteNoDTLS != 0 {
diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go
index 2e2eff4..f8ba1f8 100644
--- a/ssl/test/runner/key_agreement.go
+++ b/ssl/test/runner/key_agreement.go
@@ -87,7 +87,7 @@
 		return nil, nil, err
 	}
 	ckx := new(clientKeyExchangeMsg)
-	if clientHello.vers != VersionSSL30 {
+	if clientHello.vers != VersionSSL30 && !config.Bugs.SSL3RSAKeyExchange {
 		ckx.ciphertext = make([]byte, len(encrypted)+2)
 		ckx.ciphertext[0] = byte(len(encrypted) >> 8)
 		ckx.ciphertext[1] = byte(len(encrypted))
diff --git a/ssl/test/runner/prf.go b/ssl/test/runner/prf.go
index 991196f..6d0db97 100644
--- a/ssl/test/runner/prf.go
+++ b/ssl/test/runner/prf.go
@@ -120,6 +120,8 @@
 var keyExpansionLabel = []byte("key expansion")
 var clientFinishedLabel = []byte("client finished")
 var serverFinishedLabel = []byte("server finished")
+var channelIDLabel = []byte("TLS Channel ID signature\x00")
+var channelIDResumeLabel = []byte("Resumption\x00")
 
 func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
 	switch version {
@@ -180,9 +182,9 @@
 			newHash = sha512.New384
 		}
 
-		return finishedHash{newHash(), newHash(), nil, nil, version, prf12(newHash)}
+		return finishedHash{newHash(), newHash(), nil, nil, []byte{}, version, prf12(newHash)}
 	}
-	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), version, prf10}
+	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), []byte{}, version, prf10}
 }
 
 // A finishedHash calculates the hash of a set of handshake messages suitable
@@ -195,11 +197,15 @@
 	clientMD5 hash.Hash
 	serverMD5 hash.Hash
 
+	// In TLS 1.2 (and SSL 3 for implementation convenience), a
+	// full buffer is required.
+	buffer []byte
+
 	version uint16
 	prf     func(result, secret, label, seed []byte)
 }
 
-func (h finishedHash) Write(msg []byte) (n int, err error) {
+func (h *finishedHash) Write(msg []byte) (n int, err error) {
 	h.client.Write(msg)
 	h.server.Write(msg)
 
@@ -207,14 +213,19 @@
 		h.clientMD5.Write(msg)
 		h.serverMD5.Write(msg)
 	}
+
+	if h.buffer != nil {
+		h.buffer = append(h.buffer, msg...)
+	}
+
 	return len(msg), nil
 }
 
 // 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.
-func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte {
-	md5.Write(magic[:])
+func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
+	md5.Write(magic)
 	md5.Write(masterSecret)
 	md5.Write(ssl30Pad1[:])
 	md5Digest := md5.Sum(nil)
@@ -225,7 +236,7 @@
 	md5.Write(md5Digest)
 	md5Digest = md5.Sum(nil)
 
-	sha1.Write(magic[:])
+	sha1.Write(magic)
 	sha1.Write(masterSecret)
 	sha1.Write(ssl30Pad1[:40])
 	sha1Digest := sha1.Sum(nil)
@@ -249,7 +260,7 @@
 // Finished message.
 func (h finishedHash) clientSum(masterSecret []byte) []byte {
 	if h.version == VersionSSL30 {
-		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic)
+		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
 	}
 
 	out := make([]byte, finishedVerifyLength)
@@ -269,7 +280,7 @@
 // Finished message.
 func (h finishedHash) serverSum(masterSecret []byte) []byte {
 	if h.version == VersionSSL30 {
-		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic)
+		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
 	}
 
 	out := make([]byte, finishedVerifyLength)
@@ -290,7 +301,7 @@
 func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) {
 	if h.version < VersionTLS12 {
 		// Nothing to negotiate before TLS 1.2.
-		return signatureAndHash{sigType, 0}, nil
+		return signatureAndHash{signature: sigType}, nil
 	}
 
 	for _, v := range serverList {
@@ -303,13 +314,24 @@
 
 // hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
 // id suitable for signing by a TLS client certificate.
-func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash) ([]byte, crypto.Hash, error) {
+func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash, masterSecret []byte) ([]byte, crypto.Hash, error) {
+	if h.version == VersionSSL30 {
+		if signatureAndHash.signature != signatureRSA {
+			return nil, 0, errors.New("tls: unsupported signature type for client certificate")
+		}
+
+		md5Hash := md5.New()
+		md5Hash.Write(h.buffer)
+		sha1Hash := sha1.New()
+		sha1Hash.Write(h.buffer)
+		return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil
+	}
 	if h.version >= VersionTLS12 {
 		if signatureAndHash.hash != hashSHA256 {
 			return nil, 0, errors.New("tls: unsupported hash function for client certificate")
 		}
-		digest := h.server.Sum(nil)
-		return digest, crypto.SHA256, nil
+		digest := sha256.Sum256(h.buffer)
+		return digest[:], crypto.SHA256, nil
 	}
 	if signatureAndHash.signature == signatureECDSA {
 		digest := h.server.Sum(nil)
@@ -321,3 +343,23 @@
 	digest = h.server.Sum(digest)
 	return digest, crypto.MD5SHA1, nil
 }
+
+// hashForChannelID returns the hash to be signed for TLS Channel
+// ID. If a resumption, resumeHash has the previous handshake
+// hash. Otherwise, it is nil.
+func (h finishedHash) hashForChannelID(resumeHash []byte) []byte {
+	hash := sha256.New()
+	hash.Write(channelIDLabel)
+	if resumeHash != nil {
+		hash.Write(channelIDResumeLabel)
+		hash.Write(resumeHash)
+	}
+	hash.Write(h.server.Sum(nil))
+	return hash.Sum(nil)
+}
+
+// discardHandshakeBuffer is called when there is no more need to
+// buffer the entirety of the handshake messages.
+func (h *finishedHash) discardHandshakeBuffer() {
+	h.buffer = nil
+}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 4a5b762..323f43f 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -2,7 +2,11 @@
 
 import (
 	"bytes"
+	"crypto/ecdsa"
+	"crypto/elliptic"
 	"crypto/x509"
+	"encoding/base64"
+	"encoding/pem"
 	"flag"
 	"fmt"
 	"io"
@@ -25,11 +29,14 @@
 )
 
 const (
-	rsaKeyFile   = "key.pem"
-	ecdsaKeyFile = "ecdsa_key.pem"
+	rsaKeyFile       = "key.pem"
+	ecdsaKeyFile     = "ecdsa_key.pem"
+	channelIDKeyFile = "channel_id_key.pem"
 )
 
 var rsaCertificate, ecdsaCertificate Certificate
+var channelIDKey *ecdsa.PrivateKey
+var channelIDBytes []byte
 
 func initCertificates() {
 	var err error
@@ -42,6 +49,26 @@
 	if err != nil {
 		panic(err)
 	}
+
+	channelIDPEMBlock, err := ioutil.ReadFile(channelIDKeyFile)
+	if err != nil {
+		panic(err)
+	}
+	channelIDDERBlock, _ := pem.Decode(channelIDPEMBlock)
+	if channelIDDERBlock.Type != "EC PRIVATE KEY" {
+		panic("bad key type")
+	}
+	channelIDKey, err = x509.ParseECPrivateKey(channelIDDERBlock.Bytes)
+	if err != nil {
+		panic(err)
+	}
+	if channelIDKey.Curve != elliptic.P256() {
+		panic("bad curve")
+	}
+
+	channelIDBytes = make([]byte, 64)
+	writeIntPadded(channelIDBytes[:32], channelIDKey.X)
+	writeIntPadded(channelIDBytes[32:], channelIDKey.Y)
 }
 
 var certificateOnce sync.Once
@@ -70,6 +97,11 @@
 	dtls
 )
 
+const (
+	alpn = 1
+	npn  = 2
+)
+
 type testCase struct {
 	testType      testType
 	protocol      protocol
@@ -83,6 +115,18 @@
 	// expectedVersion, if non-zero, specifies the TLS version that must be
 	// negotiated.
 	expectedVersion uint16
+	// expectedResumeVersion, if non-zero, specifies the TLS version that
+	// must be negotiated on resumption. If zero, expectedVersion is used.
+	expectedResumeVersion uint16
+	// expectChannelID controls whether the connection should have
+	// negotiated a Channel ID with channelIDKey.
+	expectChannelID bool
+	// expectedNextProto controls whether the connection should
+	// negotiate a next protocol via NPN or ALPN.
+	expectedNextProto string
+	// expectedNextProtoType, if non-zero, is the expected next
+	// protocol negotiation mechanism.
+	expectedNextProtoType int
 	// messageLen is the length, in bytes, of the test message that will be
 	// sent.
 	messageLen int
@@ -91,11 +135,19 @@
 	// keyFile is the path to the private key to use for the server.
 	keyFile string
 	// resumeSession controls whether a second connection should be tested
-	// which resumes the first session.
+	// which attempts to resume the first session.
 	resumeSession bool
+	// resumeConfig, if not nil, points to a Config to be used on
+	// resumption. SessionTicketKey and ClientSessionCache are copied from
+	// the initial connection's config. If nil, the initial connection's
+	// config is used.
+	resumeConfig *Config
 	// sendPrefix sends a prefix on the socket before actually performing a
 	// handshake.
 	sendPrefix string
+	// shimWritesFirst controls whether the shim sends an initial "hello"
+	// message before doing a roundtrip with the runner.
+	shimWritesFirst bool
 	// flags, if not empty, contains a list of command-line flags that will
 	// be passed to the shim program.
 	flags []string
@@ -160,7 +212,7 @@
 		expectedLocalError: "no fallback SCSV found",
 	},
 	{
-		name: "FallbackSCSV",
+		name: "SendFallbackSCSV",
 		config: Config{
 			Bugs: ProtocolBugs{
 				FailIfNotFallbackSCSV: true,
@@ -169,36 +221,6 @@
 		flags: []string{"-fallback-scsv"},
 	},
 	{
-		testType: serverTest,
-		name:     "ServerNameExtension",
-		config: Config{
-			ServerName: "example.com",
-		},
-		flags: []string{"-expect-server-name", "example.com"},
-	},
-	{
-		testType: clientTest,
-		name:     "DuplicateExtensionClient",
-		config: Config{
-			Bugs: ProtocolBugs{
-				DuplicateExtension: true,
-			},
-		},
-		shouldFail:         true,
-		expectedLocalError: "remote error: error decoding message",
-	},
-	{
-		testType: serverTest,
-		name:     "DuplicateExtensionServer",
-		config: Config{
-			Bugs: ProtocolBugs{
-				DuplicateExtension: true,
-			},
-		},
-		shouldFail:         true,
-		expectedLocalError: "remote error: error decoding message",
-	},
-	{
 		name: "ClientCertificateTypes",
 		config: Config{
 			ClientAuth: RequestClientCert,
@@ -208,11 +230,14 @@
 				CertTypeECDSASign,
 			},
 		},
-		flags: []string{"-expect-certificate-types", string([]byte{
-			CertTypeDSSSign,
-			CertTypeRSASign,
-			CertTypeECDSASign,
-		})},
+		flags: []string{
+			"-expect-certificate-types",
+			base64.StdEncoding.EncodeToString([]byte{
+				CertTypeDSSSign,
+				CertTypeRSASign,
+				CertTypeECDSASign,
+			}),
+		},
 	},
 	{
 		name: "NoClientCertificate",
@@ -447,9 +472,21 @@
 		shouldFail:    true,
 		expectedError: ":HTTPS_PROXY_REQUEST:",
 	},
+	{
+		name: "SkipCipherVersionCheck",
+		config: Config{
+			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+			MaxVersion:   VersionTLS11,
+			Bugs: ProtocolBugs{
+				SkipCipherVersionCheck: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_CIPHER_RETURNED:",
+	},
 }
 
-func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) error {
+func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
 	if test.protocol == dtls {
 		conn = newPacketAdaptor(conn)
 	}
@@ -480,8 +517,50 @@
 		return err
 	}
 
-	if vers := tlsConn.ConnectionState().Version; test.expectedVersion != 0 && vers != test.expectedVersion {
-		return fmt.Errorf("got version %x, expected %x", vers, test.expectedVersion)
+	// TODO(davidben): move all per-connection expectations into a dedicated
+	// expectations struct that can be specified separately for the two
+	// legs.
+	expectedVersion := test.expectedVersion
+	if isResume && test.expectedResumeVersion != 0 {
+		expectedVersion = test.expectedResumeVersion
+	}
+	if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion {
+		return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
+	}
+
+	if test.expectChannelID {
+		channelID := tlsConn.ConnectionState().ChannelID
+		if channelID == nil {
+			return fmt.Errorf("no channel ID negotiated")
+		}
+		if channelID.Curve != channelIDKey.Curve ||
+			channelIDKey.X.Cmp(channelIDKey.X) != 0 ||
+			channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
+			return fmt.Errorf("incorrect channel ID")
+		}
+	}
+
+	if expected := test.expectedNextProto; expected != "" {
+		if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected {
+			return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
+		}
+	}
+
+	if test.expectedNextProtoType != 0 {
+		if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN {
+			return fmt.Errorf("next proto type mismatch")
+		}
+	}
+
+	if test.shimWritesFirst {
+		var buf [5]byte
+		_, err := io.ReadFull(tlsConn, buf[:])
+		if err != nil {
+			return err
+		}
+		if string(buf[:]) != "hello" {
+			return fmt.Errorf("bad initial message")
+		}
 	}
 
 	if messageLen < 0 {
@@ -601,6 +680,10 @@
 		flags = append(flags, "-resume")
 	}
 
+	if test.shimWritesFirst {
+		flags = append(flags, "-shim-writes-first")
+	}
+
 	flags = append(flags, test.flags...)
 
 	var shim *exec.Cmd
@@ -630,12 +713,25 @@
 		}
 	}
 
-	err := doExchange(test, &config, conn, test.messageLen)
+	err := doExchange(test, &config, conn, test.messageLen,
+		false /* not a resumption */)
 	conn.Close()
 	if err == nil && test.resumeSession {
-		err = doExchange(test, &config, connResume, test.messageLen)
-		connResume.Close()
+		var resumeConfig Config
+		if test.resumeConfig != nil {
+			resumeConfig = *test.resumeConfig
+			if len(resumeConfig.Certificates) == 0 {
+				resumeConfig.Certificates = []Certificate{getRSACertificate()}
+			}
+			resumeConfig.SessionTicketKey = config.SessionTicketKey
+			resumeConfig.ClientSessionCache = config.ClientSessionCache
+		} else {
+			resumeConfig = config
+		}
+		err = doExchange(test, &resumeConfig, connResume, test.messageLen,
+			true /* resumption */)
 	}
+	connResume.Close()
 
 	childErr := shim.Wait()
 
@@ -697,25 +793,40 @@
 	{"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
 	{"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
 	{"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
+	{"AES128-SHA256", TLS_RSA_WITH_AES_128_CBC_SHA256},
 	{"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
 	{"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
+	{"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
 	{"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
 	{"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
+	{"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
 	{"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
 	{"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
+	{"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
 	{"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
 	{"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
+	{"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
+	{"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
 	{"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-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},
 	{"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
 	{"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},
 	{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
 	{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
 }
 
+func isTLS12Only(suiteName string) bool {
+	return strings.HasSuffix(suiteName, "-GCM") ||
+		strings.HasSuffix(suiteName, "-SHA256") ||
+		strings.HasSuffix(suiteName, "-SHA384")
+}
+
 func addCipherSuiteTests() {
 	for _, suite := range testCipherSuites {
 		var cert Certificate
@@ -732,7 +843,7 @@
 		}
 
 		for _, ver := range tlsVersions {
-			if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
+			if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
 				continue
 			}
 
@@ -902,29 +1013,14 @@
 	certPool.AddCert(cert)
 
 	for _, ver := range tlsVersions {
-		if ver.version == VersionSSL30 {
-			// TODO(davidben): The Go implementation does not
-			// correctly compute CertificateVerify hashes for SSLv3.
-			continue
-		}
-
-		var cipherSuites []uint16
-		if ver.version >= VersionTLS12 {
-			// Pick a SHA-256 cipher suite. The Go implementation
-			// does not correctly handle client auth with a SHA-384
-			// cipher suite.
-			cipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
-		}
-
 		testCases = append(testCases, testCase{
 			testType: clientTest,
 			name:     ver.name + "-Client-ClientAuth-RSA",
 			config: Config{
-				MinVersion:   ver.version,
-				MaxVersion:   ver.version,
-				CipherSuites: cipherSuites,
-				ClientAuth:   RequireAnyClientCert,
-				ClientCAs:    certPool,
+				MinVersion: ver.version,
+				MaxVersion: ver.version,
+				ClientAuth: RequireAnyClientCert,
+				ClientCAs:  certPool,
 			},
 			flags: []string{
 				"-cert-file", rsaCertificateFile,
@@ -932,36 +1028,41 @@
 			},
 		})
 		testCases = append(testCases, testCase{
-			testType: clientTest,
-			name:     ver.name + "-Client-ClientAuth-ECDSA",
-			config: Config{
-				MinVersion:   ver.version,
-				MaxVersion:   ver.version,
-				CipherSuites: cipherSuites,
-				ClientAuth:   RequireAnyClientCert,
-				ClientCAs:    certPool,
-			},
-			flags: []string{
-				"-cert-file", ecdsaCertificateFile,
-				"-key-file", ecdsaKeyFile,
-			},
-		})
-		testCases = append(testCases, testCase{
 			testType: serverTest,
 			name:     ver.name + "-Server-ClientAuth-RSA",
 			config: Config{
+				MinVersion:   ver.version,
+				MaxVersion:   ver.version,
 				Certificates: []Certificate{rsaCertificate},
 			},
 			flags: []string{"-require-any-client-certificate"},
 		})
-		testCases = append(testCases, testCase{
-			testType: serverTest,
-			name:     ver.name + "-Server-ClientAuth-ECDSA",
-			config: Config{
-				Certificates: []Certificate{ecdsaCertificate},
-			},
-			flags: []string{"-require-any-client-certificate"},
-		})
+		if ver.version != VersionSSL30 {
+			testCases = append(testCases, testCase{
+				testType: serverTest,
+				name:     ver.name + "-Server-ClientAuth-ECDSA",
+				config: Config{
+					MinVersion:   ver.version,
+					MaxVersion:   ver.version,
+					Certificates: []Certificate{ecdsaCertificate},
+				},
+				flags: []string{"-require-any-client-certificate"},
+			})
+			testCases = append(testCases, testCase{
+				testType: clientTest,
+				name:     ver.name + "-Client-ClientAuth-ECDSA",
+				config: Config{
+					MinVersion: ver.version,
+					MaxVersion: ver.version,
+					ClientAuth: RequireAnyClientCert,
+					ClientCAs:  certPool,
+				},
+				flags: []string{
+					"-cert-file", ecdsaCertificateFile,
+					"-key-file", ecdsaKeyFile,
+				},
+			})
+		}
 	}
 }
 
@@ -1029,8 +1130,7 @@
 		testType: clientTest,
 		name:     "ClientAuth-Client" + suffix,
 		config: Config{
-			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
-			ClientAuth:   RequireAnyClientCert,
+			ClientAuth: RequireAnyClientCert,
 			Bugs: ProtocolBugs{
 				MaxHandshakeRecordLength: maxHandshakeRecordLength,
 			},
@@ -1080,13 +1180,14 @@
 			protocol: protocol,
 			name:     "NPN-Client" + suffix,
 			config: Config{
-				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
-				NextProtos:   []string{"foo"},
+				NextProtos: []string{"foo"},
 				Bugs: ProtocolBugs{
 					MaxHandshakeRecordLength: maxHandshakeRecordLength,
 				},
 			},
-			flags: append(flags, "-select-next-proto", "foo"),
+			flags:                 append(flags, "-select-next-proto", "foo"),
+			expectedNextProto:     "foo",
+			expectedNextProtoType: npn,
 		})
 		testCases = append(testCases, testCase{
 			protocol: protocol,
@@ -1101,6 +1202,8 @@
 			flags: append(flags,
 				"-advertise-npn", "\x03foo\x03bar\x03baz",
 				"-expect-next-proto", "bar"),
+			expectedNextProto:     "bar",
+			expectedNextProtoType: npn,
 		})
 
 		// Client does False Start and negotiates NPN.
@@ -1111,13 +1214,34 @@
 				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 				NextProtos:   []string{"foo"},
 				Bugs: ProtocolBugs{
+					ExpectFalseStart:         true,
 					MaxHandshakeRecordLength: maxHandshakeRecordLength,
 				},
 			},
 			flags: append(flags,
 				"-false-start",
 				"-select-next-proto", "foo"),
-			resumeSession: true,
+			shimWritesFirst: true,
+			resumeSession:   true,
+		})
+
+		// Client does False Start and negotiates ALPN.
+		testCases = append(testCases, testCase{
+			protocol: protocol,
+			name:     "FalseStart-ALPN" + suffix,
+			config: Config{
+				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+				NextProtos:   []string{"foo"},
+				Bugs: ProtocolBugs{
+					ExpectFalseStart:         true,
+					MaxHandshakeRecordLength: maxHandshakeRecordLength,
+				},
+			},
+			flags: append(flags,
+				"-false-start",
+				"-advertise-alpn", "\x03foo"),
+			shimWritesFirst: true,
+			resumeSession:   true,
 		})
 
 		// False Start without session tickets.
@@ -1127,14 +1251,19 @@
 				CipherSuites:           []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
 				NextProtos:             []string{"foo"},
 				SessionTicketsDisabled: true,
+				Bugs: ProtocolBugs{
+					ExpectFalseStart:         true,
+					MaxHandshakeRecordLength: maxHandshakeRecordLength,
+				},
 			},
-			flags: []string{
+			flags: append(flags,
 				"-false-start",
 				"-select-next-proto", "foo",
-			},
+			),
+			shimWritesFirst: true,
 		})
 
-		// Client sends a V2ClientHello.
+		// Server parses a V2ClientHello.
 		testCases = append(testCases, testCase{
 			protocol: protocol,
 			testType: serverTest,
@@ -1151,6 +1280,42 @@
 			},
 			flags: flags,
 		})
+
+		// Client sends a Channel ID.
+		testCases = append(testCases, testCase{
+			protocol: protocol,
+			name:     "ChannelID-Client" + suffix,
+			config: Config{
+				RequestChannelID: true,
+				Bugs: ProtocolBugs{
+					MaxHandshakeRecordLength: maxHandshakeRecordLength,
+				},
+			},
+			flags: append(flags,
+				"-send-channel-id", channelIDKeyFile,
+			),
+			resumeSession:   true,
+			expectChannelID: true,
+		})
+
+		// Server accepts a Channel ID.
+		testCases = append(testCases, testCase{
+			protocol: protocol,
+			testType: serverTest,
+			name:     "ChannelID-Server" + suffix,
+			config: Config{
+				ChannelID: channelIDKey,
+				Bugs: ProtocolBugs{
+					MaxHandshakeRecordLength: maxHandshakeRecordLength,
+				},
+			},
+			flags: append(flags,
+				"-expect-channel-id",
+				base64.StdEncoding.EncodeToString(channelIDBytes),
+			),
+			resumeSession:   true,
+			expectChannelID: true,
+		})
 	} else {
 		testCases = append(testCases, testCase{
 			protocol: protocol,
@@ -1216,6 +1381,231 @@
 	}
 }
 
+func addD5BugTests() {
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "D5Bug-NoQuirk-Reject",
+		config: Config{
+			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				SSL3RSAKeyExchange: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG:",
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "D5Bug-Quirk-Normal",
+		config: Config{
+			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+		},
+		flags: []string{"-tls-d5-bug"},
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "D5Bug-Quirk-Bug",
+		config: Config{
+			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				SSL3RSAKeyExchange: true,
+			},
+		},
+		flags: []string{"-tls-d5-bug"},
+	})
+}
+
+func addExtensionTests() {
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "DuplicateExtensionClient",
+		config: Config{
+			Bugs: ProtocolBugs{
+				DuplicateExtension: true,
+			},
+		},
+		shouldFail:         true,
+		expectedLocalError: "remote error: error decoding message",
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "DuplicateExtensionServer",
+		config: Config{
+			Bugs: ProtocolBugs{
+				DuplicateExtension: true,
+			},
+		},
+		shouldFail:         true,
+		expectedLocalError: "remote error: error decoding message",
+	})
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "ServerNameExtensionClient",
+		config: Config{
+			Bugs: ProtocolBugs{
+				ExpectServerName: "example.com",
+			},
+		},
+		flags: []string{"-host-name", "example.com"},
+	})
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "ServerNameExtensionClient",
+		config: Config{
+			Bugs: ProtocolBugs{
+				ExpectServerName: "mismatch.com",
+			},
+		},
+		flags:              []string{"-host-name", "example.com"},
+		shouldFail:         true,
+		expectedLocalError: "tls: unexpected server name",
+	})
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "ServerNameExtensionClient",
+		config: Config{
+			Bugs: ProtocolBugs{
+				ExpectServerName: "missing.com",
+			},
+		},
+		shouldFail:         true,
+		expectedLocalError: "tls: unexpected server name",
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ServerNameExtensionServer",
+		config: Config{
+			ServerName: "example.com",
+		},
+		flags:         []string{"-expect-server-name", "example.com"},
+		resumeSession: true,
+	})
+	testCases = append(testCases, testCase{
+		testType: clientTest,
+		name:     "ALPNClient",
+		config: Config{
+			NextProtos: []string{"foo"},
+		},
+		flags: []string{
+			"-advertise-alpn", "\x03foo\x03bar\x03baz",
+			"-expect-alpn", "foo",
+		},
+		expectedNextProto:     "foo",
+		expectedNextProtoType: alpn,
+		resumeSession:         true,
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ALPNServer",
+		config: Config{
+			NextProtos: []string{"foo", "bar", "baz"},
+		},
+		flags: []string{
+			"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
+			"-select-alpn", "foo",
+		},
+		expectedNextProto:     "foo",
+		expectedNextProtoType: alpn,
+		resumeSession:         true,
+	})
+	// Test that the server prefers ALPN over NPN.
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ALPNServer-Preferred",
+		config: Config{
+			NextProtos: []string{"foo", "bar", "baz"},
+		},
+		flags: []string{
+			"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
+			"-select-alpn", "foo",
+			"-advertise-npn", "\x03foo\x03bar\x03baz",
+		},
+		expectedNextProto:     "foo",
+		expectedNextProtoType: alpn,
+		resumeSession:         true,
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "ALPNServer-Preferred-Swapped",
+		config: Config{
+			NextProtos: []string{"foo", "bar", "baz"},
+			Bugs: ProtocolBugs{
+				SwapNPNAndALPN: true,
+			},
+		},
+		flags: []string{
+			"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
+			"-select-alpn", "foo",
+			"-advertise-npn", "\x03foo\x03bar\x03baz",
+		},
+		expectedNextProto:     "foo",
+		expectedNextProtoType: alpn,
+		resumeSession:         true,
+	})
+}
+
+func addResumptionVersionTests() {
+	// TODO(davidben): Once DTLS 1.2 is working, test that as well.
+	for _, sessionVers := range tlsVersions {
+		// TODO(davidben): SSLv3 is omitted here because runner does not
+		// support resumption with session IDs.
+		if sessionVers.version == VersionSSL30 {
+			continue
+		}
+		for _, resumeVers := range tlsVersions {
+			if resumeVers.version == VersionSSL30 {
+				continue
+			}
+			suffix := "-" + sessionVers.name + "-" + resumeVers.name
+
+			// TODO(davidben): Write equivalent tests for the server
+			// and clean up the server's logic. This requires being
+			// able to give the shim a different set of SSL_OP_NO_*
+			// flags between the initial connection and the
+			// resume. Perhaps resumption should be tested by
+			// serializing the SSL_SESSION and starting a second
+			// shim.
+			testCases = append(testCases, testCase{
+				name:          "Resume-Client" + suffix,
+				resumeSession: true,
+				config: Config{
+					MaxVersion:   sessionVers.version,
+					CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+					Bugs: ProtocolBugs{
+						AllowSessionVersionMismatch: true,
+					},
+				},
+				expectedVersion: sessionVers.version,
+				resumeConfig: &Config{
+					MaxVersion:   resumeVers.version,
+					CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+					Bugs: ProtocolBugs{
+						AllowSessionVersionMismatch: true,
+					},
+				},
+				expectedResumeVersion: resumeVers.version,
+			})
+
+			testCases = append(testCases, testCase{
+				name:          "Resume-Client-NoResume" + suffix,
+				flags:         []string{"-expect-session-miss"},
+				resumeSession: true,
+				config: Config{
+					MaxVersion:   sessionVers.version,
+					CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+				},
+				expectedVersion: sessionVers.version,
+				resumeConfig: &Config{
+					MaxVersion:             resumeVers.version,
+					CipherSuites:           []uint16{TLS_RSA_WITH_RC4_128_SHA},
+					SessionTicketsDisabled: true,
+				},
+				expectedResumeVersion: resumeVers.version,
+			})
+		}
+	}
+}
+
 func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
@@ -1268,6 +1658,9 @@
 	addCBCSplittingTests()
 	addClientAuthTests()
 	addVersionNegotiationTests()
+	addD5BugTests()
+	addExtensionTests()
+	addResumptionVersionTests()
 	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 519543b..74791d6 100644
--- a/ssl/test/runner/ticket.go
+++ b/ssl/test/runner/ticket.go
@@ -18,10 +18,11 @@
 // 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
-	certificates [][]byte
+	vers          uint16
+	cipherSuite   uint16
+	masterSecret  []byte
+	handshakeHash []byte
+	certificates  [][]byte
 }
 
 func (s *sessionState) equal(i interface{}) bool {
@@ -32,7 +33,8 @@
 
 	if s.vers != s1.vers ||
 		s.cipherSuite != s1.cipherSuite ||
-		!bytes.Equal(s.masterSecret, s1.masterSecret) {
+		!bytes.Equal(s.masterSecret, s1.masterSecret) ||
+		!bytes.Equal(s.handshakeHash, s1.handshakeHash) {
 		return false
 	}
 
@@ -50,7 +52,7 @@
 }
 
 func (s *sessionState) marshal() []byte {
-	length := 2 + 2 + 2 + len(s.masterSecret) + 2
+	length := 2 + 2 + 2 + len(s.masterSecret) + 2 + len(s.handshakeHash) + 2
 	for _, cert := range s.certificates {
 		length += 4 + len(cert)
 	}
@@ -67,6 +69,12 @@
 	copy(x, s.masterSecret)
 	x = x[len(s.masterSecret):]
 
+	x[0] = byte(len(s.handshakeHash) >> 8)
+	x[1] = byte(len(s.handshakeHash))
+	x = x[2:]
+	copy(x, s.handshakeHash)
+	x = x[len(s.handshakeHash):]
+
 	x[0] = byte(len(s.certificates) >> 8)
 	x[1] = byte(len(s.certificates))
 	x = x[2:]
@@ -103,6 +111,19 @@
 		return false
 	}
 
+	handshakeHashLen := int(data[0])<<8 | int(data[1])
+	data = data[2:]
+	if len(data) < handshakeHashLen {
+		return false
+	}
+
+	s.handshakeHash = data[:handshakeHashLen]
+	data = data[handshakeHashLen:]
+
+	if len(data) < 2 {
+		return false
+	}
+
 	numCerts := int(data[0])<<8 | int(data[1])
 	data = data[2:]
 
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 9716227..70543cc 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -16,6 +16,9 @@
 
 #include <string.h>
 
+#include <memory>
+
+#include <openssl/base64.h>
 
 namespace {
 
@@ -50,25 +53,37 @@
   { "-no-tls1", &TestConfig::no_tls1 },
   { "-no-ssl3", &TestConfig::no_ssl3 },
   { "-cookie-exchange", &TestConfig::cookie_exchange },
+  { "-shim-writes-first", &TestConfig::shim_writes_first },
+  { "-tls-d5-bug", &TestConfig::tls_d5_bug },
+  { "-expect-session-miss", &TestConfig::expect_session_miss },
 };
 
 const size_t kNumBoolFlags = sizeof(kBoolFlags) / sizeof(kBoolFlags[0]);
 
-// TODO(davidben): Some of these should be in a new kBase64Flags to allow NUL
-// bytes.
 const StringFlag kStringFlags[] = {
   { "-key-file", &TestConfig::key_file },
   { "-cert-file", &TestConfig::cert_file },
   { "-expect-server-name", &TestConfig::expected_server_name },
-  // Conveniently, 00 is not a certificate type.
-  { "-expect-certificate-types", &TestConfig::expected_certificate_types },
   { "-advertise-npn", &TestConfig::advertise_npn },
   { "-expect-next-proto", &TestConfig::expected_next_proto },
   { "-select-next-proto", &TestConfig::select_next_proto },
+  { "-send-channel-id", &TestConfig::send_channel_id },
+  { "-host-name", &TestConfig::host_name },
+  { "-advertise-alpn", &TestConfig::advertise_alpn },
+  { "-expect-alpn", &TestConfig::expected_alpn },
+  { "-expect-advertised-alpn", &TestConfig::expected_advertised_alpn },
+  { "-select-alpn", &TestConfig::select_alpn },
 };
 
 const size_t kNumStringFlags = sizeof(kStringFlags) / sizeof(kStringFlags[0]);
 
+const StringFlag kBase64Flags[] = {
+  { "-expect-certificate-types", &TestConfig::expected_certificate_types },
+  { "-expect-channel-id", &TestConfig::expected_channel_id },
+};
+
+const size_t kNumBase64Flags = sizeof(kBase64Flags) / sizeof(kBase64Flags[0]);
+
 }  // namespace
 
 TestConfig::TestConfig()
@@ -86,7 +101,10 @@
       no_tls11(false),
       no_tls1(false),
       no_ssl3(false),
-      cookie_exchange(false) {
+      cookie_exchange(false),
+      shim_writes_first(false),
+      tls_d5_bug(false),
+      expect_session_miss(false) {
 }
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config) {
@@ -117,6 +135,32 @@
       continue;
     }
 
+    for (j = 0; j < kNumBase64Flags; j++) {
+      if (strcmp(argv[i], kBase64Flags[j].flag) == 0) {
+        break;
+      }
+    }
+    if (j < kNumBase64Flags) {
+      i++;
+      if (i >= argc) {
+        fprintf(stderr, "Missing parameter\n");
+        return false;
+      }
+      size_t len;
+      if (!EVP_DecodedLength(&len, strlen(argv[i]))) {
+        fprintf(stderr, "Invalid base64: %s\n", argv[i]);
+      }
+      std::unique_ptr<uint8_t[]> decoded(new uint8_t[len]);
+      if (!EVP_DecodeBase64(decoded.get(), &len, len,
+                            reinterpret_cast<const uint8_t *>(argv[i]),
+                            strlen(argv[i]))) {
+        fprintf(stderr, "Invalid base64: %s\n", argv[i]);
+      }
+      out_config->*(kBase64Flags[j].member) = std::string(
+          reinterpret_cast<const char *>(decoded.get()), len);
+      continue;
+    }
+
     fprintf(stderr, "Unknown argument: %s\n", argv[i]);
     return false;
   }
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index 34d720e..acce504 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -43,6 +43,16 @@
   bool no_tls1;
   bool no_ssl3;
   bool cookie_exchange;
+  std::string expected_channel_id;
+  std::string send_channel_id;
+  bool shim_writes_first;
+  bool tls_d5_bug;
+  std::string host_name;
+  std::string advertise_alpn;
+  std::string expected_alpn;
+  std::string expected_advertised_alpn;
+  std::string select_alpn;
+  bool expect_session_miss;
 };
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config);
diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt
index 4b9c03b..e513c8b 100644
--- a/tool/CMakeLists.txt
+++ b/tool/CMakeLists.txt
@@ -6,6 +6,7 @@
 	args.cc
 	client.cc
 	const.cc
+	pkcs12.cc
 	speed.cc
 	tool.cc
 )
diff --git a/tool/client.cc b/tool/client.cc
index 5acc8b1..8aef559 100644
--- a/tool/client.cc
+++ b/tool/client.cc
@@ -18,6 +18,7 @@
 #include <vector>
 
 #include <errno.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 
@@ -253,6 +254,16 @@
 
   SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
 
+  const char *keylog_file = getenv("SSLKEYLOGFILE");
+  if (keylog_file) {
+    BIO *keylog_bio = BIO_new_file(keylog_file, "a");
+    if (!keylog_bio) {
+      ERR_print_errors_cb(PrintErrorCallback, stderr);
+      return false;
+    }
+    SSL_CTX_set_keylog_bio(ctx, keylog_bio);
+  }
+
   int sock = -1;
   if (!Connect(&sock, args_map["-connect"])) {
     return false;
diff --git a/tool/pkcs12.cc b/tool/pkcs12.cc
new file mode 100644
index 0000000..d35ba0b
--- /dev/null
+++ b/tool/pkcs12.cc
@@ -0,0 +1,125 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs8.h>
+#include <openssl/stack.h>
+
+#include "internal.h"
+
+
+static const struct argument kArguments[] = {
+    {
+     "-dump", false, "Dump the key and contents of the given file to stdout",
+    },
+    {
+     "", false, "",
+    },
+};
+
+bool DoPKCS12(const std::vector<std::string> &args) {
+  std::map<std::string, std::string> args_map;
+
+  if (!ParseKeyValueArguments(&args_map, args, kArguments) ||
+      args_map["-dump"].empty()) {
+    PrintUsage(kArguments);
+    return false;
+  }
+
+  int fd = open(args_map["-dump"].c_str(), O_RDONLY);
+  if (fd < 0) {
+    perror("open");
+    return false;
+  }
+
+  struct stat st;
+  if (fstat(fd, &st)) {
+    perror("fstat");
+    close(fd);
+    return false;
+  }
+  const size_t size = st.st_size;
+
+  std::unique_ptr<uint8_t[]> contents(new uint8_t[size]);
+  ssize_t n;
+  size_t off = 0;
+  do {
+    n = read(fd, &contents[off], size - off);
+    if (n >= 0) {
+      off += static_cast<size_t>(n);
+    }
+  } while ((n > 0 && off < size) || (n == -1 && errno == EINTR));
+
+  if (off != size) {
+    perror("read");
+    close(fd);
+    return false;
+  }
+
+  close(fd);
+
+  printf("Enter password: ");
+  fflush(stdout);
+
+  char password[256];
+  off = 0;
+  do {
+    n = read(0, &password[off], sizeof(password) - 1 - off);
+    if (n >= 0) {
+      off += static_cast<size_t>(n);
+    }
+  } while ((n > 0 && memchr(password, '\n', off) == NULL &&
+            off < sizeof(password) - 1) ||
+           (n == -1 && errno == EINTR));
+
+  char *newline = reinterpret_cast<char*>(memchr(password, '\n', off));
+  if (newline == NULL) {
+    return false;
+  }
+  *newline = 0;
+
+  CBS pkcs12;
+  CBS_init(&pkcs12, contents.get(), size);
+
+  EVP_PKEY *key;
+  STACK_OF(X509) *certs = sk_X509_new_null();
+
+  if (!PKCS12_get_key_and_certs(&key, certs, &pkcs12, password)) {
+    fprintf(stderr, "Failed to parse PKCS#12 data:\n");
+    BIO_print_errors_fp(stderr);
+    return false;
+  }
+
+  PEM_write_PrivateKey(stdout, key, NULL, NULL, 0, NULL, NULL);
+  EVP_PKEY_free(key);
+
+  for (size_t i = 0; i < sk_X509_num(certs); i++) {
+    PEM_write_X509(stdout, sk_X509_value(certs, i));
+  }
+  sk_X509_pop_free(certs, X509_free);
+
+  return true;
+}
diff --git a/tool/tool.cc b/tool/tool.cc
index b8aa911..a0866d7 100644
--- a/tool/tool.cc
+++ b/tool/tool.cc
@@ -19,11 +19,12 @@
 #include <openssl/ssl.h>
 
 
-bool Speed(const std::vector<std::string> &args);
 bool Client(const std::vector<std::string> &args);
+bool DoPKCS12(const std::vector<std::string> &args);
+bool Speed(const std::vector<std::string> &args);
 
 static void usage(const char *name) {
-  printf("Usage: %s [speed|client]\n", name);
+  printf("Usage: %s [speed|client|pkcs12]\n", name);
 }
 
 int main(int argc, char **argv) {
@@ -43,6 +44,8 @@
     return !Speed(args);
   } else if (tool == "s_client" || tool == "client") {
     return !Client(args);
+  } else if (tool == "pkcs12") {
+    return !DoPKCS12(args);
   } else {
     usage(argv[0]);
     return 1;
diff --git a/util/all_tests.sh b/util/all_tests.sh
index 178c30b..e4f3126 100644
--- a/util/all_tests.sh
+++ b/util/all_tests.sh
@@ -20,32 +20,34 @@
 fi
 
 TESTS="
-./crypto/cipher/aead_test aes-128-gcm $SRC/crypto/cipher/aes_128_gcm_tests.txt
-./crypto/cipher/aead_test aes-256-gcm $SRC/crypto/cipher/aes_256_gcm_tests.txt
-./crypto/cipher/aead_test chacha20-poly1305 $SRC/crypto/cipher/chacha20_poly1305_tests.txt
-./crypto/cipher/aead_test rc4-md5 $SRC/crypto/cipher/rc4_md5_tests.txt
-./crypto/cipher/aead_test aes-128-key-wrap $SRC/crypto/cipher/aes_128_key_wrap_tests.txt
-./crypto/cipher/aead_test aes-256-key-wrap $SRC/crypto/cipher/aes_256_key_wrap_tests.txt
 ./crypto/base64/base64_test
 ./crypto/bio/bio_test
 ./crypto/bn/bn_test
+./crypto/bytestring/bytestring_test
+./crypto/cipher/aead_test aes-128-gcm $SRC/crypto/cipher/aes_128_gcm_tests.txt
+./crypto/cipher/aead_test aes-128-key-wrap $SRC/crypto/cipher/aes_128_key_wrap_tests.txt
+./crypto/cipher/aead_test aes-256-gcm $SRC/crypto/cipher/aes_256_gcm_tests.txt
+./crypto/cipher/aead_test aes-256-key-wrap $SRC/crypto/cipher/aes_256_key_wrap_tests.txt
+./crypto/cipher/aead_test chacha20-poly1305 $SRC/crypto/cipher/chacha20_poly1305_tests.txt
+./crypto/cipher/aead_test rc4-md5 $SRC/crypto/cipher/rc4_md5_tests.txt
 ./crypto/cipher/cipher_test $SRC/crypto/cipher/cipher_test.txt
 ./crypto/dh/dh_test
 ./crypto/dsa/dsa_test
-./crypto/err/err_test
 ./crypto/ec/example_mul
 ./crypto/ecdsa/ecdsa_test
+./crypto/err/err_test
 ./crypto/evp/example_sign
 ./crypto/hmac/hmac_test
 ./crypto/lhash/lhash_test
 ./crypto/md5/md5_test
 ./crypto/modes/gcm_test
+./crypto/pkcs8/pkcs12_test
 ./crypto/rsa/rsa_test
 ./crypto/sha/sha1_test
+./crypto/x509/pkcs7_test
 ./crypto/x509v3/tab_test
 ./crypto/x509v3/v3name_test
-./crypto/bytestring/bytestring_test
-./crypto/x509/pkcs7_test
+./ssl/pqueue/pqueue_test
 ./ssl/ssl_test
 "
 
diff --git a/util/doc.config b/util/doc.config
index 7c0835d..4b5f3b1 100644
--- a/util/doc.config
+++ b/util/doc.config
@@ -3,45 +3,45 @@
   "Sections": [{
     "Name": "Low-level infrastructure",
     "Headers": [
-      "crypto/base64/base64.h",
-      "crypto/bio/bio.h",
-      "crypto/buf/buf.h",
-      "crypto/err/err.h",
-      "crypto/cpu.h",
-      "crypto/ex_data.h",
-      "crypto/lhash/lhash.h",
-      "crypto/mem.h",
-      "crypto/obj/obj.h",
-      "crypto/stack/stack.h",
-      "crypto/thread.h",
-      "crypto/time_support.h"
+      "include/openssl/base64.h",
+      "include/openssl/bio.h",
+      "include/openssl/buf.h",
+      "include/openssl/err.h",
+      "include/openssl/cpu.h",
+      "include/openssl/ex_data.h",
+      "include/openssl/lhash.h",
+      "include/openssl/mem.h",
+      "include/openssl/obj.h",
+      "include/openssl/stack.h",
+      "include/openssl/thread.h",
+      "include/openssl/time_support.h"
     ]
   },{
     "Name": "Low-level crypto primitives",
     "Headers": [
-      "crypto/aes/aes.h",
-      "crypto/bn/bn.h",
-      "crypto/des/des.h",
-      "crypto/dh/dh.h",
-      "crypto/dsa/dsa.h",
-      "crypto/ec/ec.h",
-      "crypto/ec/ec_key.h",
-      "crypto/ecdh/ecdh.h",
-      "crypto/ecdsa/ecdsa.h",
-      "crypto/engine/engine.h",
-      "crypto/hmac/hmac.h",
-      "crypto/md5/md5.h",
-      "crypto/modes/modes.h",
-      "crypto/rc4/rc4.h",
-      "crypto/rsa/rsa.h",
-      "crypto/sha/sha.h"
+      "include/openssl/aes.h",
+      "include/openssl/bn.h",
+      "include/openssl/des.h",
+      "include/openssl/dh.h",
+      "include/openssl/dsa.h",
+      "include/openssl/ec.h",
+      "include/openssl/ec_key.h",
+      "include/openssl/ecdh.h",
+      "include/openssl/ecdsa.h",
+      "include/openssl/engine.h",
+      "include/openssl/hmac.h",
+      "include/openssl/md5.h",
+      "include/openssl/modes.h",
+      "include/openssl/rc4.h",
+      "include/openssl/rsa.h",
+      "include/openssl/sha.h"
     ]
   },{
     "Name": "Crypto interfaces",
     "Headers": [
-      "crypto/digest/digest.h",
-      "crypto/cipher/cipher.h",
-      "crypto/evp/evp.h"
+      "include/openssl/digest.h",
+      "include/openssl/cipher.h",
+      "include/openssl/evp.h"
     ]
   }]
 }