Revert "Revert "external/boringssl: sync with upstream.""

This reverts commit a04d78d392463df4e69a64360c952ffa5abd22f7.

Underlying issue was fixed.

Change-Id: I49685b653d16e728eb38e79e02b2c33ddeefed88
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 6858cbb..3115279 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. ../include)
+include_directories(../include)
 
 if(APPLE)
   if (${ARCH} STREQUAL "x86")
@@ -57,7 +57,6 @@
   set(
     CRYPTO_ARCH_SOURCES
 
-    cpu-x86_64-asm.${ASM_EXT}
     cpu-intel.c
   )
 endif()
@@ -66,7 +65,6 @@
   set(
     CRYPTO_ARCH_SOURCES
 
-    cpu-x86-asm.${ASM_EXT}
     cpu-intel.c
   )
 endif()
@@ -230,6 +228,3 @@
 )
 
 target_link_libraries(refcount_test crypto)
-
-perlasm(cpu-x86_64-asm.${ASM_EXT} cpu-x86_64-asm.pl)
-perlasm(cpu-x86-asm.${ASM_EXT} cpu-x86-asm.pl)
diff --git a/src/crypto/aes/CMakeLists.txt b/src/crypto/aes/CMakeLists.txt
index 490f40a..c82d99a 100644
--- a/src/crypto/aes/CMakeLists.txt
+++ b/src/crypto/aes/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 if (${ARCH} STREQUAL "x86_64")
   set(
@@ -60,3 +60,12 @@
 perlasm(aes-armv4.${ASM_EXT} asm/aes-armv4.pl)
 perlasm(bsaes-armv7.${ASM_EXT} asm/bsaes-armv7.pl)
 perlasm(aesv8-armx.${ASM_EXT} asm/aesv8-armx.pl)
+
+add_executable(
+  aes_test
+
+  aes_test.cc
+  $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(aes_test crypto)
diff --git a/src/crypto/aes/aes_test.cc b/src/crypto/aes/aes_test.cc
new file mode 100644
index 0000000..e488d81
--- /dev/null
+++ b/src/crypto/aes/aes_test.cc
@@ -0,0 +1,102 @@
+/* Copyright (c) 2015, 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/aes.h>
+#include <openssl/crypto.h>
+
+
+static bool TestAES(const uint8_t *key, size_t key_len,
+                    const uint8_t plaintext[AES_BLOCK_SIZE],
+                    const uint8_t ciphertext[AES_BLOCK_SIZE]) {
+  AES_KEY aes_key;
+  if (AES_set_encrypt_key(key, key_len * 8, &aes_key) != 0) {
+    fprintf(stderr, "AES_set_encrypt_key failed\n");
+    return false;
+  }
+
+  // Test encryption.
+  uint8_t block[AES_BLOCK_SIZE];
+  AES_encrypt(plaintext, block, &aes_key);
+  if (memcmp(block, ciphertext, AES_BLOCK_SIZE) != 0) {
+    fprintf(stderr, "AES_encrypt gave the wrong output\n");
+    return false;
+  }
+
+  // Test in-place encryption.
+  memcpy(block, plaintext, AES_BLOCK_SIZE);
+  AES_encrypt(block, block, &aes_key);
+  if (memcmp(block, ciphertext, AES_BLOCK_SIZE) != 0) {
+    fprintf(stderr, "AES_encrypt gave the wrong output\n");
+    return false;
+  }
+
+  if (AES_set_decrypt_key(key, key_len * 8, &aes_key) != 0) {
+    fprintf(stderr, "AES_set_decrypt_key failed\n");
+    return false;
+  }
+
+  // Test decryption.
+  AES_decrypt(ciphertext, block, &aes_key);
+  if (memcmp(block, plaintext, AES_BLOCK_SIZE) != 0) {
+    fprintf(stderr, "AES_decrypt gave the wrong output\n");
+    return false;
+  }
+
+  // Test in-place decryption.
+  memcpy(block, ciphertext, AES_BLOCK_SIZE);
+  AES_decrypt(block, block, &aes_key);
+  if (memcmp(block, plaintext, AES_BLOCK_SIZE) != 0) {
+    fprintf(stderr, "AES_decrypt gave the wrong output\n");
+    return false;
+  }
+  return true;
+}
+
+int main() {
+  CRYPTO_library_init();
+
+  // Test vectors from FIPS-197, Appendix C.
+  if (!TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
+                                "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               128 / 8,
+               (const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77"
+                                "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               (const uint8_t *)"\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
+                                "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a") ||
+      !TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
+                                "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                                "\x10\x11\x12\x13\x14\x15\x16\x17",
+               192 / 8,
+               (const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77"
+                                "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               (const uint8_t *)"\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
+                                "\x6e\xaf\x70\xa0\xec\x0d\x71\x91") ||
+      !TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
+                                "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                                "\x10\x11\x12\x13\x14\x15\x16\x17"
+                                "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               256 / 8,
+               (const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77"
+                                "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               (const uint8_t *)"\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
+                                "\xea\xfc\x49\x90\x4b\x49\x60\x89")) {
+    return false;
+  }
+
+  printf("PASS\n");
+  return 0;
+}
diff --git a/src/crypto/aes/asm/aes-586.pl b/src/crypto/aes/asm/aes-586.pl
index 07fb94c..6e8a6a8 100755
--- a/src/crypto/aes/asm/aes-586.pl
+++ b/src/crypto/aes/asm/aes-586.pl
@@ -45,7 +45,7 @@
 # the undertaken effort was that it appeared that in tight IA-32
 # register window little-endian flavor could achieve slightly higher
 # Instruction Level Parallelism, and it indeed resulted in up to 15%
-# better performance on most recent µ-archs...
+# better performance on most recent µ-archs...
 #
 # Third version adds AES_cbc_encrypt implementation, which resulted in
 # up to 40% performance imrovement of CBC benchmark results. 40% was
@@ -224,7 +224,7 @@
 $speed_limit=512;	# chunks smaller than $speed_limit are
 			# processed with compact routine in CBC mode
 $small_footprint=1;	# $small_footprint=1 code is ~5% slower [on
-			# recent µ-archs], but ~5 times smaller!
+			# recent µ-archs], but ~5 times smaller!
 			# I favor compact code to minimize cache
 			# contention and in hope to "collect" 5% back
 			# in real-life applications...
@@ -565,7 +565,7 @@
 # Performance is not actually extraordinary in comparison to pure
 # x86 code. In particular encrypt performance is virtually the same.
 # Decrypt performance on the other hand is 15-20% better on newer
-# µ-archs [but we're thankful for *any* improvement here], and ~50%
+# µ-archs [but we're thankful for *any* improvement here], and ~50%
 # better on PIII:-) And additionally on the pros side this code
 # eliminates redundant references to stack and thus relieves/
 # minimizes the pressure on the memory bus.
diff --git a/src/crypto/aes/asm/aes-armv4.pl b/src/crypto/aes/asm/aes-armv4.pl
index 36cd3b6..882017a 100644
--- a/src/crypto/aes/asm/aes-armv4.pl
+++ b/src/crypto/aes/asm/aes-armv4.pl
@@ -65,7 +65,7 @@
 $code=<<___;
 #if defined(__arm__)
 #ifndef __KERNEL__
-# include "arm_arch.h"
+# include <openssl/arm_arch.h>
 #else
 # define __ARM_ARCH__ __LINUX_ARM_ARCH__
 #endif
diff --git a/src/crypto/aes/asm/aesv8-armx.pl b/src/crypto/aes/asm/aesv8-armx.pl
index b0916f6..121154a 100644
--- a/src/crypto/aes/asm/aesv8-armx.pl
+++ b/src/crypto/aes/asm/aesv8-armx.pl
@@ -45,7 +45,7 @@
 $prefix="aes_v8";
 
 $code=<<___;
-#include "arm_arch.h"
+#include <openssl/arm_arch.h>
 
 #if __ARM_MAX_ARCH__>=7
 .text
diff --git a/src/crypto/aes/asm/bsaes-armv7.pl b/src/crypto/aes/asm/bsaes-armv7.pl
index 273f0b9..7fe349a 100644
--- a/src/crypto/aes/asm/bsaes-armv7.pl
+++ b/src/crypto/aes/asm/bsaes-armv7.pl
@@ -703,7 +703,7 @@
 $code.=<<___;
 #if defined(__arm__)
 #ifndef __KERNEL__
-# include "arm_arch.h"
+# include <openssl/arm_arch.h>
 
 # define VFP_ABI_PUSH	vstmdb	sp!,{d8-d15}
 # define VFP_ABI_POP	vldmia	sp!,{d8-d15}
diff --git a/src/crypto/arm_arch.h b/src/crypto/arm_arch.h
deleted file mode 100644
index 0600fbb..0000000
--- a/src/crypto/arm_arch.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* ====================================================================
- * Copyright (c) 1998-2011 The OpenSSL Project.  All rights reserved.
- *
- * 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 above 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 acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED 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 OpenSSL PROJECT OR
- * ITS 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.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com). */
-
-#ifndef OPENSSL_HEADER_ARM_ARCH_H
-#define OPENSSL_HEADER_ARM_ARCH_H
-
-#if !defined(__ARM_ARCH__)
-# if defined(__CC_ARM)
-#  define __ARM_ARCH__ __TARGET_ARCH_ARM
-#  if defined(__BIG_ENDIAN)
-#   define __ARMEB__
-#  else
-#   define __ARMEL__
-#  endif
-# elif defined(__GNUC__)
-#  if defined(__aarch64__)
-#    define __ARM_ARCH__ 8
-#    if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#      define __ARMEB__
-#    else
-#      define __ARMEL__
-#    endif
-  /* Why doesn't gcc define __ARM_ARCH__? Instead it defines
-   * bunch of below macros. See all_architectires[] table in
-   * gcc/config/arm/arm.c. On a side note it defines
-   * __ARMEL__/__ARMEB__ for little-/big-endian. */
-#  elif	defined(__ARM_ARCH)
-#    define __ARM_ARCH__ __ARM_ARCH
-#  elif	defined(__ARM_ARCH_8A__)
-#    define __ARM_ARCH__ 8
-#  elif	defined(__ARM_ARCH_7__)	|| defined(__ARM_ARCH_7A__)	|| \
-	defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__)	|| \
-	defined(__ARM_ARCH_7EM__)
-#   define __ARM_ARCH__ 7
-#  elif	defined(__ARM_ARCH_6__)	|| defined(__ARM_ARCH_6J__)	|| \
-	defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__)	|| \
-	defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__)	|| \
-	defined(__ARM_ARCH_6T2__)
-#   define __ARM_ARCH__ 6
-#  elif	defined(__ARM_ARCH_5__)	|| defined(__ARM_ARCH_5T__)	|| \
-	defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__)	|| \
-	defined(__ARM_ARCH_5TEJ__)
-#   define __ARM_ARCH__ 5
-#  elif	defined(__ARM_ARCH_4__)	|| defined(__ARM_ARCH_4T__)
-#   define __ARM_ARCH__ 4
-#  else
-#   error "unsupported ARM architecture"
-#  endif
-# endif
-#endif
-
-/* Even when building for 32-bit ARM, support for aarch64 crypto instructions
- * will be included. */
-#define __ARM_MAX_ARCH__ 8
-
-#if !__ASSEMBLER__
-
-/* OPENSSL_armcap_P contains flags describing the capabilities of the CPU and
- * is easy for assembly code to acesss. For C code, see the functions in
- * |cpu.h|. */
-extern uint32_t OPENSSL_armcap_P;
-
-#endif  /* !__ASSEMBLER__ */
-
-/* ARMV7_NEON is true when a NEON unit is present in the current CPU. */
-#define ARMV7_NEON (1 << 0)
-
-/* ARMV7_NEON_FUNCTIONAL is true when the NEON unit doesn't contain subtle bugs.
- * The Poly1305 NEON code is known to trigger bugs in the NEON units of some
- * phones. If this bit isn't set then the Poly1305 NEON code won't be used.
- * See https://code.google.com/p/chromium/issues/detail?id=341598. */
-#define ARMV7_NEON_FUNCTIONAL (1 << 10)
-
-/* ARMV8_AES indicates support for hardware AES instructions. */
-#define ARMV8_AES (1 << 2)
-
-/* ARMV8_SHA1 indicates support for hardware SHA-1 instructions. */
-#define ARMV8_SHA1 (1 << 3)
-
-/* ARMV8_SHA256 indicates support for hardware SHA-256 instructions. */
-#define ARMV8_SHA256 (1 << 4)
-
-/* ARMV8_PMULL indicates support for carryless multiplication. */
-#define ARMV8_PMULL (1 << 5)
-
-
-#endif  /* OPENSSL_HEADER_THREAD_H */
diff --git a/src/crypto/asn1/CMakeLists.txt b/src/crypto/asn1/CMakeLists.txt
index 283636e..41e3122 100644
--- a/src/crypto/asn1/CMakeLists.txt
+++ b/src/crypto/asn1/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   asn1
diff --git a/src/crypto/asn1/a_bitstr.c b/src/crypto/asn1/a_bitstr.c
index 8055f0c..8bad339 100644
--- a/src/crypto/asn1/a_bitstr.c
+++ b/src/crypto/asn1/a_bitstr.c
@@ -125,8 +125,7 @@
 
 	if (len < 1)
 		{
-		OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_BIT_STRING,
-			ASN1_R_STRING_TOO_SHORT);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_SHORT);
 		goto err;
 		}
 
@@ -141,8 +140,7 @@
 	padding = *(p++);
 	if (padding > 7)
 		{
-		OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_BIT_STRING,
-			ASN1_R_INVALID_BIT_STRING_BITS_LEFT);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT);
 		goto err;
 		}
 
@@ -157,8 +155,7 @@
 		s=(unsigned char *)OPENSSL_malloc((int)len);
 		if (s == NULL)
 			{
-			OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_BIT_STRING,
-				ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			goto err;
 			}
 		memcpy(s,p,(int)len);
@@ -209,7 +206,7 @@
 								 w+1);
 		if (c == NULL)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_BIT_STRING_set_bit, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			return 0;
 			}
   		if (w+1-a->length > 0) memset(c+a->length, 0, w+1-a->length);
diff --git a/src/crypto/asn1/a_bool.c b/src/crypto/asn1/a_bool.c
index c30ee48..826bcf4 100644
--- a/src/crypto/asn1/a_bool.c
+++ b/src/crypto/asn1/a_bool.c
@@ -107,6 +107,6 @@
 	*pp=p;
 	return(ret);
 err:
-	OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_BOOLEAN, i);
+	OPENSSL_PUT_ERROR(ASN1, i);
 	return(ret);
 	}
diff --git a/src/crypto/asn1/a_bytes.c b/src/crypto/asn1/a_bytes.c
index 8874f48..1904375 100644
--- a/src/crypto/asn1/a_bytes.c
+++ b/src/crypto/asn1/a_bytes.c
@@ -125,7 +125,7 @@
 	*pp=p;
 	return(ret);
 err:
-	OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_type_bytes, i);
+	OPENSSL_PUT_ERROR(ASN1, i);
 	if ((ret != NULL) && ((a == NULL) || (*a != ret)))
 		ASN1_STRING_free(ret);
 	return(NULL);
@@ -243,7 +243,7 @@
 err:
 	if ((ret != NULL) && ((a == NULL) || (*a != ret)))
 		ASN1_STRING_free(ret);
-	OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_bytes, i);
+	OPENSSL_PUT_ERROR(ASN1, i);
 	return(NULL);
 	}
 
@@ -309,7 +309,7 @@
 	if (os != NULL) ASN1_STRING_free(os);
 	return(1);
 err:
-	OPENSSL_PUT_ERROR(ASN1, asn1_collate_primitive, c->error);
+	OPENSSL_PUT_ERROR(ASN1, c->error);
 	if (os != NULL) ASN1_STRING_free(os);
 	if (b.data != NULL) OPENSSL_free(b.data);
 	return(0);
diff --git a/src/crypto/asn1/a_d2i_fp.c b/src/crypto/asn1/a_d2i_fp.c
index 6022c74..97ec75b 100644
--- a/src/crypto/asn1/a_d2i_fp.c
+++ b/src/crypto/asn1/a_d2i_fp.c
@@ -75,7 +75,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_d2i_fp, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
                 return(NULL);
 		}
         BIO_set_fp(b,in,BIO_NOCLOSE);
@@ -129,7 +129,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_item_d2i_fp, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
                 return(NULL);
 		}
         BIO_set_fp(b,in,BIO_NOCLOSE);
@@ -154,7 +154,7 @@
 	b=BUF_MEM_new();
 	if (b == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return -1;
 		}
 
@@ -167,20 +167,20 @@
 
 			if (len + want < len || !BUF_MEM_grow_clean(b,len+want))
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 				goto err;
 				}
 			i=BIO_read(in,&(b->data[len]),want);
 			if ((i < 0) && ((len-off) == 0))
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_NOT_ENOUGH_DATA);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
 				goto err;
 				}
 			if (i > 0)
 				{
 				if (len+i < len)
 					{
-					OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_TOO_LONG);
+					OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
 					goto err;
 					}
 				len+=i;
@@ -211,7 +211,7 @@
 			eos++;
 			if (eos < 0)
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_HEADER_TOO_LONG);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG);
 				goto err;
 				}
 			want=HEADER_SIZE;
@@ -235,12 +235,12 @@
 				if (want > INT_MAX /* BIO_read takes an int length */ ||
 					len+want < len)
 						{
-						OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_TOO_LONG);
+						OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
 						goto err;
 						}
 				if (!BUF_MEM_grow_clean(b,len+want))
 					{
-					OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ERR_R_MALLOC_FAILURE);
+					OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 					goto err;
 					}
 				while (want > 0)
@@ -248,7 +248,7 @@
 					i=BIO_read(in,&(b->data[len]),want);
 					if (i <= 0)
 						{
-						OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_NOT_ENOUGH_DATA);
+						OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
 						goto err;
 						}
 					/* This can't overflow because
@@ -259,7 +259,7 @@
 				}
 			if (off + c.slen < off)
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_TOO_LONG);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
 				goto err;
 				}
 			off+=c.slen;
@@ -274,7 +274,7 @@
 
 	if (off > INT_MAX)
 		{
-		OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_TOO_LONG);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
 		goto err;
 		}
 
diff --git a/src/crypto/asn1/a_dup.c b/src/crypto/asn1/a_dup.c
index 8ec1c5f..5e87457 100644
--- a/src/crypto/asn1/a_dup.c
+++ b/src/crypto/asn1/a_dup.c
@@ -72,7 +72,7 @@
 	i=i2d(x,NULL);
 	b=OPENSSL_malloc(i+10);
 	if (b == NULL)
-		{ OPENSSL_PUT_ERROR(ASN1, ASN1_dup, ERR_R_MALLOC_FAILURE); return(NULL); }
+		{ OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); return(NULL); }
 	p= b;
 	i=i2d(x,&p);
 	p2= b;
@@ -95,7 +95,7 @@
 
 	i=ASN1_item_i2d(x,&b,it);
 	if (b == NULL)
-		{ OPENSSL_PUT_ERROR(ASN1, ASN1_item_dup, ERR_R_MALLOC_FAILURE); return(NULL); }
+		{ OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); return(NULL); }
 	p= b;
 	ret=ASN1_item_d2i(NULL,&p,i, it);
 	OPENSSL_free(b);
diff --git a/src/crypto/asn1/a_enum.c b/src/crypto/asn1/a_enum.c
index a581a34..579dafd 100644
--- a/src/crypto/asn1/a_enum.c
+++ b/src/crypto/asn1/a_enum.c
@@ -84,7 +84,7 @@
 		}
 	if (a->data == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_ENUMERATED_set, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return(0);
 		}
 	d=v;
@@ -147,7 +147,7 @@
 		ret=ai;
 	if (ret == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, BN_to_ASN1_ENUMERATED, ASN1_R_NESTED_ASN1_ERROR);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 		goto err;
 		}
 	if(BN_is_negative(bn)) ret->type = V_ASN1_NEG_ENUMERATED;
@@ -159,7 +159,7 @@
 		unsigned char *new_data=OPENSSL_realloc(ret->data, len+4);
 		if (!new_data)
 			{
-			OPENSSL_PUT_ERROR(ASN1, BN_to_ASN1_ENUMERATED, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			goto err;
 			}
 		ret->data=new_data;
@@ -177,7 +177,7 @@
 	BIGNUM *ret;
 
 	if ((ret=BN_bin2bn(ai->data,ai->length,bn)) == NULL)
-		OPENSSL_PUT_ERROR(ASN1, ASN1_ENUMERATED_to_BN, ASN1_R_BN_LIB);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_BN_LIB);
 	else if(ai->type == V_ASN1_NEG_ENUMERATED) BN_set_negative(ret,1);
 	return(ret);
 	}
diff --git a/src/crypto/asn1/a_gentm.c b/src/crypto/asn1/a_gentm.c
index be093a4..7cb18a9 100644
--- a/src/crypto/asn1/a_gentm.c
+++ b/src/crypto/asn1/a_gentm.c
@@ -239,7 +239,7 @@
 		p=OPENSSL_malloc(len);
 		if (p == NULL)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_GENERALIZEDTIME_adj, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			return(NULL);
 			}
 		if (s->data != NULL)
diff --git a/src/crypto/asn1/a_i2d_fp.c b/src/crypto/asn1/a_i2d_fp.c
index 11e40d3..74ded78 100644
--- a/src/crypto/asn1/a_i2d_fp.c
+++ b/src/crypto/asn1/a_i2d_fp.c
@@ -67,7 +67,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_i2d_fp, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,out,BIO_NOCLOSE);
@@ -76,7 +76,7 @@
         return(ret);
         }
 
-int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x)
+int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, void *x)
 	{
 	char *b;
 	unsigned char *p;
@@ -86,7 +86,7 @@
 	b=(char *)OPENSSL_malloc(n);
 	if (b == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_i2d_bio, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return(0);
 		}
 
@@ -116,7 +116,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_item_i2d_fp, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,out,BIO_NOCLOSE);
@@ -133,7 +133,7 @@
 	n = ASN1_item_i2d(x, &b, it);
 	if (b == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_item_i2d_bio, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return(0);
 		}
 
diff --git a/src/crypto/asn1/a_int.c b/src/crypto/asn1/a_int.c
index 2ecccc5..9a56534 100644
--- a/src/crypto/asn1/a_int.c
+++ b/src/crypto/asn1/a_int.c
@@ -257,7 +257,7 @@
 	*pp=pend;
 	return(ret);
 err:
-	OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_INTEGER, i);
+	OPENSSL_PUT_ERROR(ASN1, i);
 	if ((ret != NULL) && ((a == NULL) || (*a != ret)))
 		M_ASN1_INTEGER_free(ret);
 	return(NULL);
@@ -327,7 +327,7 @@
 	*pp=p;
 	return(ret);
 err:
-	OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_UINTEGER, i);
+	OPENSSL_PUT_ERROR(ASN1, i);
 	if ((ret != NULL) && ((a == NULL) || (*a != ret)))
 		M_ASN1_INTEGER_free(ret);
 	return(NULL);
@@ -350,7 +350,7 @@
 		}
 	if (a->data == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_INTEGER_set, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return(0);
 		}
 	d=v;
@@ -413,7 +413,7 @@
 		ret=ai;
 	if (ret == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, BN_to_ASN1_INTEGER, ASN1_R_NESTED_ASN1_ERROR);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 		goto err;
 		}
 	if (BN_is_negative(bn) && !BN_is_zero(bn))
@@ -426,7 +426,7 @@
 		unsigned char *new_data=OPENSSL_realloc(ret->data, len+4);
 		if (!new_data)
 			{
-			OPENSSL_PUT_ERROR(ASN1, BN_to_ASN1_INTEGER, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			goto err;
 			}
 		ret->data=new_data;
@@ -449,7 +449,7 @@
 	BIGNUM *ret;
 
 	if ((ret=BN_bin2bn(ai->data,ai->length,bn)) == NULL)
-		OPENSSL_PUT_ERROR(ASN1, ASN1_INTEGER_to_BN, ASN1_R_BN_LIB);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_BN_LIB);
 	else if(ai->type == V_ASN1_NEG_INTEGER)
 		BN_set_negative(ret, 1);
 	return(ret);
diff --git a/src/crypto/asn1/a_mbstr.c b/src/crypto/asn1/a_mbstr.c
index 9abe659..42806d1 100644
--- a/src/crypto/asn1/a_mbstr.c
+++ b/src/crypto/asn1/a_mbstr.c
@@ -108,7 +108,7 @@
 
 		case MBSTRING_BMP:
 		if(len & 1) {
-			OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy,  ASN1_R_INVALID_BMPSTRING_LENGTH);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH);
 			return -1;
 		}
 		nchar = len >> 1;
@@ -116,7 +116,7 @@
 
 		case MBSTRING_UNIV:
 		if(len & 3) {
-			OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy,  ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
 			return -1;
 		}
 		nchar = len >> 2;
@@ -127,7 +127,7 @@
 		/* This counts the characters and does utf8 syntax checking */
 		ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar);
 		if(ret < 0) {
-			OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy,  ASN1_R_INVALID_UTF8STRING);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UTF8STRING);
 			return -1;
 		}
 		break;
@@ -137,19 +137,19 @@
 		break;
 
 		default:
-		OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy,  ASN1_R_UNKNOWN_FORMAT);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT);
 		return -1;
 	}
 
 	if((minsize > 0) && (nchar < minsize)) {
-		OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy,  ASN1_R_STRING_TOO_SHORT);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_SHORT);
 		BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize);
 		ERR_add_error_data(2, "minsize=", strbuf);
 		return -1;
 	}
 
 	if((maxsize > 0) && (nchar > maxsize)) {
-		OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy,  ASN1_R_STRING_TOO_LONG);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG);
 		BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
 		ERR_add_error_data(2, "maxsize=", strbuf);
 		return -1;
@@ -157,7 +157,7 @@
 
 	/* Now work out minimal type (if any) */
 	if(traverse_string(in, len, inform, type_str, &mask) < 0) {
-		OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy,  ASN1_R_ILLEGAL_CHARACTERS);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
 		return -1;
 	}
 
@@ -191,7 +191,7 @@
 		free_out = 1;
 		dest = ASN1_STRING_type_new(str_type);
 		if(!dest) {
-			OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy,  ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			return -1;
 		}
 		*out = dest;
@@ -199,7 +199,7 @@
 	/* If both the same type just copy across */
 	if(inform == outform) {
 		if(!ASN1_STRING_set(dest, in, len)) {
-			OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			return -1;
 		}
 		return str_type;
@@ -230,7 +230,7 @@
 	}
 	if(!(p = OPENSSL_malloc(outlen + 1))) {
 		if(free_out) ASN1_STRING_free(dest);
-		OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return -1;
 	}
 	dest->length = outlen;
diff --git a/src/crypto/asn1/a_object.c b/src/crypto/asn1/a_object.c
index 189886c..6ddfca9 100644
--- a/src/crypto/asn1/a_object.c
+++ b/src/crypto/asn1/a_object.c
@@ -106,13 +106,13 @@
 		}
 	else
 		{
-		OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_FIRST_NUM_TOO_LARGE);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIRST_NUM_TOO_LARGE);
 		goto err;
 		}
 
 	if (num <= 0)
 		{
-		OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_MISSING_SECOND_NUMBER);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_SECOND_NUMBER);
 		goto err;
 		}
 	c= *(p++);
@@ -122,7 +122,7 @@
 		if (num <= 0) break;
 		if ((c != '.') && (c != ' '))
 			{
-			OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_INVALID_SEPARATOR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_SEPARATOR);
 			goto err;
 			}
 		l=0;
@@ -136,7 +136,7 @@
 				break;
 			if ((c < '0') || (c > '9'))
 				{
-				OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_INVALID_DIGIT);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_DIGIT);
 				goto err;
 				}
 			if (!use_bn && l >= ((ULONG_MAX - 80) / 10L))
@@ -160,7 +160,7 @@
 			{
 			if ((first < 2) && (l >= 40))
 				{
-				OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_SECOND_NUMBER_TOO_LARGE);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE);
 				goto err;
 				}
 			if (use_bn)
@@ -204,7 +204,7 @@
 			{
 			if (len+i > olen)
 				{
-				OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_BUFFER_TOO_SMALL);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL);
 				goto err;
 				}
 			while (--i > 0)
@@ -280,7 +280,7 @@
 	if(ret) *pp = p;
 	return ret;
 err:
-	OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_OBJECT, i);
+	OPENSSL_PUT_ERROR(ASN1, i);
 	return(NULL);
 }
 
@@ -300,7 +300,7 @@
 	if (len <= 0 || len > INT_MAX || pp == NULL || (p = *pp) == NULL ||
 	    p[len - 1] & 0x80)
 		{
-		OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_OBJECT, ASN1_R_INVALID_OBJECT_ENCODING);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_OBJECT_ENCODING);
 		return NULL;
 		}
 	/* Now 0 < len <= INT_MAX, so the cast is safe. */
@@ -309,7 +309,7 @@
 		{
 		if (*p == 0x80 && (!i || !(p[-1] & 0x80)))
 			{
-			OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_OBJECT, ASN1_R_INVALID_OBJECT_ENCODING);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_OBJECT_ENCODING);
 			return NULL;
 			}
 		}
@@ -350,7 +350,7 @@
 	*pp=p;
 	return(ret);
 err:
-	OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_OBJECT, i);
+	OPENSSL_PUT_ERROR(ASN1, i);
 	if ((ret != NULL) && ((a == NULL) || (*a != ret)))
 		ASN1_OBJECT_free(ret);
 	return(NULL);
@@ -363,7 +363,7 @@
 	ret=(ASN1_OBJECT *)OPENSSL_malloc(sizeof(ASN1_OBJECT));
 	if (ret == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_OBJECT_new, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return(NULL);
 		}
 	ret->length=0;
diff --git a/src/crypto/asn1/a_strnid.c b/src/crypto/asn1/a_strnid.c
index df849e1..d4316f7 100644
--- a/src/crypto/asn1/a_strnid.c
+++ b/src/crypto/asn1/a_strnid.c
@@ -215,13 +215,13 @@
 	flags &= ~STABLE_FLAGS_MALLOC;
 	if(!stable) stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp);
 	if(!stable) {
-		OPENSSL_PUT_ERROR(ASN1, ASN1_STRING_TABLE_add,  ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return 0;
 	}
 	if(!(tmp = ASN1_STRING_TABLE_get(nid))) {
 		tmp = OPENSSL_malloc(sizeof(ASN1_STRING_TABLE));
 		if(!tmp) {
-			OPENSSL_PUT_ERROR(ASN1, ASN1_STRING_TABLE_add,  ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			return 0;
 		}
 		tmp->flags = flags | STABLE_FLAGS_MALLOC;
diff --git a/src/crypto/asn1/a_time.c b/src/crypto/asn1/a_time.c
index e02e858..ac2cb48 100644
--- a/src/crypto/asn1/a_time.c
+++ b/src/crypto/asn1/a_time.c
@@ -85,7 +85,7 @@
 	if(a->type == V_ASN1_UTCTIME || a->type == V_ASN1_GENERALIZEDTIME)
 				return(i2d_ASN1_bytes((ASN1_STRING *)a,pp,
 				     a->type ,V_ASN1_UNIVERSAL));
-	OPENSSL_PUT_ERROR(ASN1, XXX, ASN1_R_EXPECTING_A_TIME);
+	OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPECTING_A_TIME);
 	return -1;
 	}
 #endif
@@ -105,7 +105,7 @@
 	ts=OPENSSL_gmtime(&t,&data);
 	if (ts == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_TIME_adj,  ASN1_R_ERROR_GETTING_TIME);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_ERROR_GETTING_TIME);
 		return NULL;
 		}
 	if (offset_day || offset_sec)
diff --git a/src/crypto/asn1/a_utctm.c b/src/crypto/asn1/a_utctm.c
index 52b010f..dbbbecb 100644
--- a/src/crypto/asn1/a_utctm.c
+++ b/src/crypto/asn1/a_utctm.c
@@ -81,12 +81,12 @@
 		V_ASN1_UTCTIME,V_ASN1_UNIVERSAL);
 	if (ret == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, XXX, ERR_R_NESTED_ASN1_ERROR);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_NESTED_ASN1_ERROR);
 		return(NULL);
 		}
 	if (!ASN1_UTCTIME_check(ret))
 		{
-		OPENSSL_PUT_ERROR(ASN1, XXX, ASN1_R_INVALID_TIME_FORMAT);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT);
 		goto err;
 		}
 
@@ -257,7 +257,7 @@
 		p=OPENSSL_malloc(len);
 		if (p == NULL)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_UTCTIME_adj, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			goto err;
 			}
 		if (s->data != NULL)
diff --git a/src/crypto/asn1/asn1_lib.c b/src/crypto/asn1/asn1_lib.c
index 9aa2678..a109749 100644
--- a/src/crypto/asn1/asn1_lib.c
+++ b/src/crypto/asn1/asn1_lib.c
@@ -69,17 +69,10 @@
 OPENSSL_DECLARE_ERROR_REASON(ASN1, MALLOC_FAILURE);
 
 /* Cross-module errors from crypto/x509/i2d_pr.c */
-OPENSSL_DECLARE_ERROR_FUNCTION(ASN1, i2d_PrivateKey);
 OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE);
 
 /* Cross-module errors from crypto/x509/asn1_gen.c.
  * TODO(davidben): Remove these once asn1_gen.c is gone. */
-OPENSSL_DECLARE_ERROR_FUNCTION(ASN1, ASN1_generate_v3);
-OPENSSL_DECLARE_ERROR_FUNCTION(ASN1, asn1_cb);
-OPENSSL_DECLARE_ERROR_FUNCTION(ASN1, parse_tagging);
-OPENSSL_DECLARE_ERROR_FUNCTION(ASN1, append_exp);
-OPENSSL_DECLARE_ERROR_FUNCTION(ASN1, asn1_str2type);
-OPENSSL_DECLARE_ERROR_FUNCTION(ASN1, bitstr_cb);
 OPENSSL_DECLARE_ERROR_REASON(ASN1, DEPTH_EXCEEDED);
 OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BITSTRING_FORMAT);
 OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BOOLEAN);
@@ -183,7 +176,7 @@
 #endif
 	if (*plength > (omax - (p - *pp)))
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_get_object, ASN1_R_TOO_LONG);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
 		/* Set this so that even if things are not long enough
 		 * the values are set correctly */
 		ret|=0x80;
@@ -191,7 +184,7 @@
 	*pp=p;
 	return(ret|inf);
 err:
-	OPENSSL_PUT_ERROR(ASN1, ASN1_get_object, ASN1_R_HEADER_TOO_LONG);
+	OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG);
 	return(0x80);
 	}
 
@@ -433,7 +426,7 @@
 
 		if (str->data == NULL)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_STRING_set, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			str->data=c;
 			return(0);
 			}
@@ -469,7 +462,7 @@
 	ret=(ASN1_STRING *)OPENSSL_malloc(sizeof(ASN1_STRING));
 	if (ret == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_STRING_type_new, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return(NULL);
 		}
 	ret->length=0;
diff --git a/src/crypto/asn1/asn_pack.c b/src/crypto/asn1/asn_pack.c
index ee58fa5..e842a10 100644
--- a/src/crypto/asn1/asn_pack.c
+++ b/src/crypto/asn1/asn_pack.c
@@ -68,7 +68,7 @@
 
 	if (!oct || !*oct) {
 		if (!(octmp = ASN1_STRING_new ())) {
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_pack, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			return NULL;
 		}
 		if (oct) *oct = octmp;
@@ -80,11 +80,11 @@
 	}
 		
 	if (!(octmp->length = ASN1_item_i2d(obj, &octmp->data, it))) {
-		OPENSSL_PUT_ERROR(ASN1, ASN1_item_pack, ASN1_R_ENCODE_ERROR);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_ENCODE_ERROR);
 		return NULL;
 	}
 	if (!octmp->data) {
-		OPENSSL_PUT_ERROR(ASN1, ASN1_item_pack, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	return octmp;
@@ -99,6 +99,6 @@
 
 	p = oct->data;
 	if(!(ret = ASN1_item_d2i(NULL, &p, oct->length, it)))
-		OPENSSL_PUT_ERROR(ASN1, ASN1_item_unpack, ASN1_R_DECODE_ERROR);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
 	return ret;
 }
diff --git a/src/crypto/asn1/bio_ndef.c b/src/crypto/asn1/bio_ndef.c
index 2f7105d..f07d3de 100644
--- a/src/crypto/asn1/bio_ndef.c
+++ b/src/crypto/asn1/bio_ndef.c
@@ -112,7 +112,7 @@
 
 	if (!aux || !aux->asn1_cb)
 		{
-		OPENSSL_PUT_ERROR(ASN1, BIO_new_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_STREAMING_NOT_SUPPORTED);
 		return NULL;
 		}
 	ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT));
diff --git a/src/crypto/asn1/f_enum.c b/src/crypto/asn1/f_enum.c
index 530afe5..bcdb773 100644
--- a/src/crypto/asn1/f_enum.c
+++ b/src/crypto/asn1/f_enum.c
@@ -144,7 +144,7 @@
 		i-=again;
 		if (i%2 != 0)
 			{
-			OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_ENUMERATED, ASN1_R_ODD_NUMBER_OF_CHARS);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
 			goto err;
 			}
 		i/=2;
@@ -158,7 +158,7 @@
 					(unsigned int)num+i*2);
 			if (sp == NULL)
 				{
-				OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_ENUMERATED, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 				goto err;
 				}
 			s=sp;
@@ -177,7 +177,7 @@
 					m=m-'A'+10;
 				else
 					{
-					OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_ENUMERATED, ASN1_R_NON_HEX_CHARACTERS);
+					OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS);
 					goto err;
 					}
 				s[num+j]<<=4;
@@ -197,7 +197,7 @@
 	if (0)
 		{
 err_sl:
-		OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_ENUMERATED, ASN1_R_SHORT_LINE);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE);
 		}
 	if (s != NULL)
 		OPENSSL_free(s);
diff --git a/src/crypto/asn1/f_int.c b/src/crypto/asn1/f_int.c
index 2c4fe6f..5186304 100644
--- a/src/crypto/asn1/f_int.c
+++ b/src/crypto/asn1/f_int.c
@@ -149,7 +149,7 @@
 		i-=again;
 		if (i%2 != 0)
 			{
-			OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_INTEGER, ASN1_R_ODD_NUMBER_OF_CHARS);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
 			goto err;
 			}
 		i/=2;
@@ -162,7 +162,7 @@
 				sp=OPENSSL_realloc_clean(s,slen,num+i*2);
 			if (sp == NULL)
 				{
-				OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_INTEGER, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 				goto err;
 				}
 			s=sp;
@@ -181,7 +181,7 @@
 					m=m-'A'+10;
 				else
 					{
-					OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_INTEGER, ASN1_R_NON_HEX_CHARACTERS);
+					OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS);
 					goto err;
 					}
 				s[num+j]<<=4;
@@ -201,7 +201,7 @@
 	if (0)
 		{
 err_sl:
-		OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_INTEGER, ASN1_R_SHORT_LINE);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE);
 		}
 	if (s != NULL)
 		OPENSSL_free(s);
diff --git a/src/crypto/asn1/f_string.c b/src/crypto/asn1/f_string.c
index 2f53670..5a7fe36 100644
--- a/src/crypto/asn1/f_string.c
+++ b/src/crypto/asn1/f_string.c
@@ -142,7 +142,7 @@
 		i-=again;
 		if (i%2 != 0)
 			{
-			OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_STRING, ASN1_R_ODD_NUMBER_OF_CHARS);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
 			goto err;
 			}
 		i/=2;
@@ -156,7 +156,7 @@
 					(unsigned int)num+i*2);
 			if (sp == NULL)
 				{
-				OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_STRING, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 				goto err;
 				}
 			s=sp;
@@ -175,7 +175,7 @@
 					m=m-'A'+10;
 				else
 					{
-					OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_STRING, ASN1_R_NON_HEX_CHARACTERS);
+					OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS);
 					goto err;
 					}
 				s[num+j]<<=4;
@@ -195,7 +195,7 @@
 	if (0)
 		{
 err_sl:
-		OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_STRING, ASN1_R_SHORT_LINE);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE);
 		}
 	if (s != NULL)
 		OPENSSL_free(s);
diff --git a/src/crypto/asn1/tasn_dec.c b/src/crypto/asn1/tasn_dec.c
index 73d3bb3..507a842 100644
--- a/src/crypto/asn1/tasn_dec.c
+++ b/src/crypto/asn1/tasn_dec.c
@@ -189,7 +189,7 @@
 			 */
 			if ((tag != -1) || opt)
 				{
-				OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
 				goto err;
 				}
 			return asn1_template_ex_d2i(pval, in, len,
@@ -206,7 +206,7 @@
 						&p, len, -1, 0, 1, ctx);
 		if (!ret)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			goto err;
 			}
 
@@ -215,7 +215,7 @@
 			{
 			/* If OPTIONAL, assume this is OK */
 			if (opt) return -1;
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_MSTRING_NOT_UNIVERSAL);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_MSTRING_NOT_UNIVERSAL);
 			goto err;
 			}
 		/* Check tag matches bit map */
@@ -224,7 +224,7 @@
 			/* If OPTIONAL, assume this is OK */
 			if (opt)
 				return -1;
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_MSTRING_WRONG_TAG);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_MSTRING_WRONG_TAG);
 			goto err;
 			}
 		return asn1_d2i_ex_primitive(pval, in, len,
@@ -255,7 +255,7 @@
 					&p, len, exptag, aclass, 1, ctx);
 			if (!ret)
 				{
-				OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 				goto err;
 				}
 			if (ret == -1)
@@ -283,7 +283,7 @@
 			imphack = *wp;
 			if (p == NULL)
 				{
-				OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 				goto err;
 				}
 			*wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED)
@@ -298,7 +298,7 @@
 		if (ptmpval)
 			return 1;
 
-		OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 		goto err;
 
 
@@ -320,7 +320,7 @@
 			}
 		else if (!ASN1_item_ex_new(pval, it))
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			goto err;
 			}
 		/* CHOICE type, try each possibility in turn */
@@ -340,7 +340,7 @@
 				break;
 			/* Otherwise must be an ASN1 parsing error */
 			errtt = tt;
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			goto err;
 			}
 
@@ -354,7 +354,7 @@
 				ASN1_item_ex_free(pval, it);
 				return -1;
 				}
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_NO_MATCHING_CHOICE_TYPE);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NO_MATCHING_CHOICE_TYPE);
 			goto err;
 			}
 
@@ -380,7 +380,7 @@
 					&p, len, tag, aclass, opt, ctx);
 		if (!ret)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			goto err;
 			}
 		else if (ret == -1)
@@ -394,13 +394,13 @@
 		else seq_nolen = seq_eoc;
 		if (!cst)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_SEQUENCE_NOT_CONSTRUCTED);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_NOT_CONSTRUCTED);
 			goto err;
 			}
 
 		if (!*pval && !ASN1_item_ex_new(pval, it))
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			goto err;
 			}
 
@@ -437,7 +437,7 @@
 				{
 				if (!seq_eoc)
 					{
-					OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_UNEXPECTED_EOC);
+					OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNEXPECTED_EOC);
 					goto err;
 					}
 				len -= p - q;
@@ -479,13 +479,13 @@
 		/* Check for EOC if expecting one */
 		if (seq_eoc && !asn1_check_eoc(&p, len))
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_MISSING_EOC);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC);
 			goto err;
 			}
 		/* Check all data read */
 		if (!seq_nolen && len)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_SEQUENCE_LENGTH_MISMATCH);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_LENGTH_MISMATCH);
 			goto err;
 			}
 
@@ -508,7 +508,7 @@
 			else
 				{
 				errtt = seqtt;
-				OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_FIELD_MISSING);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIELD_MISSING);
 				goto err;
 				}
 			}
@@ -524,7 +524,7 @@
 		return 0;
 		}
 	auxerr:
-	OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i,  ASN1_R_AUX_ERROR);
+	OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR);
 	err:
 	ASN1_item_ex_free(pval, it);
 	if (errtt)
@@ -569,21 +569,21 @@
 		q = p;
 		if (!ret)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_template_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			return 0;
 			}
 		else if (ret == -1)
 			return -1;
 		if (!cst)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_template_ex_d2i,  ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED);
 			return 0;
 			}
 		/* We've found the field so it can't be OPTIONAL now */
 		ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx);
 		if (!ret)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_template_ex_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			return 0;
 			}
 		/* We read the field in OK so update length */
@@ -593,7 +593,7 @@
 			/* If NDEF we must have an EOC here */
 			if (!asn1_check_eoc(&p, len))
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_template_ex_d2i,  ASN1_R_MISSING_EOC);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC);
 				goto err;
 				}
 			}
@@ -603,7 +603,7 @@
 			 * an error */
 			if (len)
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_template_ex_d2i,  ASN1_R_EXPLICIT_LENGTH_MISMATCH);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPLICIT_LENGTH_MISMATCH);
 				goto err;
 				}
 			}
@@ -659,7 +659,7 @@
 					&p, len, sktag, skaclass, opt, ctx);
 		if (!ret)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			return 0;
 			}
 		else if (ret == -1)
@@ -682,7 +682,7 @@
 				
 		if (!*val)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i,  ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			goto err;
 			}
 
@@ -696,7 +696,7 @@
 				{
 				if (!sk_eoc)
 					{
-					OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i,  ASN1_R_UNEXPECTED_EOC);
+					OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNEXPECTED_EOC);
 					goto err;
 					}
 				len -= p - q;
@@ -708,20 +708,20 @@
 						ASN1_ITEM_ptr(tt->item),
 						-1, 0, 0, ctx))
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 				goto err;
 				}
 			len -= p - q;
 			if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val,
 						skfield))
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i,  ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 				goto err;
 				}
 			}
 		if (sk_eoc)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i,  ASN1_R_MISSING_EOC);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC);
 			goto err;
 			}
 		}
@@ -732,7 +732,7 @@
 			ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx);
 		if (!ret)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			goto err;
 			}
 		else if (ret == -1)
@@ -745,7 +745,7 @@
 							-1, 0, opt, ctx);
 		if (!ret)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			goto err;
 			}
 		else if (ret == -1)
@@ -775,7 +775,7 @@
 	long len; 
 	if (!pval)
 		{
-		OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive,  ASN1_R_ILLEGAL_NULL);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NULL);
 		return 0; /* Should never happen */
 		}
 
@@ -793,12 +793,12 @@
 		unsigned char oclass;
 		if (tag >= 0)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive,  ASN1_R_ILLEGAL_TAGGED_ANY);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_TAGGED_ANY);
 			return 0;
 			}
 		if (opt)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive,  ASN1_R_ILLEGAL_OPTIONAL_ANY);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OPTIONAL_ANY);
 			return 0;
 			}
 		p = *in;
@@ -806,7 +806,7 @@
 					&p, inlen, -1, 0, 0, ctx);
 		if (!ret)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			return 0;
 			}
 		if (oclass != V_ASN1_UNIVERSAL)
@@ -823,7 +823,7 @@
 				&p, inlen, tag, aclass, opt, ctx);
 	if (!ret)
 		{
-		OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive,  ASN1_R_NESTED_ASN1_ERROR);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 		return 0;
 		}
 	else if (ret == -1)
@@ -843,7 +843,7 @@
 		/* SEQUENCE and SET must be constructed */
 		else if (!cst)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive,  ASN1_R_TYPE_NOT_CONSTRUCTED);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_TYPE_NOT_CONSTRUCTED);
 			return 0;
 			}
 
@@ -869,8 +869,7 @@
 			|| utype == V_ASN1_ENUMERATED)
 			{
 			/* These types only have primitive encodings. */
-			OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive,
-				ASN1_R_TYPE_NOT_PRIMITIVE);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_TYPE_NOT_PRIMITIVE);
 			return 0;
 			}
 
@@ -892,7 +891,7 @@
 		/* Append a final null to string */
 		if (!BUF_MEM_grow_clean(&buf, len + 1))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive,  ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			return 0;
 			}
 		buf.data[len] = 0;
@@ -960,7 +959,7 @@
 		case V_ASN1_NULL:
 		if (len)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i,  ASN1_R_NULL_IS_WRONG_LENGTH);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NULL_IS_WRONG_LENGTH);
 			goto err;
 			}
 		*pval = (ASN1_VALUE *)1;
@@ -969,7 +968,7 @@
 		case V_ASN1_BOOLEAN:
 		if (len != 1)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i,  ASN1_R_BOOLEAN_IS_WRONG_LENGTH);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_BOOLEAN_IS_WRONG_LENGTH);
 			goto err;
 			}
 		else
@@ -1016,12 +1015,12 @@
 		default:
 		if (utype == V_ASN1_BMPSTRING && (len & 1))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i,  ASN1_R_BMPSTRING_IS_WRONG_LENGTH);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH);
 			goto err;
 			}
 		if (utype == V_ASN1_UNIVERSALSTRING && (len & 3))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i,  ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH);
 			goto err;
 			}
 		/* All based on ASN1_STRING and handled the same */
@@ -1030,7 +1029,7 @@
 			stmp = ASN1_STRING_type_new(utype);
 			if (!stmp)
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i,  ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 				goto err;
 				}
 			*pval = (ASN1_VALUE *)stmp;
@@ -1053,7 +1052,7 @@
 			{
 			if (!ASN1_STRING_set(stmp, cont, len))
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i,  ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 				ASN1_STRING_free(stmp);	
 				*pval = NULL;
 				goto err;
@@ -1115,7 +1114,7 @@
 		if(!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len,
 				-1, 0, 0, NULL))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_find_end,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			return 0;
 			}
 		if (inf)
@@ -1126,7 +1125,7 @@
 		}
 	if (expected_eoc)
 		{
-		OPENSSL_PUT_ERROR(ASN1, asn1_find_end,  ASN1_R_MISSING_EOC);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC);
 		return 0;
 		}
 	*in = p;
@@ -1173,7 +1172,7 @@
 			 * constructed form */
 			if (!inf)
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_collect,  ASN1_R_UNEXPECTED_EOC);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNEXPECTED_EOC);
 				return 0;
 				}
 			inf = 0;
@@ -1183,7 +1182,7 @@
 		if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p,
 					len, tag, aclass, 0, NULL))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_collect,  ASN1_R_NESTED_ASN1_ERROR);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
 			return 0;
 			}
 
@@ -1192,7 +1191,7 @@
 			{
 			if (depth >= ASN1_MAX_STRING_NEST)
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_collect,  ASN1_R_NESTED_ASN1_STRING);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_STRING);
 				return 0;
 				}
 			if (!asn1_collect(buf, &p, plen, ininf, tag, aclass,
@@ -1205,7 +1204,7 @@
 		}
 	if (inf)
 		{
-		OPENSSL_PUT_ERROR(ASN1, asn1_collect,  ASN1_R_MISSING_EOC);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC);
 		return 0;
 		}
 	*in = p;
@@ -1220,7 +1219,7 @@
 		len = buf->length;
 		if (!BUF_MEM_grow_clean(buf, len + plen))
 			{
-			OPENSSL_PUT_ERROR(ASN1, collect_data,  ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			return 0;
 			}
 		memcpy(buf->data + len, *p, plen);
@@ -1288,7 +1287,7 @@
 			 */
 			if (!(i & 0x81) && ((plen + ctx->hdrlen) > len))
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_check_tlen,  ASN1_R_TOO_LONG);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
 				asn1_tlc_clear(ctx);
 				return 0;
 				}
@@ -1297,7 +1296,7 @@
 
 	if (i & 0x80)
 		{
-		OPENSSL_PUT_ERROR(ASN1, asn1_check_tlen,  ASN1_R_BAD_OBJECT_HEADER);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_OBJECT_HEADER);
 		asn1_tlc_clear(ctx);
 		return 0;
 		}
@@ -1310,7 +1309,7 @@
 			 */
 			if (opt) return -1;
 			asn1_tlc_clear(ctx);
-			OPENSSL_PUT_ERROR(ASN1, asn1_check_tlen,  ASN1_R_WRONG_TAG);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_TAG);
 			return 0;
 			}
 		/* We have a tag and class match:
diff --git a/src/crypto/asn1/tasn_new.c b/src/crypto/asn1/tasn_new.c
index 6d69dcb..c68fe06 100644
--- a/src/crypto/asn1/tasn_new.c
+++ b/src/crypto/asn1/tasn_new.c
@@ -209,7 +209,7 @@
 	return 1;
 
 	memerr:
-	OPENSSL_PUT_ERROR(ASN1, asn1_item_ex_combine_new,  ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 	ASN1_item_ex_free(pval, it);
 #ifdef CRYPTO_MDEBUG
 	if (it->sname) CRYPTO_pop_info();
@@ -217,7 +217,7 @@
 	return 0;
 
 	auxerr:
-	OPENSSL_PUT_ERROR(ASN1, asn1_item_ex_combine_new,  ASN1_R_AUX_ERROR);
+	OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR);
 	ASN1_item_ex_free(pval, it);
 #ifdef CRYPTO_MDEBUG
 	if (it->sname) CRYPTO_pop_info();
@@ -289,7 +289,7 @@
 		skval = sk_ASN1_VALUE_new_null();
 		if (!skval)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_template_new,  ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			ret = 0;
 			goto done;
 			}
diff --git a/src/crypto/asn1/tasn_prn.c b/src/crypto/asn1/tasn_prn.c
index df19ff0..6a097a1 100644
--- a/src/crypto/asn1/tasn_prn.c
+++ b/src/crypto/asn1/tasn_prn.c
@@ -88,7 +88,7 @@
 	ret = OPENSSL_malloc(sizeof(ASN1_PCTX));
 	if (ret == NULL)
 		{
-		OPENSSL_PUT_ERROR(ASN1, ASN1_PCTX_new, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return NULL;
 		}
 	ret->flags = 0;
diff --git a/src/crypto/asn1/tasn_utl.c b/src/crypto/asn1/tasn_utl.c
index ff3764e..960cdbb 100644
--- a/src/crypto/asn1/tasn_utl.c
+++ b/src/crypto/asn1/tasn_utl.c
@@ -260,8 +260,7 @@
 err:
   /* FIXME: should log the value or OID of unsupported type */
   if (nullerr) {
-    OPENSSL_PUT_ERROR(ASN1, asn1_do_adb,
-                      ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE);
+    OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE);
   }
   return NULL;
 }
diff --git a/src/crypto/asn1/x_long.c b/src/crypto/asn1/x_long.c
index 5c2f96e..7b1a6fe 100644
--- a/src/crypto/asn1/x_long.c
+++ b/src/crypto/asn1/x_long.c
@@ -150,7 +150,7 @@
 	unsigned long utmp = 0;
 	char *cp = (char *)pval;
 	if(len > (int)sizeof(long)) {
-		OPENSSL_PUT_ERROR(ASN1, long_c2i,  ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
 		return 0;
 	}
 	/* Is it negative? */
@@ -168,7 +168,7 @@
 		ltmp = -ltmp;
 	}
 	if(ltmp == it->size) {
-		OPENSSL_PUT_ERROR(ASN1, long_c2i,  ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
 		return 0;
 	}
 	memcpy(cp, &ltmp, sizeof(long));
diff --git a/src/crypto/base64/CMakeLists.txt b/src/crypto/base64/CMakeLists.txt
index 42037a5..f1dba6c 100644
--- a/src/crypto/base64/CMakeLists.txt
+++ b/src/crypto/base64/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   base64
diff --git a/src/crypto/bio/CMakeLists.txt b/src/crypto/bio/CMakeLists.txt
index dbf5951..8de090a 100644
--- a/src/crypto/bio/CMakeLists.txt
+++ b/src/crypto/bio/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   bio
diff --git a/src/crypto/bio/bio.c b/src/crypto/bio/bio.c
index 5ac5911..4bc98ba 100644
--- a/src/crypto/bio/bio.c
+++ b/src/crypto/bio/bio.c
@@ -90,7 +90,7 @@
 BIO *BIO_new(const BIO_METHOD *method) {
   BIO *ret = OPENSSL_malloc(sizeof(BIO));
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(BIO, BIO_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -153,7 +153,7 @@
   }
 
   if (io_func == NULL) {
-    OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return -2;
   }
 
@@ -165,7 +165,7 @@
   }
 
   if (!bio->init) {
-    OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNINITIALIZED);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
     return -2;
   }
 
@@ -217,7 +217,7 @@
   }
 
   if (bio->method == NULL || bio->method->ctrl == NULL) {
-    OPENSSL_PUT_ERROR(BIO, BIO_ctrl, BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return -2;
   }
 
@@ -323,7 +323,7 @@
   }
 
   if (bio->method == NULL || bio->method->callback_ctrl == NULL) {
-    OPENSSL_PUT_ERROR(BIO, BIO_callback_ctrl, BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return 0;
   }
 
@@ -462,6 +462,10 @@
   ERR_print_errors_cb(print_bio, bio);
 }
 
+void ERR_print_errors(BIO *bio) {
+  BIO_print_errors(bio);
+}
+
 /* bio_read_all reads everything from |bio| and prepends |prefix| to it. On
  * success, |*out| is set to an allocated buffer (which should be freed with
  * |OPENSSL_free|), |*out_len| is set to its length and one is returned. The
diff --git a/src/crypto/bio/bio_mem.c b/src/crypto/bio/bio_mem.c
index f3aad6f..ef56111 100644
--- a/src/crypto/bio/bio_mem.c
+++ b/src/crypto/bio/bio_mem.c
@@ -70,7 +70,7 @@
   const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len;
 
   if (!buf && len != 0) {
-    OPENSSL_PUT_ERROR(BIO, BIO_new_mem_buf, BIO_R_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_NULL_PARAMETER);
     return NULL;
   }
 
@@ -167,7 +167,7 @@
   b = (BUF_MEM *)bio->ptr;
 
   if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
-    OPENSSL_PUT_ERROR(BIO, mem_write, BIO_R_WRITE_TO_READ_ONLY_BIO);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_WRITE_TO_READ_ONLY_BIO);
     goto err;
   }
 
diff --git a/src/crypto/bio/buffer.c b/src/crypto/bio/buffer.c
index 3fc0685..9d0cb3c 100644
--- a/src/crypto/bio/buffer.c
+++ b/src/crypto/bio/buffer.c
@@ -406,7 +406,7 @@
   return ret;
 
 malloc_error:
-  OPENSSL_PUT_ERROR(BIO, buffer_ctrl, ERR_R_MALLOC_FAILURE);
+  OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
   return 0;
 }
 
diff --git a/src/crypto/bio/connect.c b/src/crypto/bio/connect.c
index 32361bf..2ed2def 100644
--- a/src/crypto/bio/connect.c
+++ b/src/crypto/bio/connect.c
@@ -142,7 +142,7 @@
       case BIO_CONN_S_BEFORE:
         p = c->param_hostname;
         if (p == NULL) {
-          OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_HOSTNAME_SPECIFIED);
+          OPENSSL_PUT_ERROR(BIO, BIO_R_NO_HOSTNAME_SPECIFIED);
           goto exit_loop;
         }
         for (; *p != 0; p++) {
@@ -167,7 +167,7 @@
         }
 
         if (c->param_port == NULL) {
-          OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_PORT_SPECIFIED);
+          OPENSSL_PUT_ERROR(BIO, BIO_R_NO_PORT_SPECIFIED);
           ERR_add_error_data(2, "host=", c->param_hostname);
           goto exit_loop;
         }
@@ -175,7 +175,7 @@
         if (!bio_ip_and_port_to_socket_and_addr(
                 &bio->num, &c->them, &c->them_length, c->param_hostname,
                 c->param_port)) {
-          OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_UNABLE_TO_CREATE_SOCKET);
+          OPENSSL_PUT_ERROR(BIO, BIO_R_UNABLE_TO_CREATE_SOCKET);
           ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
           goto exit_loop;
         }
@@ -185,7 +185,7 @@
 
         if (c->nbio) {
           if (!bio_socket_nbio(bio->num, 1)) {
-            OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_ERROR_SETTING_NBIO);
+            OPENSSL_PUT_ERROR(BIO, BIO_R_ERROR_SETTING_NBIO);
             ERR_add_error_data(4, "host=", c->param_hostname, ":",
                                c->param_port);
             goto exit_loop;
@@ -197,7 +197,7 @@
                          sizeof(i));
         if (ret < 0) {
           OPENSSL_PUT_SYSTEM_ERROR(setsockopt);
-          OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_KEEPALIVE);
+          OPENSSL_PUT_ERROR(BIO, BIO_R_KEEPALIVE);
           ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
           goto exit_loop;
         }
@@ -211,7 +211,7 @@
             bio->retry_reason = BIO_RR_CONNECT;
           } else {
             OPENSSL_PUT_SYSTEM_ERROR(connect);
-            OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_CONNECT_ERROR);
+            OPENSSL_PUT_ERROR(BIO, BIO_R_CONNECT_ERROR);
             ERR_add_error_data(4, "host=", c->param_hostname, ":",
                                c->param_port);
           }
@@ -232,7 +232,7 @@
           } else {
             BIO_clear_retry_flags(bio);
             OPENSSL_PUT_SYSTEM_ERROR(connect);
-            OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NBIO_CONNECT_ERROR);
+            OPENSSL_PUT_ERROR(BIO, BIO_R_NBIO_CONNECT_ERROR);
             ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
             ret = 0;
           }
@@ -464,7 +464,7 @@
       break;
     case BIO_CTRL_SET_CALLBACK: {
 #if 0 /* FIXME: Should this be used?  -- Richard Levitte */
-		OPENSSL_PUT_ERROR(BIO, XXX, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+		OPENSSL_PUT_ERROR(BIO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
 		ret = -1;
 #else
       ret = 0;
diff --git a/src/crypto/bio/file.c b/src/crypto/bio/file.c
index 7f57aad..2d3ccfe 100644
--- a/src/crypto/bio/file.c
+++ b/src/crypto/bio/file.c
@@ -88,7 +88,7 @@
 #define BIO_FP_APPEND 0x08
 
 static FILE *open_file(const char *filename, const char *mode) {
-#if defined(_WIN32) && defined(CP_UTF8)
+#if defined(OPENSSL_WINDOWS) && defined(CP_UTF8)
   int sz, len_0 = (int)strlen(filename) + 1;
   DWORD flags;
 
@@ -133,9 +133,9 @@
 
     ERR_add_error_data(5, "fopen('", filename, "','", mode, "')");
     if (errno == ENOENT) {
-      OPENSSL_PUT_ERROR(BIO, BIO_new_file, BIO_R_NO_SUCH_FILE);
+      OPENSSL_PUT_ERROR(BIO, BIO_R_NO_SUCH_FILE);
     } else {
-      OPENSSL_PUT_ERROR(BIO, BIO_new_file, BIO_R_SYS_LIB);
+      OPENSSL_PUT_ERROR(BIO, BIO_R_SYS_LIB);
     }
     return NULL;
   }
@@ -182,20 +182,19 @@
 }
 
 static int file_read(BIO *b, char *out, int outl) {
-  int ret = 0;
-
   if (!b->init) {
     return 0;
   }
 
-  ret = fread(out, 1, outl, (FILE *)b->ptr);
+  size_t ret = fread(out, 1, outl, (FILE *)b->ptr);
   if (ret == 0 && ferror((FILE *)b->ptr)) {
     OPENSSL_PUT_SYSTEM_ERROR(fread);
-    OPENSSL_PUT_ERROR(BIO, file_read, ERR_R_SYS_LIB);
-    ret = -1;
+    OPENSSL_PUT_ERROR(BIO, ERR_R_SYS_LIB);
+    return -1;
   }
 
-  return ret;
+  /* fread reads at most |outl| bytes, so |ret| fits in an int. */
+  return (int)ret;
 }
 
 static int file_write(BIO *b, const char *in, int inl) {
@@ -253,7 +252,7 @@
       } else if (num & BIO_FP_READ) {
         BUF_strlcpy(p, "r", sizeof(p));
       } else {
-        OPENSSL_PUT_ERROR(BIO, file_ctrl, BIO_R_BAD_FOPEN_MODE);
+        OPENSSL_PUT_ERROR(BIO, BIO_R_BAD_FOPEN_MODE);
         ret = 0;
         break;
       }
@@ -261,7 +260,7 @@
       if (fp == NULL) {
         OPENSSL_PUT_SYSTEM_ERROR(fopen);
         ERR_add_error_data(5, "fopen('", ptr, "','", p, "')");
-        OPENSSL_PUT_ERROR(BIO, file_ctrl, ERR_R_SYS_LIB);
+        OPENSSL_PUT_ERROR(BIO, ERR_R_SYS_LIB);
         ret = 0;
         break;
       }
diff --git a/src/crypto/bio/pair.c b/src/crypto/bio/pair.c
index cc55950..6f78890 100644
--- a/src/crypto/bio/pair.c
+++ b/src/crypto/bio/pair.c
@@ -181,27 +181,25 @@
   BIO_clear_retry_flags(bio);
 
   if (!bio->init) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf, BIO_R_UNINITIALIZED);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
     return 0;
   }
 
   b = bio->ptr;
 
   if (!b || !b->peer) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf,
-                      BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return 0;
   }
 
   peer_b = b->peer->ptr;
   if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf,
-                      BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return 0;
   }
 
   if (peer_b->zero_copy_read_lock) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf, BIO_R_INVALID_ARGUMENT);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
     return 0;
   }
 
@@ -229,37 +227,32 @@
   assert(BIO_get_retry_flags(bio) == 0);
 
   if (!bio->init) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
-                      BIO_R_UNINITIALIZED);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
     return 0;
   }
 
   b = bio->ptr;
 
   if (!b || !b->peer) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
-                      BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return 0;
   }
 
   peer_b = b->peer->ptr;
   if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
-                      BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return 0;
   }
 
   if (!peer_b->zero_copy_read_lock) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
-                      BIO_R_INVALID_ARGUMENT);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
     return 0;
   }
 
   max_available =
       bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset);
   if (bytes_read > max_available) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_read_buf_done,
-                      BIO_R_INVALID_ARGUMENT);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
     return 0;
   }
 
@@ -318,35 +311,33 @@
   BIO_clear_retry_flags(bio);
 
   if (!bio->init) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf, BIO_R_UNINITIALIZED);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
     return 0;
   }
 
   b = bio->ptr;
 
   if (!b || !b->buf || !b->peer) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf,
-                      BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return 0;
   }
   peer_b = b->peer->ptr;
   if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf,
-                      BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return 0;
   }
 
   assert(b->buf != NULL);
 
   if (b->zero_copy_write_lock) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf, BIO_R_INVALID_ARGUMENT);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
     return 0;
   }
 
   b->request = 0;
   if (b->closed) {
     /* Bio is already closed. */
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf, BIO_R_BROKEN_PIPE);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
     return 0;
   }
 
@@ -369,43 +360,38 @@
   uint8_t* dummy_write_buf;
 
   if (!bio->init) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
-                      BIO_R_UNINITIALIZED);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
     return 0;
   }
 
   b = bio->ptr;
 
   if (!b || !b->buf || !b->peer) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
-                      BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return 0;
   }
   peer_b = b->peer->ptr;
   if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
-                      BIO_R_UNSUPPORTED_METHOD);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
     return 0;
   }
 
   b->request = 0;
   if (b->closed) {
     /* BIO is already closed. */
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done, BIO_R_BROKEN_PIPE);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
     return 0;
   }
 
   if (!b->zero_copy_write_lock) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
-                      BIO_R_INVALID_ARGUMENT);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
     return 0;
   }
 
   rest = bio_zero_copy_get_write_buf(b, &dummy_write_buf, &dummy_write_offset);
 
   if (bytes_written > rest) {
-    OPENSSL_PUT_ERROR(BIO, BIO_zero_copy_get_write_buf_done,
-                      BIO_R_INVALID_ARGUMENT);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
     return 0;
   }
 
@@ -525,7 +511,7 @@
   b->request = 0;
   if (b->closed) {
     /* we already closed */
-    OPENSSL_PUT_ERROR(BIO, bio_write, BIO_R_BROKEN_PIPE);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
     return -1;
   }
 
@@ -590,7 +576,7 @@
   b2 = bio2->ptr;
 
   if (b1->peer != NULL || b2->peer != NULL) {
-    OPENSSL_PUT_ERROR(BIO, bio_make_pair, BIO_R_IN_USE);
+    OPENSSL_PUT_ERROR(BIO, BIO_R_IN_USE);
     return 0;
   }
 
@@ -605,7 +591,7 @@
       b1->buf_externally_allocated = 0;
       b1->buf = OPENSSL_malloc(b1->size);
       if (b1->buf == NULL) {
-        OPENSSL_PUT_ERROR(BIO, bio_make_pair, ERR_R_MALLOC_FAILURE);
+        OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
         return 0;
       }
     } else {
@@ -624,7 +610,7 @@
       b2->buf_externally_allocated = 0;
       b2->buf = OPENSSL_malloc(b2->size);
       if (b2->buf == NULL) {
-        OPENSSL_PUT_ERROR(BIO, bio_make_pair, ERR_R_MALLOC_FAILURE);
+        OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
         return 0;
       }
     } else {
diff --git a/src/crypto/bio/printf.c b/src/crypto/bio/printf.c
index f51b396..2f5ae4a 100644
--- a/src/crypto/bio/printf.c
+++ b/src/crypto/bio/printf.c
@@ -95,7 +95,7 @@
     out = OPENSSL_malloc(requested_len + 1);
     out_malloced = 1;
     if (out == NULL) {
-      OPENSSL_PUT_ERROR(BIO, BIO_printf, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
       return -1;
     }
     va_start(args, format);
diff --git a/src/crypto/bio/socket_helper.c b/src/crypto/bio/socket_helper.c
index b1cdd1a..01f635e 100644
--- a/src/crypto/bio/socket_helper.c
+++ b/src/crypto/bio/socket_helper.c
@@ -12,7 +12,8 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
-#define _POSIX_SOURCE
+#undef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200112L
 
 #include <openssl/bio.h>
 #include <openssl/err.h>
@@ -50,7 +51,7 @@
 
   ret = getaddrinfo(hostname, port_str, &hint, &result);
   if (ret != 0) {
-    OPENSSL_PUT_ERROR(SYS, getaddrinfo, 0);
+    OPENSSL_PUT_ERROR(SYS, 0);
     ERR_add_error_data(1, gai_strerror(ret));
     return 0;
   }
diff --git a/src/crypto/bn/CMakeLists.txt b/src/crypto/bn/CMakeLists.txt
index 2e0cb45..232e40a 100644
--- a/src/crypto/bn/CMakeLists.txt
+++ b/src/crypto/bn/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 if (${ARCH} STREQUAL "x86_64")
   set(
@@ -39,6 +39,7 @@
   add.c
   asm/x86_64-gcc.c
   bn.c
+  bn_asn1.c
   cmp.c
   convert.c
   ctx.c
diff --git a/src/crypto/bn/add.c b/src/crypto/bn/add.c
index 1c6b2d7..a043d83 100644
--- a/src/crypto/bn/add.c
+++ b/src/crypto/bn/add.c
@@ -267,7 +267,7 @@
 
   if (dif < 0) /* hmm... should not be happening */
   {
-    OPENSSL_PUT_ERROR(BN, BN_usub, BN_R_ARG2_LT_ARG3);
+    OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3);
     return 0;
   }
 
diff --git a/src/crypto/bn/asm/armv4-mont.pl b/src/crypto/bn/asm/armv4-mont.pl
index 0f1b6a9..4206fd8 100644
--- a/src/crypto/bn/asm/armv4-mont.pl
+++ b/src/crypto/bn/asm/armv4-mont.pl
@@ -79,7 +79,7 @@
 $_num="$num,#15*4";	$_bpend=$_num;
 
 $code=<<___;
-#include "arm_arch.h"
+#include <openssl/arm_arch.h>
 
 .text
 .code	32
diff --git a/src/crypto/bn/bn.c b/src/crypto/bn/bn.c
index f32d6b0..b342749 100644
--- a/src/crypto/bn/bn.c
+++ b/src/crypto/bn/bn.c
@@ -69,7 +69,7 @@
   BIGNUM *bn = OPENSSL_malloc(sizeof(BIGNUM));
 
   if (bn == NULL) {
-    OPENSSL_PUT_ERROR(BN, BN_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -279,26 +279,26 @@
   }
 }
 
-BIGNUM *bn_wexpand(BIGNUM *bn, unsigned words) {
+BIGNUM *bn_wexpand(BIGNUM *bn, size_t words) {
   BN_ULONG *a;
 
-  if (words <= (unsigned) bn->dmax) {
+  if (words <= (size_t)bn->dmax) {
     return bn;
   }
 
   if (words > (INT_MAX / (4 * BN_BITS2))) {
-    OPENSSL_PUT_ERROR(BN, bn_wexpand, BN_R_BIGNUM_TOO_LONG);
+    OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
     return NULL;
   }
 
   if (bn->flags & BN_FLG_STATIC_DATA) {
-    OPENSSL_PUT_ERROR(BN, bn_wexpand, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA);
+    OPENSSL_PUT_ERROR(BN, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA);
     return NULL;
   }
 
   a = (BN_ULONG *)OPENSSL_malloc(sizeof(BN_ULONG) * words);
   if (a == NULL) {
-    OPENSSL_PUT_ERROR(BN, bn_wexpand, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -306,12 +306,16 @@
 
   OPENSSL_free(bn->d);
   bn->d = a;
-  bn->dmax = words;
+  bn->dmax = (int)words;
 
   return bn;
 }
 
-BIGNUM *bn_expand(BIGNUM *bn, unsigned bits) {
+BIGNUM *bn_expand(BIGNUM *bn, size_t bits) {
+  if (bits + BN_BITS2 - 1 < bits) {
+    OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
+    return NULL;
+  }
   return bn_wexpand(bn, (bits+BN_BITS2-1)/BN_BITS2);
 }
 
diff --git a/src/crypto/bn/bn_asn1.c b/src/crypto/bn/bn_asn1.c
new file mode 100644
index 0000000..9d70ba8
--- /dev/null
+++ b/src/crypto/bn/bn_asn1.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2015, 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/bn.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+
+
+int BN_cbs2unsigned(CBS *cbs, BIGNUM *ret) {
+  CBS child;
+  if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) ||
+      CBS_len(&child) == 0) {
+    OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
+    return 0;
+  }
+
+  if (CBS_data(&child)[0] & 0x80) {
+    OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
+    return 0;
+  }
+
+  /* INTEGERs must be minimal. */
+  if (CBS_data(&child)[0] == 0x00 &&
+      CBS_len(&child) > 1 &&
+      !(CBS_data(&child)[1] & 0x80)) {
+    OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
+    return 0;
+  }
+
+  return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL;
+}
+
+int BN_cbs2unsigned_buggy(CBS *cbs, BIGNUM *ret) {
+  CBS child;
+  if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) ||
+      CBS_len(&child) == 0) {
+    OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
+    return 0;
+  }
+
+  /* This function intentionally does not reject negative numbers or non-minimal
+   * encodings. Estonian IDs issued between September 2014 to September 2015 are
+   * broken. See https://crbug.com/532048 and https://crbug.com/534766.
+   *
+   * TODO(davidben): Remove this code and callers in March 2016. */
+  return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL;
+}
+
+int BN_bn2cbb(CBB *cbb, const BIGNUM *bn) {
+  /* Negative numbers are unsupported. */
+  if (BN_is_negative(bn)) {
+    OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
+    return 0;
+  }
+
+  CBB child;
+  if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) {
+    OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR);
+    return 0;
+  }
+
+  /* The number must be padded with a leading zero if the high bit would
+   * otherwise be set (or |bn| is zero). */
+  if (BN_num_bits(bn) % 8 == 0 &&
+      !CBB_add_u8(&child, 0x00)) {
+    OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR);
+    return 0;
+  }
+
+  uint8_t *out;
+  if (!CBB_add_space(&child, &out, BN_num_bytes(bn))) {
+    OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR);
+    return 0;
+  }
+  BN_bn2bin(bn, out);
+  if (!CBB_flush(cbb)) {
+    OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR);
+    return 0;
+  }
+  return 1;
+}
diff --git a/src/crypto/bn/bn_test.cc b/src/crypto/bn/bn_test.cc
index 6a7d48c..47093a7 100644
--- a/src/crypto/bn/bn_test.cc
+++ b/src/crypto/bn/bn_test.cc
@@ -82,6 +82,7 @@
 #include <openssl/mem.h>
 
 #include "../crypto/test/scoped_types.h"
+#include "../crypto/test/test_util.h"
 
 
 // This program tests the BIGNUM implementation. It takes an optional -bc
@@ -117,11 +118,13 @@
 static bool test_small_prime(FILE *fp, BN_CTX *ctx);
 static bool test_mod_exp_mont5(FILE *fp, BN_CTX *ctx);
 static bool test_sqrt(FILE *fp, BN_CTX *ctx);
-static bool test_bn2bin_padded(FILE *fp, BN_CTX *ctx);
-static bool test_dec2bn(FILE *fp, BN_CTX *ctx);
-static bool test_hex2bn(FILE *fp, BN_CTX *ctx);
-static bool test_asc2bn(FILE *fp, BN_CTX *ctx);
+static bool test_bn2bin_padded(BN_CTX *ctx);
+static bool test_dec2bn(BN_CTX *ctx);
+static bool test_hex2bn(BN_CTX *ctx);
+static bool test_asc2bn(BN_CTX *ctx);
+static bool test_mpi();
 static bool test_rand();
+static bool test_asn1();
 
 static const uint8_t kSample[] =
     "\xC6\x4F\x43\x04\x2A\xEA\xCA\x6E\x58\x36\x80\x5B\xE8\xC9"
@@ -311,35 +314,15 @@
   }
   flush_fp(bc_file.get());
 
-  message(bc_file.get(), "BN_bn2bin_padded");
-  if (!test_bn2bin_padded(bc_file.get(), ctx.get())) {
+  if (!test_bn2bin_padded(ctx.get()) ||
+      !test_dec2bn(ctx.get()) ||
+      !test_hex2bn(ctx.get()) ||
+      !test_asc2bn(ctx.get()) ||
+      !test_mpi() ||
+      !test_rand() ||
+      !test_asn1()) {
     return 1;
   }
-  flush_fp(bc_file.get());
-
-  message(bc_file.get(), "BN_dec2bn");
-  if (!test_dec2bn(bc_file.get(), ctx.get())) {
-    return 1;
-  }
-  flush_fp(bc_file.get());
-
-  message(bc_file.get(), "BN_hex2bn");
-  if (!test_hex2bn(bc_file.get(), ctx.get())) {
-    return 1;
-  }
-  flush_fp(bc_file.get());
-
-  message(bc_file.get(), "BN_asc2bn");
-  if (!test_asc2bn(bc_file.get(), ctx.get())) {
-    return 1;
-  }
-  flush_fp(bc_file.get());
-
-  message(bc_file.get(), "BN_rand");
-  if (!test_rand()) {
-    return 1;
-  }
-  flush_fp(bc_file.get());
 
   printf("PASS\n");
   return 0;
@@ -440,6 +423,16 @@
     return false;
   }
 
+  if (!BN_one(a.get())) {
+    return false;
+  }
+  BN_zero(b.get());
+  if (BN_div(d.get(), c.get(), a.get(), b.get(), ctx)) {
+    fprintf(stderr, "Division by zero succeeded!\n");
+    return false;
+  }
+  ERR_clear_error();
+
   for (int i = 0; i < num0 + num1; i++) {
     if (i < num1) {
       if (!BN_rand(a.get(), 400, 0, 0) ||
@@ -837,18 +830,17 @@
   }
 
   for (int i = 0; i < num0; i++) {
-    BN_ULONG s;
     do {
       if (!BN_rand(a.get(), 512, -1, 0) ||
           !BN_rand(b.get(), BN_BITS2, -1, 0)) {
         return false;
       }
-      s = b->d[0];
-    } while (!s);
+    } while (BN_is_zero(b.get()));
 
     if (!BN_copy(b.get(), a.get())) {
       return false;
     }
+    BN_ULONG s = b->d[0];
     BN_ULONG r = BN_div_word(b.get(), s);
     if (r == (BN_ULONG)-1) {
       return false;
@@ -891,8 +883,27 @@
   ScopedBIGNUM B(BN_new());
   ScopedBIGNUM n(BN_new());
   ScopedBN_MONT_CTX mont(BN_MONT_CTX_new());
-  if (!a || !b || !c || !d || !A || !B || !n || !mont ||
-      !BN_rand(a.get(), 100, 0, 0) ||
+  if (!a || !b || !c || !d || !A || !B || !n || !mont) {
+    return false;
+  }
+
+  BN_zero(n.get());
+  if (BN_MONT_CTX_set(mont.get(), n.get(), ctx)) {
+    fprintf(stderr, "BN_MONT_CTX_set succeeded for zero modulus!\n");
+    return false;
+  }
+  ERR_clear_error();
+
+  if (!BN_set_word(n.get(), 16)) {
+    return false;
+  }
+  if (BN_MONT_CTX_set(mont.get(), n.get(), ctx)) {
+    fprintf(stderr, "BN_MONT_CTX_set succeeded for even modulus!\n");
+    return false;
+  }
+  ERR_clear_error();
+
+  if (!BN_rand(a.get(), 100, 0, 0) ||
       !BN_rand(b.get(), 100, 0, 0)) {
     return false;
   }
@@ -932,6 +943,7 @@
       return false;
     }
   }
+
   return true;
 }
 
@@ -985,6 +997,16 @@
     return false;
   }
 
+  if (!BN_one(a.get()) || !BN_one(b.get())) {
+    return false;
+  }
+  BN_zero(c.get());
+  if (BN_mod_mul(e.get(), a.get(), b.get(), c.get(), ctx)) {
+    fprintf(stderr, "BN_mod_mul with zero modulus succeeded!\n");
+    return false;
+  }
+  ERR_clear_error();
+
   for (int j = 0; j < 3; j++) {
     if (!BN_rand(c.get(), 1024, 0, 0)) {
       return false;
@@ -1039,8 +1061,21 @@
   ScopedBIGNUM c(BN_new());
   ScopedBIGNUM d(BN_new());
   ScopedBIGNUM e(BN_new());
-  if (!a || !b || !c || !d || !e ||
-      !BN_rand(c.get(), 30, 0, 1)) {  // must be odd for montgomery
+  if (!a || !b || !c || !d || !e) {
+    return false;
+  }
+
+  if (!BN_one(a.get()) || !BN_one(b.get())) {
+    return false;
+  }
+  BN_zero(c.get());
+  if (BN_mod_exp(d.get(), a.get(), b.get(), c.get(), ctx)) {
+    fprintf(stderr, "BN_mod_exp with zero modulus succeeded!\n");
+    return 0;
+  }
+  ERR_clear_error();
+
+  if (!BN_rand(c.get(), 30, 0, 1)) {  // must be odd for montgomery
     return false;
   }
   for (int i = 0; i < num2; i++) {
@@ -1079,8 +1114,32 @@
   ScopedBIGNUM c(BN_new());
   ScopedBIGNUM d(BN_new());
   ScopedBIGNUM e(BN_new());
-  if (!a || !b || !c || !d || !e ||
-      !BN_rand(c.get(), 30, 0, 1)) {  // must be odd for montgomery
+  if (!a || !b || !c || !d || !e) {
+    return false;
+  }
+
+  if (!BN_one(a.get()) || !BN_one(b.get())) {
+    return false;
+  }
+  BN_zero(c.get());
+  if (BN_mod_exp_mont_consttime(d.get(), a.get(), b.get(), c.get(), ctx,
+                                nullptr)) {
+    fprintf(stderr, "BN_mod_exp_mont_consttime with zero modulus succeeded!\n");
+    return 0;
+  }
+  ERR_clear_error();
+
+  if (!BN_set_word(c.get(), 16)) {
+    return false;
+  }
+  if (BN_mod_exp_mont_consttime(d.get(), a.get(), b.get(), c.get(), ctx,
+                                nullptr)) {
+    fprintf(stderr, "BN_mod_exp_mont_consttime with even modulus succeeded!\n");
+    return 0;
+  }
+  ERR_clear_error();
+
+  if (!BN_rand(c.get(), 30, 0, 1)) {  // must be odd for montgomery
     return false;
   }
   for (int i = 0; i < num2; i++) {
@@ -1208,8 +1267,9 @@
     if (!BN_one(e.get())) {
       return false;
     }
-    for (; !BN_is_zero(b.get()); BN_sub(b.get(), b.get(), BN_value_one())) {
-      if (!BN_mul(e.get(), e.get(), a.get(), ctx)) {
+    while (!BN_is_zero(b.get())) {
+      if (!BN_mul(e.get(), e.get(), a.get(), ctx) ||
+          !BN_sub(b.get(), b.get(), BN_value_one())) {
         return false;
       }
     }
@@ -1371,7 +1431,7 @@
   return true;
 }
 
-static bool test_bn2bin_padded(FILE *fp, BN_CTX *ctx) {
+static bool test_bn2bin_padded(BN_CTX *ctx) {
   uint8_t zeros[256], out[256], reference[128];
 
   memset(zeros, 0, sizeof(zeros));
@@ -1448,7 +1508,7 @@
   return ret;
 }
 
-static bool test_dec2bn(FILE *fp, BN_CTX *ctx) {
+static bool test_dec2bn(BN_CTX *ctx) {
   ScopedBIGNUM bn;
   int ret = DecimalToBIGNUM(&bn, "0");
   if (ret != 1 || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) {
@@ -1490,7 +1550,7 @@
   return ret;
 }
 
-static bool test_hex2bn(FILE *fp, BN_CTX *ctx) {
+static bool test_hex2bn(BN_CTX *ctx) {
   ScopedBIGNUM bn;
   int ret = HexToBIGNUM(&bn, "0");
   if (ret != 1 || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) {
@@ -1533,7 +1593,7 @@
   return ScopedBIGNUM(raw);
 }
 
-static bool test_asc2bn(FILE *fp, BN_CTX *ctx) {
+static bool test_asc2bn(BN_CTX *ctx) {
   ScopedBIGNUM bn = ASCIIToBIGNUM("0");
   if (!bn || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) {
     fprintf(stderr, "BN_asc2bn gave a bad result.\n");
@@ -1585,6 +1645,63 @@
   return true;
 }
 
+struct MPITest {
+  const char *base10;
+  const char *mpi;
+  size_t mpi_len;
+};
+
+static const MPITest kMPITests[] = {
+  { "0", "\x00\x00\x00\x00", 4 },
+  { "1", "\x00\x00\x00\x01\x01", 5 },
+  { "-1", "\x00\x00\x00\x01\x81", 5 },
+  { "128", "\x00\x00\x00\x02\x00\x80", 6 },
+  { "256", "\x00\x00\x00\x02\x01\x00", 6 },
+  { "-256", "\x00\x00\x00\x02\x81\x00", 6 },
+};
+
+static bool test_mpi() {
+  uint8_t scratch[8];
+
+  for (size_t i = 0; i < sizeof(kMPITests) / sizeof(kMPITests[0]); i++) {
+    const MPITest &test = kMPITests[i];
+    ScopedBIGNUM bn(ASCIIToBIGNUM(test.base10));
+    const size_t mpi_len = BN_bn2mpi(bn.get(), NULL);
+    if (mpi_len > sizeof(scratch)) {
+      fprintf(stderr, "MPI test #%u: MPI size is too large to test.\n",
+              (unsigned)i);
+      return false;
+    }
+
+    const size_t mpi_len2 = BN_bn2mpi(bn.get(), scratch);
+    if (mpi_len != mpi_len2) {
+      fprintf(stderr, "MPI test #%u: length changes.\n", (unsigned)i);
+      return false;
+    }
+
+    if (mpi_len != test.mpi_len ||
+        memcmp(test.mpi, scratch, mpi_len) != 0) {
+      fprintf(stderr, "MPI test #%u failed:\n", (unsigned)i);
+      hexdump(stderr, "Expected: ", test.mpi, test.mpi_len);
+      hexdump(stderr, "Got:      ", scratch, mpi_len);
+      return false;
+    }
+
+    ScopedBIGNUM bn2(BN_mpi2bn(scratch, mpi_len, NULL));
+    if (bn2.get() == nullptr) {
+      fprintf(stderr, "MPI test #%u: failed to parse\n", (unsigned)i);
+      return false;
+    }
+
+    if (BN_cmp(bn.get(), bn2.get()) != 0) {
+      fprintf(stderr, "MPI test #%u: wrong result\n", (unsigned)i);
+      return false;
+    }
+  }
+
+  return true;
+}
+
 static bool test_rand() {
   ScopedBIGNUM bn(BN_new());
   if (!bn) {
@@ -1628,3 +1745,170 @@
 
   return true;
 }
+
+struct ASN1Test {
+  const char *value_ascii;
+  const char *der;
+  size_t der_len;
+};
+
+static const ASN1Test kASN1Tests[] = {
+    {"0", "\x02\x01\x00", 3},
+    {"1", "\x02\x01\x01", 3},
+    {"127", "\x02\x01\x7f", 3},
+    {"128", "\x02\x02\x00\x80", 4},
+    {"0xdeadbeef", "\x02\x05\x00\xde\xad\xbe\xef", 7},
+    {"0x0102030405060708",
+     "\x02\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10},
+    {"0xffffffffffffffff",
+      "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11},
+};
+
+struct ASN1InvalidTest {
+  const char *der;
+  size_t der_len;
+};
+
+static const ASN1InvalidTest kASN1InvalidTests[] = {
+    // Bad tag.
+    {"\x03\x01\x00", 3},
+    // Empty contents.
+    {"\x02\x00", 2},
+};
+
+// kASN1BuggyTests are incorrect encodings and how |BN_cbs2unsigned_buggy|
+// should interpret them.
+static const ASN1Test kASN1BuggyTests[] = {
+    // Negative numbers.
+    {"128", "\x02\x01\x80", 3},
+    {"255", "\x02\x01\xff", 3},
+    // Unnecessary leading zeros.
+    {"1", "\x02\x02\x00\x01", 4},
+};
+
+static bool test_asn1() {
+  for (const ASN1Test &test : kASN1Tests) {
+    ScopedBIGNUM bn = ASCIIToBIGNUM(test.value_ascii);
+    if (!bn) {
+      return false;
+    }
+
+    // Test that the input is correctly parsed.
+    ScopedBIGNUM bn2(BN_new());
+    if (!bn2) {
+      return false;
+    }
+    CBS cbs;
+    CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
+    if (!BN_cbs2unsigned(&cbs, bn2.get()) || CBS_len(&cbs) != 0) {
+      fprintf(stderr, "Parsing ASN.1 INTEGER failed.\n");
+      return false;
+    }
+    if (BN_cmp(bn.get(), bn2.get()) != 0) {
+      fprintf(stderr, "Bad parse.\n");
+      return false;
+    }
+
+    // Test the value serializes correctly.
+    CBB cbb;
+    uint8_t *der;
+    size_t der_len;
+    CBB_zero(&cbb);
+    if (!CBB_init(&cbb, 0) ||
+        !BN_bn2cbb(&cbb, bn.get()) ||
+        !CBB_finish(&cbb, &der, &der_len)) {
+      CBB_cleanup(&cbb);
+      return false;
+    }
+    ScopedOpenSSLBytes delete_der(der);
+    if (der_len != test.der_len ||
+        memcmp(der, reinterpret_cast<const uint8_t*>(test.der), der_len) != 0) {
+      fprintf(stderr, "Bad serialization.\n");
+      return false;
+    }
+
+    // |BN_cbs2unsigned_buggy| parses all valid input.
+    CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
+    if (!BN_cbs2unsigned_buggy(&cbs, bn2.get()) || CBS_len(&cbs) != 0) {
+      fprintf(stderr, "Parsing ASN.1 INTEGER failed.\n");
+      return false;
+    }
+    if (BN_cmp(bn.get(), bn2.get()) != 0) {
+      fprintf(stderr, "Bad parse.\n");
+      return false;
+    }
+  }
+
+  for (const ASN1InvalidTest &test : kASN1InvalidTests) {
+    ScopedBIGNUM bn(BN_new());
+    if (!bn) {
+      return false;
+    }
+    CBS cbs;
+    CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
+    if (BN_cbs2unsigned(&cbs, bn.get())) {
+      fprintf(stderr, "Parsed invalid input.\n");
+      return false;
+    }
+    ERR_clear_error();
+
+    // All tests in kASN1InvalidTests are also rejected by
+    // |BN_cbs2unsigned_buggy|.
+    CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
+    if (BN_cbs2unsigned_buggy(&cbs, bn.get())) {
+      fprintf(stderr, "Parsed invalid input.\n");
+      return false;
+    }
+    ERR_clear_error();
+  }
+
+  for (const ASN1Test &test : kASN1BuggyTests) {
+    // These broken encodings are rejected by |BN_cbs2unsigned|.
+    ScopedBIGNUM bn(BN_new());
+    if (!bn) {
+      return false;
+    }
+
+    CBS cbs;
+    CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
+    if (BN_cbs2unsigned(&cbs, bn.get())) {
+      fprintf(stderr, "Parsed invalid input.\n");
+      return false;
+    }
+    ERR_clear_error();
+
+    // However |BN_cbs2unsigned_buggy| accepts them.
+    ScopedBIGNUM bn2 = ASCIIToBIGNUM(test.value_ascii);
+    if (!bn2) {
+      return false;
+    }
+
+    CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
+    if (!BN_cbs2unsigned_buggy(&cbs, bn.get()) || CBS_len(&cbs) != 0) {
+      fprintf(stderr, "Parsing (invalid) ASN.1 INTEGER failed.\n");
+      return false;
+    }
+
+    if (BN_cmp(bn.get(), bn2.get()) != 0) {
+      fprintf(stderr, "\"Bad\" parse.\n");
+      return false;
+    }
+  }
+
+  // Serializing negative numbers is not supported.
+  ScopedBIGNUM bn = ASCIIToBIGNUM("-1");
+  if (!bn) {
+    return false;
+  }
+  CBB cbb;
+  CBB_zero(&cbb);
+  if (!CBB_init(&cbb, 0) ||
+      BN_bn2cbb(&cbb, bn.get())) {
+    fprintf(stderr, "Serialized negative number.\n");
+    CBB_cleanup(&cbb);
+    return false;
+  }
+  CBB_cleanup(&cbb);
+
+  return true;
+}
diff --git a/src/crypto/bn/convert.c b/src/crypto/bn/convert.c
index 531b661..0122709 100644
--- a/src/crypto/bn/convert.c
+++ b/src/crypto/bn/convert.c
@@ -56,7 +56,9 @@
 
 #include <openssl/bn.h>
 
+#include <assert.h>
 #include <ctype.h>
+#include <limits.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -67,7 +69,8 @@
 #include "internal.h"
 
 BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
-  unsigned num_words, m;
+  size_t num_words;
+  unsigned m;
   BN_ULONG word = 0;
   BIGNUM *bn = NULL;
 
@@ -93,7 +96,10 @@
     return NULL;
   }
 
-  ret->top = num_words;
+  /* |bn_wexpand| must check bounds on |num_words| to write it into
+   * |ret->dmax|. */
+  assert(num_words <= INT_MAX);
+  ret->top = (int)num_words;
   ret->neg = 0;
 
   while (len--) {
@@ -198,7 +204,7 @@
 
   buf = (char *)OPENSSL_malloc(bn->top * BN_BYTES * 2 + 2);
   if (buf == NULL) {
-    OPENSSL_PUT_ERROR(BN, BN_bn2hex, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -227,47 +233,59 @@
   return buf;
 }
 
-/* decode_hex decodes |i| bytes of hex data from |in| and updates |bn|. */
-static void decode_hex(BIGNUM *bn, const char *in, int i) {
-  int h, m, j, k, c;
-  BN_ULONG l=0;
-
-  j = i; /* least significant 'hex' */
-  h = 0;
-  while (j > 0) {
-    m = ((BN_BYTES * 2) <= j) ? (BN_BYTES * 2) : j;
-    l = 0;
-    for (;;) {
-      c = in[j - m];
-      if ((c >= '0') && (c <= '9')) {
-        k = c - '0';
-      } else if ((c >= 'a') && (c <= 'f')) {
-        k = c - 'a' + 10;
-      } else if ((c >= 'A') && (c <= 'F')) {
-        k = c - 'A' + 10;
-      } else {
-        k = 0; /* paranoia */
-      }
-
-      l = (l << 4) | k;
-
-      if (--m <= 0) {
-        bn->d[h++] = l;
-        break;
-      }
-    }
-
-    j -= (BN_BYTES * 2);
+/* decode_hex decodes |in_len| bytes of hex data from |in| and updates |bn|. */
+static int decode_hex(BIGNUM *bn, const char *in, int in_len) {
+  if (in_len > INT_MAX/4) {
+    OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
+    return 0;
+  }
+  /* |in_len| is the number of hex digits. */
+  if (bn_expand(bn, in_len * 4) == NULL) {
+    return 0;
   }
 
-  bn->top = h;
+  int i = 0;
+  while (in_len > 0) {
+    /* Decode one |BN_ULONG| at a time. */
+    int todo = BN_BYTES * 2;
+    if (todo > in_len) {
+      todo = in_len;
+    }
+
+    BN_ULONG word = 0;
+    int j;
+    for (j = todo; j > 0; j--) {
+      char c = in[in_len - j];
+
+      BN_ULONG hex;
+      if (c >= '0' && c <= '9') {
+        hex = c - '0';
+      } else if (c >= 'a' && c <= 'f') {
+        hex = c - 'a' + 10;
+      } else if (c >= 'A' && c <= 'F') {
+        hex = c - 'A' + 10;
+      } else {
+        hex = 0;
+        /* This shouldn't happen. The caller checks |isxdigit|. */
+        assert(0);
+      }
+      word = (word << 4) | hex;
+    }
+
+    bn->d[i++] = word;
+    in_len -= todo;
+  }
+  assert(i <= bn->dmax);
+  bn->top = i;
+  return 1;
 }
 
 /* decode_dec decodes |in_len| bytes of decimal data from |in| and updates |bn|. */
-static void decode_dec(BIGNUM *bn, const char *in, int in_len) {
+static int decode_dec(BIGNUM *bn, const char *in, int in_len) {
   int i, j;
   BN_ULONG l = 0;
 
+  /* Decode |BN_DEC_NUM| digits at a time. */
   j = BN_DEC_NUM - (in_len % BN_DEC_NUM);
   if (j == BN_DEC_NUM) {
     j = 0;
@@ -277,15 +295,18 @@
     l *= 10;
     l += in[i] - '0';
     if (++j == BN_DEC_NUM) {
-      BN_mul_word(bn, BN_DEC_CONV);
-      BN_add_word(bn, l);
+      if (!BN_mul_word(bn, BN_DEC_CONV) ||
+          !BN_add_word(bn, l)) {
+        return 0;
+      }
       l = 0;
       j = 0;
     }
   }
+  return 1;
 }
 
-typedef void (*decode_func) (BIGNUM *bn, const char *in, int i);
+typedef int (*decode_func) (BIGNUM *bn, const char *in, int in_len);
 typedef int (*char_test_func) (int c);
 
 static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_func want_char) {
@@ -302,7 +323,7 @@
     in++;
   }
 
-  for (i = 0; want_char((unsigned char)in[i]); i++) {}
+  for (i = 0; want_char((unsigned char)in[i]) && i + neg < INT_MAX; i++) {}
 
   num = i + neg;
   if (outp == NULL) {
@@ -320,13 +341,10 @@
     BN_zero(ret);
   }
 
-  /* i is the number of hex digests; */
-  if (bn_expand(ret, i * 4) == NULL) {
+  if (!decode(ret, in, i)) {
     goto err;
   }
 
-  decode(ret, in, i);
-
   bn_correct_top(ret);
   if (!BN_is_zero(ret)) {
     ret->neg = neg;
@@ -365,7 +383,7 @@
       (BN_ULONG *)OPENSSL_malloc((num / BN_DEC_NUM + 1) * sizeof(BN_ULONG));
   buf = (char *)OPENSSL_malloc(num + 3);
   if ((buf == NULL) || (bn_data == NULL)) {
-    OPENSSL_PUT_ERROR(BN, BN_bn2dec, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
     goto err;
   }
   t = BN_dup(a);
@@ -499,3 +517,81 @@
       return BN_MASK2;
   }
 }
+
+size_t BN_bn2mpi(const BIGNUM *in, uint8_t *out) {
+  const size_t bits = BN_num_bits(in);
+  const size_t bytes = (bits + 7) / 8;
+  /* If the number of bits is a multiple of 8, i.e. if the MSB is set,
+   * prefix with a zero byte. */
+  int extend = 0;
+  if (bytes != 0 && (bits & 0x07) == 0) {
+    extend = 1;
+  }
+
+  const size_t len = bytes + extend;
+  if (len < bytes ||
+      4 + len < len ||
+      (len & 0xffffffff) != len) {
+    /* If we cannot represent the number then we emit zero as the interface
+     * doesn't allow an error to be signalled. */
+    if (out) {
+      memset(out, 0, 4);
+    }
+    return 4;
+  }
+
+  if (out == NULL) {
+    return 4 + len;
+  }
+
+  out[0] = len >> 24;
+  out[1] = len >> 16;
+  out[2] = len >> 8;
+  out[3] = len;
+  if (extend) {
+    out[4] = 0;
+  }
+  BN_bn2bin(in, out + 4 + extend);
+  if (in->neg && len > 0) {
+    out[4] |= 0x80;
+  }
+  return len + 4;
+}
+
+BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) {
+  if (len < 4) {
+    OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
+    return NULL;
+  }
+  const size_t in_len = ((size_t)in[0] << 24) |
+                        ((size_t)in[1] << 16) |
+                        ((size_t)in[2] << 8) |
+                        ((size_t)in[3]);
+  if (in_len != len - 4) {
+    OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
+    return NULL;
+  }
+
+  if (out == NULL) {
+    out = BN_new();
+  }
+  if (out == NULL) {
+    OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
+    return NULL;
+  }
+
+  if (in_len == 0) {
+    BN_zero(out);
+    return out;
+  }
+
+  in += 4;
+  if (BN_bin2bn(in, in_len, out) == NULL) {
+    return NULL;
+  }
+  out->neg = ((*in) & 0x80) != 0;
+  if (out->neg) {
+    BN_clear_bit(out, BN_num_bits(out) - 1);
+  }
+  return out;
+}
diff --git a/src/crypto/bn/ctx.c b/src/crypto/bn/ctx.c
index 0578376..48d9adf 100644
--- a/src/crypto/bn/ctx.c
+++ b/src/crypto/bn/ctx.c
@@ -124,7 +124,7 @@
 BN_CTX *BN_CTX_new(void) {
   BN_CTX *ret = OPENSSL_malloc(sizeof(BN_CTX));
   if (!ret) {
-    OPENSSL_PUT_ERROR(BN, BN_CTX_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -153,7 +153,7 @@
     ctx->err_stack++;
   } else if (!BN_STACK_push(&ctx->stack, ctx->used)) {
     /* (Try to) get a new frame pointer */
-    OPENSSL_PUT_ERROR(BN, BN_CTX_start, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
+    OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
     ctx->err_stack++;
   }
 }
@@ -169,7 +169,7 @@
     /* Setting too_many prevents repeated "get" attempts from
      * cluttering the error stack. */
     ctx->too_many = 1;
-    OPENSSL_PUT_ERROR(BN, BN_CTX_get, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
+    OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
     return NULL;
   }
 
diff --git a/src/crypto/bn/div.c b/src/crypto/bn/div.c
index 3588ea1..779dda2 100644
--- a/src/crypto/bn/div.c
+++ b/src/crypto/bn/div.c
@@ -125,7 +125,7 @@
    * so don't just rely on bn_check_top() here */
   if ((num->top > 0 && num->d[num->top - 1] == 0) ||
       (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
-    OPENSSL_PUT_ERROR(BN, BN_div, BN_R_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED);
     return 0;
   }
 
@@ -135,7 +135,7 @@
   }
 
   if (BN_is_zero(divisor)) {
-    OPENSSL_PUT_ERROR(BN, BN_div, BN_R_DIV_BY_ZERO);
+    OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO);
     return 0;
   }
 
@@ -511,7 +511,7 @@
     /* max_shift >= 0 */
 
     if (max_shift < 0) {
-      OPENSSL_PUT_ERROR(BN, BN_mod_lshift_quick, BN_R_INPUT_NOT_REDUCED);
+      OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED);
       return 0;
     }
 
diff --git a/src/crypto/bn/exponentiation.c b/src/crypto/bn/exponentiation.c
index d3063c9..6c5e11b 100644
--- a/src/crypto/bn/exponentiation.c
+++ b/src/crypto/bn/exponentiation.c
@@ -131,7 +131,7 @@
 
   if ((p->flags & BN_FLG_CONSTTIME) != 0) {
     /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
-    OPENSSL_PUT_ERROR(BN, BN_exp, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
 
@@ -173,8 +173,8 @@
     }
   }
 
-  if (r != rr) {
-    BN_copy(r, rr);
+  if (r != rr && !BN_copy(r, rr)) {
+    goto err;
   }
   ret = 1;
 
@@ -333,7 +333,7 @@
   j = 0;
   while (BN_ucmp(r, &(recp->N)) >= 0) {
     if (j++ > 2) {
-      OPENSSL_PUT_ERROR(BN, BN_div_recp, BN_R_BAD_RECIPROCAL);
+      OPENSSL_PUT_ERROR(BN, BN_R_BAD_RECIPROCAL);
       goto err;
     }
     if (!BN_usub(r, r, &(recp->N))) {
@@ -427,7 +427,7 @@
 
   if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
     /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
-    OPENSSL_PUT_ERROR(BN, mod_exp_recp, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
 
@@ -616,7 +616,7 @@
   }
 
   if (!BN_is_odd(m)) {
-    OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont, BN_R_CALLED_WITH_EVEN_MODULUS);
+    OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
     return 0;
   }
   bits = BN_num_bits(p);
@@ -862,13 +862,13 @@
   unsigned char *powerbuf = NULL;
   BIGNUM tmp, am;
 
-  top = m->top;
-
-  if (!(m->d[0] & 1)) {
-    OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont_consttime,
-                      BN_R_CALLED_WITH_EVEN_MODULUS);
+  if (!BN_is_odd(m)) {
+    OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
     return 0;
   }
+
+  top = m->top;
+
   bits = BN_num_bits(p);
   if (bits == 0) {
     ret = BN_one(rr);
@@ -926,7 +926,6 @@
     }
   }
 #endif
-  (void)0;
 
   /* Allocate a buffer large enough to hold all of the pre-computed
    * powers of am, am itself and tmp.
@@ -1223,13 +1222,12 @@
 
   if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
     /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
-    OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont_word,
-        ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
 
   if (!BN_is_odd(m)) {
-    OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont_word, BN_R_CALLED_WITH_EVEN_MODULUS);
+    OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
     return 0;
   }
 
@@ -1372,7 +1370,7 @@
   BN_MONT_CTX *mont = NULL;
 
   if (!(m->d[0] & 1)) {
-    OPENSSL_PUT_ERROR(BN, BN_mod_exp2_mont, BN_R_CALLED_WITH_EVEN_MODULUS);
+    OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
     return 0;
   }
   bits1 = BN_num_bits(p1);
diff --git a/src/crypto/bn/gcd.c b/src/crypto/bn/gcd.c
index 3132c29..e106149 100644
--- a/src/crypto/bn/gcd.c
+++ b/src/crypto/bn/gcd.c
@@ -223,20 +223,23 @@
 }
 
 /* solves ax == 1 (mod n) */
-static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, const BIGNUM *a,
-                                        const BIGNUM *n, BN_CTX *ctx);
+static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse,
+                                        const BIGNUM *a, const BIGNUM *n,
+                                        BN_CTX *ctx);
 
-BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n,
-                       BN_CTX *ctx) {
+BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
+                          const BIGNUM *n, BN_CTX *ctx) {
   BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
   BIGNUM *ret = NULL;
   int sign;
 
   if ((a->flags & BN_FLG_CONSTTIME) != 0 ||
       (n->flags & BN_FLG_CONSTTIME) != 0) {
-    return BN_mod_inverse_no_branch(out, a, n, ctx);
+    return BN_mod_inverse_no_branch(out, out_no_inverse, a, n, ctx);
   }
 
+  *out_no_inverse = 0;
+
   BN_CTX_start(ctx);
   A = BN_CTX_get(ctx);
   B = BN_CTX_get(ctx);
@@ -522,7 +525,8 @@
       }
     }
   } else {
-    OPENSSL_PUT_ERROR(BN, BN_mod_inverse, BN_R_NO_INVERSE);
+    *out_no_inverse = 1;
+    OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
     goto err;
   }
   ret = R;
@@ -535,16 +539,25 @@
   return ret;
 }
 
+BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n,
+                       BN_CTX *ctx) {
+  int no_inverse;
+  return BN_mod_inverse_ex(out, &no_inverse, a, n, ctx);
+}
+
 /* BN_mod_inverse_no_branch is a special version of BN_mod_inverse.
  * It does not contain branches that may leak sensitive information. */
-static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, const BIGNUM *a,
-                                        const BIGNUM *n, BN_CTX *ctx) {
+static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse,
+                                        const BIGNUM *a, const BIGNUM *n,
+                                        BN_CTX *ctx) {
   BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
   BIGNUM local_A, local_B;
   BIGNUM *pA, *pB;
   BIGNUM *ret = NULL;
   int sign;
 
+  *out_no_inverse = 0;
+
   BN_CTX_start(ctx);
   A = BN_CTX_get(ctx);
   B = BN_CTX_get(ctx);
@@ -682,7 +695,8 @@
       }
     }
   } else {
-    OPENSSL_PUT_ERROR(BN, BN_mod_inverse_no_branch, BN_R_NO_INVERSE);
+    *out_no_inverse = 1;
+    OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
     goto err;
   }
   ret = R;
diff --git a/src/crypto/bn/internal.h b/src/crypto/bn/internal.h
index 2674b3c..0d0eb44 100644
--- a/src/crypto/bn/internal.h
+++ b/src/crypto/bn/internal.h
@@ -136,9 +136,9 @@
 extern "C" {
 #endif
 
-/* bn_expand acts the same as |BN_wexpand|, but takes a number of bits rather
+/* bn_expand acts the same as |bn_wexpand|, but takes a number of bits rather
  * than a number of words. */
-BIGNUM *bn_expand(BIGNUM *bn, unsigned bits);
+BIGNUM *bn_expand(BIGNUM *bn, size_t bits);
 
 #if defined(OPENSSL_64_BIT)
 
diff --git a/src/crypto/bn/montgomery.c b/src/crypto/bn/montgomery.c
index 152cf2d..c6c9c88 100644
--- a/src/crypto/bn/montgomery.c
+++ b/src/crypto/bn/montgomery.c
@@ -110,6 +110,7 @@
 
 #include <string.h>
 
+#include <openssl/err.h>
 #include <openssl/mem.h>
 #include <openssl/thread.h>
 
@@ -176,6 +177,11 @@
   BIGNUM tmod;
   BN_ULONG buf[2];
 
+  if (BN_is_zero(mod)) {
+    OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO);
+    return 0;
+  }
+
   BN_CTX_start(ctx);
   Ri = BN_CTX_get(ctx);
   if (Ri == NULL) {
diff --git a/src/crypto/bn/mul.c b/src/crypto/bn/mul.c
index a17d766..029a59e 100644
--- a/src/crypto/bn/mul.c
+++ b/src/crypto/bn/mul.c
@@ -666,8 +666,8 @@
 
 end:
   bn_correct_top(rr);
-  if (r != rr) {
-    BN_copy(r, rr);
+  if (r != rr && !BN_copy(r, rr)) {
+    goto err;
   }
   ret = 1;
 
@@ -877,8 +877,8 @@
     rr->top = max;
   }
 
-  if (rr != r) {
-    BN_copy(r, rr);
+  if (rr != r && !BN_copy(r, rr)) {
+    goto err;
   }
   ret = 1;
 
diff --git a/src/crypto/bn/prime.c b/src/crypto/bn/prime.c
index cf3afcf..bbb8fe0 100644
--- a/src/crypto/bn/prime.c
+++ b/src/crypto/bn/prime.c
@@ -362,11 +362,11 @@
 
   if (bits < 2) {
     /* There are no prime numbers this small. */
-    OPENSSL_PUT_ERROR(BN, BN_generate_prime_ex, BN_R_BITS_TOO_SMALL);
+    OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);
     return 0;
   } else if (bits == 2 && safe) {
     /* The smallest safe prime (7) is three bits. */
-    OPENSSL_PUT_ERROR(BN, BN_generate_prime_ex, BN_R_BITS_TOO_SMALL);
+    OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);
     return 0;
   }
 
@@ -515,11 +515,10 @@
 
   /* A := abs(a) */
   if (a->neg) {
-    BIGNUM *t;
-    if ((t = BN_CTX_get(ctx)) == NULL) {
+    BIGNUM *t = BN_CTX_get(ctx);
+    if (t == NULL || !BN_copy(t, a)) {
       goto err;
     }
-    BN_copy(t, a);
     t->neg = 0;
     A = t;
   } else {
diff --git a/src/crypto/bn/random.c b/src/crypto/bn/random.c
index 549ac48..3116e54 100644
--- a/src/crypto/bn/random.c
+++ b/src/crypto/bn/random.c
@@ -134,7 +134,7 @@
 
   buf = OPENSSL_malloc(bytes);
   if (buf == NULL) {
-    OPENSSL_PUT_ERROR(BN, BN_rand, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -186,7 +186,7 @@
   unsigned count = 100;
 
   if (range->neg || BN_is_zero(range)) {
-    OPENSSL_PUT_ERROR(BN, BN_rand_range, BN_R_INVALID_RANGE);
+    OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE);
     return 0;
   }
 
@@ -219,7 +219,7 @@
       }
 
       if (!--count) {
-        OPENSSL_PUT_ERROR(BN, BN_rand_range, BN_R_TOO_MANY_ITERATIONS);
+        OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
         return 0;
       }
     } while (BN_cmp(r, range) >= 0);
@@ -231,7 +231,7 @@
       }
 
       if (!--count) {
-        OPENSSL_PUT_ERROR(BN, BN_rand_range, BN_R_TOO_MANY_ITERATIONS);
+        OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
         return 0;
       }
     } while (BN_cmp(r, range) >= 0);
@@ -264,13 +264,13 @@
   }
 
   if (BN_is_zero(range)) {
-    OPENSSL_PUT_ERROR(BN, BN_generate_dsa_nonce, BN_R_DIV_BY_ZERO);
+    OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO);
     goto err;
   }
 
   k_bytes = OPENSSL_malloc(num_k_bytes);
   if (!k_bytes) {
-    OPENSSL_PUT_ERROR(BN, BN_generate_dsa_nonce, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -281,7 +281,7 @@
     /* No reasonable DSA or ECDSA key should have a private key
      * this large and we don't handle this case in order to avoid
      * leaking the length of the private key. */
-    OPENSSL_PUT_ERROR(BN, BN_generate_dsa_nonce, BN_R_PRIVATE_KEY_TOO_LARGE);
+    OPENSSL_PUT_ERROR(BN, BN_R_PRIVATE_KEY_TOO_LARGE);
     goto err;
   }
   memcpy(private_bytes, priv->d, todo);
diff --git a/src/crypto/bn/rsaz_exp.h b/src/crypto/bn/rsaz_exp.h
index 0bb6b0c..c752b45 100644
--- a/src/crypto/bn/rsaz_exp.h
+++ b/src/crypto/bn/rsaz_exp.h
@@ -1,32 +1,44 @@
-/******************************************************************************
-* Copyright(c) 2012, Intel Corp.                                             
-* Developers and authors:                                                    
-* Shay Gueron (1, 2), and Vlad Krasnov (1)                                   
-* (1) Intel Corporation, Israel Development Center, Haifa, Israel                               
-* (2) University of Haifa, Israel                                              
+/*****************************************************************************
+*                                                                            *
+*  Copyright (c) 2012, Intel Corporation                                     *
+*                                                                            *
+*  All rights reserved.                                                      *
+*                                                                            *
+*  Redistribution and use in source and binary forms, with or without        *
+*  modification, are permitted provided that the following conditions are    *
+*  met:                                                                      *
+*                                                                            *
+*  *  Redistributions of source code must retain the above copyright         *
+*     notice, this list of conditions and the following disclaimer.          *
+*                                                                            *
+*  *  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.                                                          *
+*                                                                            *
+*  *  Neither the name of the Intel Corporation nor the names of its         *
+*     contributors may be used to endorse or promote products derived from   *
+*     this software without specific prior written permission.               *
+*                                                                            *
+*                                                                            *
+*  THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""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 INTEL CORPORATION 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.              *
+*                                                                            *
 ******************************************************************************
-* LICENSE:                                                                
-* This submission to OpenSSL is to be made available under the OpenSSL  
-* license, and only to the OpenSSL project, in order to allow integration    
-* into the publicly distributed code. 
-* The use of this code, or portions of this code, or concepts embedded in
-* this code, or modification of this code and/or algorithm(s) in it, or the
-* use of this code for any other purpose than stated above, requires special
-* licensing.                                                                  
-******************************************************************************
-* DISCLAIMER:                                                                
-* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS AND THE COPYRIGHT OWNERS     
-* ``AS IS''. ANY EXPRESSED 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 CONTRIBUTORS OR THE COPYRIGHT
-* OWNERS 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.                                                
-******************************************************************************/
+* Developers and authors:                                                    *
+* Shay Gueron (1, 2), and Vlad Krasnov (1)                                   *
+* (1) Intel Corporation, Israel Development Center, Haifa, Israel            *
+* (2) University of Haifa, Israel                                            *
+*****************************************************************************/
 
 #ifndef RSAZ_EXP_H
 #define RSAZ_EXP_H
diff --git a/src/crypto/bn/shift.c b/src/crypto/bn/shift.c
index f143996..defec92 100644
--- a/src/crypto/bn/shift.c
+++ b/src/crypto/bn/shift.c
@@ -69,7 +69,7 @@
   BN_ULONG l;
 
   if (n < 0) {
-    OPENSSL_PUT_ERROR(BN, BN_lshift, BN_R_NEGATIVE_NUMBER);
+    OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
     return 0;
   }
 
@@ -138,7 +138,7 @@
   BN_ULONG l, tmp;
 
   if (n < 0) {
-    OPENSSL_PUT_ERROR(BN, BN_rshift, BN_R_NEGATIVE_NUMBER);
+    OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
     return 0;
   }
 
diff --git a/src/crypto/bn/sqrt.c b/src/crypto/bn/sqrt.c
index e71a818..2ed66c2 100644
--- a/src/crypto/bn/sqrt.c
+++ b/src/crypto/bn/sqrt.c
@@ -86,7 +86,7 @@
       return ret;
     }
 
-    OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_P_IS_NOT_PRIME);
+    OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME);
     return (NULL);
   }
 
@@ -260,7 +260,7 @@
     }
     if (r == 0) {
       /* m divides p */
-      OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_P_IS_NOT_PRIME);
+      OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME);
       goto end;
     }
   } while (r == 1 && ++i < 82);
@@ -271,7 +271,7 @@
      * Even if  p  is not prime, we should have found some  y
      * such that r == -1.
      */
-    OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_TOO_MANY_ITERATIONS);
+    OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
     goto end;
   }
 
@@ -286,7 +286,7 @@
     goto end;
   }
   if (BN_is_one(y)) {
-    OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_P_IS_NOT_PRIME);
+    OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME);
     goto end;
   }
 
@@ -377,7 +377,7 @@
     while (!BN_is_one(t)) {
       i++;
       if (i == e) {
-        OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_NOT_A_SQUARE);
+        OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE);
         goto end;
       }
       if (!BN_mod_mul(t, t, t, p, ctx)) {
@@ -413,7 +413,7 @@
     }
 
     if (!err && 0 != BN_cmp(x, A)) {
-      OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_NOT_A_SQUARE);
+      OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE);
       err = 1;
     }
   }
@@ -434,7 +434,7 @@
   int ok = 0, last_delta_valid = 0;
 
   if (in->neg) {
-    OPENSSL_PUT_ERROR(BN, BN_sqrt, BN_R_NEGATIVE_NUMBER);
+    OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
     return 0;
   }
   if (BN_is_zero(in)) {
@@ -452,7 +452,7 @@
   last_delta = BN_CTX_get(ctx);
   delta = BN_CTX_get(ctx);
   if (estimate == NULL || tmp == NULL || last_delta == NULL || delta == NULL) {
-    OPENSSL_PUT_ERROR(BN, BN_sqrt, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -470,7 +470,7 @@
         !BN_sqr(tmp, estimate, ctx) ||
         /* |delta| = |in| - |tmp| */
         !BN_sub(delta, in, tmp)) {
-      OPENSSL_PUT_ERROR(BN, BN_sqrt, ERR_R_BN_LIB);
+      OPENSSL_PUT_ERROR(BN, ERR_R_BN_LIB);
       goto err;
     }
 
@@ -490,15 +490,15 @@
   }
 
   if (BN_cmp(tmp, in) != 0) {
-    OPENSSL_PUT_ERROR(BN, BN_sqrt, BN_R_NOT_A_SQUARE);
+    OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE);
     goto err;
   }
 
   ok = 1;
 
 err:
-  if (ok && out_sqrt == in) {
-    BN_copy(out_sqrt, estimate);
+  if (ok && out_sqrt == in && !BN_copy(out_sqrt, estimate)) {
+    ok = 0;
   }
   BN_CTX_end(ctx);
   return ok;
diff --git a/src/crypto/buf/CMakeLists.txt b/src/crypto/buf/CMakeLists.txt
index 19edf7d..63f1025 100644
--- a/src/crypto/buf/CMakeLists.txt
+++ b/src/crypto/buf/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   buf
diff --git a/src/crypto/buf/buf.c b/src/crypto/buf/buf.c
index 5769e77..13b5ceb 100644
--- a/src/crypto/buf/buf.c
+++ b/src/crypto/buf/buf.c
@@ -67,7 +67,7 @@
 
   ret = OPENSSL_malloc(sizeof(BUF_MEM));
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(BUF, BUF_MEM_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -105,14 +105,14 @@
   n = len + 3;
   if (n < len) {
     /* overflow */
-    OPENSSL_PUT_ERROR(BUF, buf_mem_grow, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
     return 0;
   }
   n = n / 3;
   alloc_size = n * 4;
   if (alloc_size / 4 != n) {
     /* overflow */
-    OPENSSL_PUT_ERROR(BUF, buf_mem_grow, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -127,7 +127,7 @@
   }
 
   if (new_buf == NULL) {
-    OPENSSL_PUT_ERROR(BUF, buf_mem_grow, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
     len = 0;
   } else {
     buf->data = new_buf;
@@ -180,12 +180,12 @@
   alloc_size = size + 1;
   if (alloc_size < size) {
     /* overflow */
-    OPENSSL_PUT_ERROR(BUF, BUF_strndup, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
   ret = OPENSSL_malloc(alloc_size);
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(BUF, BUF_strndup, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -226,7 +226,7 @@
 
   ret = OPENSSL_malloc(dst_size);
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(BUF, BUF_memdup, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
diff --git a/src/crypto/bytestring/CMakeLists.txt b/src/crypto/bytestring/CMakeLists.txt
index cbbacf2..3462aee 100644
--- a/src/crypto/bytestring/CMakeLists.txt
+++ b/src/crypto/bytestring/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   bytestring
diff --git a/src/crypto/bytestring/bytestring_test.cc b/src/crypto/bytestring/bytestring_test.cc
index 66e9c1e..e987e1b 100644
--- a/src/crypto/bytestring/bytestring_test.cc
+++ b/src/crypto/bytestring/bytestring_test.cc
@@ -109,7 +109,7 @@
   static const uint8_t kData2[] = {0x30, 3, 1, 2};
   static const uint8_t kData3[] = {0x30, 0x80};
   static const uint8_t kData4[] = {0x30, 0x81, 1, 1};
-  static const uint8_t kData5[] = {0x30, 0x82, 0, 1, 1};
+  static const uint8_t kData5[4 + 0x80] = {0x30, 0x82, 0, 0x80};
   static const uint8_t kData6[] = {0xa1, 3, 0x4, 1, 1};
   static const uint8_t kData7[] = {0xa1, 3, 0x4, 2, 1};
   static const uint8_t kData8[] = {0xa1, 3, 0x2, 1, 1};
@@ -649,6 +649,14 @@
   return true;
 }
 
+static int TestZero() {
+  CBB cbb;
+  CBB_zero(&cbb);
+  // Calling |CBB_cleanup| on a zero-state |CBB| must not crash.
+  CBB_cleanup(&cbb);
+  return 1;
+}
+
 int main(void) {
   CRYPTO_library_init();
 
@@ -665,7 +673,8 @@
       !TestCBBASN1() ||
       !TestBerConvert() ||
       !TestASN1Uint64() ||
-      !TestGetOptionalASN1Bool()) {
+      !TestGetOptionalASN1Bool() ||
+      !TestZero()) {
     return 1;
   }
 
diff --git a/src/crypto/bytestring/cbb.c b/src/crypto/bytestring/cbb.c
index f1e09a2..1da6a21 100644
--- a/src/crypto/bytestring/cbb.c
+++ b/src/crypto/bytestring/cbb.c
@@ -20,6 +20,10 @@
 #include <openssl/mem.h>
 
 
+void CBB_zero(CBB *cbb) {
+  memset(cbb, 0, sizeof(CBB));
+}
+
 static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) {
   struct cbb_buffer_st *base;
 
@@ -243,6 +247,11 @@
   return 1;
 }
 
+size_t CBB_len(const CBB *cbb) {
+  assert(cbb->child == NULL);
+
+  return cbb->base->len;
+}
 
 static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents,
                                    size_t len_len) {
diff --git a/src/crypto/bytestring/cbs.c b/src/crypto/bytestring/cbs.c
index b8caedd..5e0c538 100644
--- a/src/crypto/bytestring/cbs.c
+++ b/src/crypto/bytestring/cbs.c
@@ -137,6 +137,15 @@
   return 1;
 }
 
+int CBS_copy_bytes(CBS *cbs, uint8_t *out, size_t len) {
+  const uint8_t *v;
+  if (!cbs_get(cbs, &v, len)) {
+    return 0;
+  }
+  memcpy(out, v, len);
+  return 1;
+}
+
 static int cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) {
   uint32_t len;
   if (!cbs_get_u(cbs, &len, len_len)) {
@@ -320,14 +329,19 @@
 }
 
 int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
+  int present = 0;
+
   if (CBS_peek_asn1_tag(cbs, tag)) {
     if (!CBS_get_asn1(cbs, out, tag)) {
       return 0;
     }
-    *out_present = 1;
-  } else {
-    *out_present = 0;
+    present = 1;
   }
+
+  if (out_present != NULL) {
+    *out_present = present;
+  }
+
   return 1;
 }
 
diff --git a/src/crypto/bytestring/internal.h b/src/crypto/bytestring/internal.h
index 391ad19..b4ea7e5 100644
--- a/src/crypto/bytestring/internal.h
+++ b/src/crypto/bytestring/internal.h
@@ -38,14 +38,6 @@
  * 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);
 
-/* CBS_get_any_ber_asn1_element acts the same as |CBS_get_any_asn1_element| but
- * also allows indefinite-length elements to be returned. In that case,
- * |*out_header_len| and |CBS_len(out)| will both be two as only the header is
- * returned. */
-OPENSSL_EXPORT int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out,
-                                                unsigned *out_tag,
-                                                size_t *out_header_len);
-
 
 #if defined(__cplusplus)
 }  /* extern C */
diff --git a/src/crypto/chacha/CMakeLists.txt b/src/crypto/chacha/CMakeLists.txt
index 6c3f87e..266e869 100644
--- a/src/crypto/chacha/CMakeLists.txt
+++ b/src/crypto/chacha/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 if (${ARCH} STREQUAL "arm")
   set(
diff --git a/src/crypto/chacha/chacha_vec_arm.S b/src/crypto/chacha/chacha_vec_arm.S
index ddc374e..0f82627 100644
--- a/src/crypto/chacha/chacha_vec_arm.S
+++ b/src/crypto/chacha/chacha_vec_arm.S
@@ -23,6 +23,7 @@
 #     /opt/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc -O3 -mcpu=cortex-a8 -mfpu=neon -fpic -DASM_GEN -I ../../include -S chacha_vec.c -o -
 
 #if !defined(OPENSSL_NO_ASM)
+#if defined(__arm__) || defined(__aarch64__)
 
 	.syntax unified
 	.cpu cortex-a8
@@ -1423,4 +1424,5 @@
 	.ident	"GCC: (Linaro GCC 2014.11) 4.9.3 20141031 (prerelease)"
 	.section	.note.GNU-stack,"",%progbits
 
+#endif  /* __arm__ || __aarch64__ */
 #endif  /* !OPENSSL_NO_ASM */
diff --git a/src/crypto/chacha/chacha_vec_arm_generate.go b/src/crypto/chacha/chacha_vec_arm_generate.go
index d681e8a..6d167b9 100644
--- a/src/crypto/chacha/chacha_vec_arm_generate.go
+++ b/src/crypto/chacha/chacha_vec_arm_generate.go
@@ -52,7 +52,8 @@
 	output.WriteString(compiler)
 	output.WriteString(" ")
 	output.WriteString(strings.Join(args, " "))
-	output.WriteString("\n\n#if !defined(OPENSSL_NO_ASM)\n\n")
+	output.WriteString("\n\n#if !defined(OPENSSL_NO_ASM)\n")
+	output.WriteString("#if defined(__arm__) || defined(__aarch64__)\n\n")
 
 	cmd := exec.Command(compiler, args...)
 	cmd.Stderr = os.Stderr
@@ -144,5 +145,6 @@
 `
 
 const trailer = `
+#endif  /* __arm__ || __aarch64__ */
 #endif  /* !OPENSSL_NO_ASM */
 `
diff --git a/src/crypto/cipher/CMakeLists.txt b/src/crypto/cipher/CMakeLists.txt
index 2775698..6b4c729 100644
--- a/src/crypto/cipher/CMakeLists.txt
+++ b/src/crypto/cipher/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   cipher
diff --git a/src/crypto/cipher/aead.c b/src/crypto/cipher/aead.c
index 20d699d..7e747f8 100644
--- a/src/crypto/cipher/aead.c
+++ b/src/crypto/cipher/aead.c
@@ -30,11 +30,15 @@
 
 size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; }
 
+void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) {
+  memset(ctx, 0, sizeof(EVP_AEAD_CTX));
+}
+
 int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
                       const uint8_t *key, size_t key_len, size_t tag_len,
                       ENGINE *impl) {
   if (!aead->init) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_AEAD_CTX_init, CIPHER_R_NO_DIRECTION_SET);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_DIRECTION_SET);
     ctx->aead = NULL;
     return 0;
   }
@@ -47,8 +51,7 @@
                                      size_t tag_len,
                                      enum evp_aead_direction_t dir) {
   if (key_len != aead->key_len) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_AEAD_CTX_init_with_direction,
-                      CIPHER_R_UNSUPPORTED_KEY_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE);
     ctx->aead = NULL;
     return 0;
   }
@@ -101,12 +104,12 @@
   size_t possible_out_len = in_len + ctx->aead->overhead;
 
   if (possible_out_len < in_len /* overflow */) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_AEAD_CTX_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     goto error;
   }
 
   if (!check_alias(in, in_len, out)) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_AEAD_CTX_seal, CIPHER_R_OUTPUT_ALIASES_INPUT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
     goto error;
   }
 
@@ -128,7 +131,7 @@
                       size_t nonce_len, const uint8_t *in, size_t in_len,
                       const uint8_t *ad, size_t ad_len) {
   if (!check_alias(in, in_len, out)) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_AEAD_CTX_open, CIPHER_R_OUTPUT_ALIASES_INPUT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
     goto error;
   }
 
diff --git a/src/crypto/cipher/aead_test.cc b/src/crypto/cipher/aead_test.cc
index e4b75d6..baaee9e 100644
--- a/src/crypto/cipher/aead_test.cc
+++ b/src/crypto/cipher/aead_test.cc
@@ -22,6 +22,7 @@
 #include <openssl/err.h>
 
 #include "../test/file_test.h"
+#include "../test/scoped_types.h"
 #include "../test/stl_compat.h"
 
 
@@ -35,18 +36,6 @@
 //   CT: 5294265a60
 //   TAG: 1d45758621762e061368e68868e2f929
 
-// EVP_AEAD_CTX lacks a zero state, so it doesn't fit easily into
-// ScopedOpenSSLContext.
-class EVP_AEAD_CTXScoper {
- public:
-  EVP_AEAD_CTXScoper(EVP_AEAD_CTX *ctx) : ctx_(ctx) {}
-  ~EVP_AEAD_CTXScoper() {
-    EVP_AEAD_CTX_cleanup(ctx_);
-  }
- private:
-  EVP_AEAD_CTX *ctx_;
-};
-
 static bool TestAEAD(FileTest *t, void *arg) {
   const EVP_AEAD *aead = reinterpret_cast<const EVP_AEAD*>(arg);
 
@@ -60,20 +49,19 @@
     return false;
   }
 
-  EVP_AEAD_CTX ctx;
-  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key),
-                                        key.size(), tag.size(),
-                                        evp_aead_seal)) {
+  ScopedEVP_AEAD_CTX ctx;
+  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead,
+                                        bssl::vector_data(&key), key.size(),
+                                        tag.size(), evp_aead_seal)) {
     t->PrintLine("Failed to init AEAD.");
     return false;
   }
-  EVP_AEAD_CTXScoper cleanup(&ctx);
 
   std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead));
   if (!t->HasAttribute("NO_SEAL")) {
     size_t out_len;
-    if (!EVP_AEAD_CTX_seal(&ctx, bssl::vector_data(&out), &out_len, out.size(),
-                           bssl::vector_data(&nonce), nonce.size(),
+    if (!EVP_AEAD_CTX_seal(ctx.get(), bssl::vector_data(&out), &out_len,
+                           out.size(), bssl::vector_data(&nonce), nonce.size(),
                            bssl::vector_data(&in), in.size(),
                            bssl::vector_data(&ad), ad.size())) {
       t->PrintLine("Failed to run AEAD.");
@@ -101,17 +89,17 @@
 
   // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
   // reset after each operation.
-  EVP_AEAD_CTX_cleanup(&ctx);
-  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key),
-                                        key.size(), tag.size(),
-                                        evp_aead_open)) {
+  ctx.Reset();
+  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead,
+                                        bssl::vector_data(&key), key.size(),
+                                        tag.size(), evp_aead_open)) {
     t->PrintLine("Failed to init AEAD.");
     return false;
   }
 
   std::vector<uint8_t> out2(out.size());
   size_t out2_len;
-  int ret = EVP_AEAD_CTX_open(&ctx,
+  int ret = EVP_AEAD_CTX_open(ctx.get(),
                               bssl::vector_data(&out2), &out2_len, out2.size(),
                               bssl::vector_data(&nonce), nonce.size(),
                               bssl::vector_data(&out), out.size(),
@@ -137,10 +125,10 @@
 
   // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
   // reset after each operation.
-  EVP_AEAD_CTX_cleanup(&ctx);
-  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key),
-                                        key.size(), tag.size(),
-                                        evp_aead_open)) {
+  ctx.Reset();
+  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead,
+                                        bssl::vector_data(&key), key.size(),
+                                        tag.size(), evp_aead_open)) {
     t->PrintLine("Failed to init AEAD.");
     return false;
   }
@@ -148,8 +136,8 @@
   // Garbage at the end isn't ignored.
   out.push_back(0);
   out2.resize(out.size());
-  if (EVP_AEAD_CTX_open(&ctx, bssl::vector_data(&out2), &out2_len, out2.size(),
-                        bssl::vector_data(&nonce), nonce.size(),
+  if (EVP_AEAD_CTX_open(ctx.get(), bssl::vector_data(&out2), &out2_len,
+                        out2.size(), bssl::vector_data(&nonce), nonce.size(),
                         bssl::vector_data(&out), out.size(),
                         bssl::vector_data(&ad), ad.size())) {
     t->PrintLine("Decrypted bad data with trailing garbage.");
@@ -159,10 +147,10 @@
 
   // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
   // reset after each operation.
-  EVP_AEAD_CTX_cleanup(&ctx);
-  if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, bssl::vector_data(&key),
-                                        key.size(), tag.size(),
-                                        evp_aead_open)) {
+  ctx.Reset();
+  if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead,
+                                        bssl::vector_data(&key), key.size(),
+                                        tag.size(), evp_aead_open)) {
     t->PrintLine("Failed to init AEAD.");
     return false;
   }
@@ -171,8 +159,8 @@
   out[0] ^= 0x80;
   out.resize(out.size() - 1);
   out2.resize(out.size());
-  if (EVP_AEAD_CTX_open(&ctx, bssl::vector_data(&out2), &out2_len, out2.size(),
-                        bssl::vector_data(&nonce), nonce.size(),
+  if (EVP_AEAD_CTX_open(ctx.get(), bssl::vector_data(&out2), &out2_len,
+                        out2.size(), bssl::vector_data(&nonce), nonce.size(),
                         bssl::vector_data(&out), out.size(),
                         bssl::vector_data(&ad), ad.size())) {
     t->PrintLine("Decrypted bad data with corrupted byte.");
@@ -200,6 +188,7 @@
     fprintf(stderr, "A silly tag length didn't trigger an error!\n");
     return 0;
   }
+  ERR_clear_error();
 
   /* Running a second, failed _init should not cause a memory leak. */
   if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len,
@@ -208,6 +197,7 @@
     fprintf(stderr, "A silly tag length didn't trigger an error!\n");
     return 0;
   }
+  ERR_clear_error();
 
   /* Calling _cleanup on an |EVP_AEAD_CTX| after a failed _init should be a
    * no-op. */
diff --git a/src/crypto/cipher/cipher.c b/src/crypto/cipher/cipher.c
index 400c3f5..4401867 100644
--- a/src/crypto/cipher/cipher.c
+++ b/src/crypto/cipher/cipher.c
@@ -68,12 +68,18 @@
 
 const EVP_CIPHER *EVP_get_cipherbynid(int nid) {
   switch (nid) {
+    case NID_rc2_cbc:
+      return EVP_rc2_cbc();
+    case NID_rc2_40_cbc:
+      return EVP_rc2_40_cbc();
     case NID_des_ede3_cbc:
       return EVP_des_ede3_cbc();
     case NID_des_ede_cbc:
       return EVP_des_cbc();
     case NID_aes_128_cbc:
       return EVP_aes_128_cbc();
+    case NID_aes_192_cbc:
+      return EVP_aes_192_cbc();
     case NID_aes_256_cbc:
       return EVP_aes_256_cbc();
     default:
@@ -115,7 +121,7 @@
 
 int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) {
   if (in == NULL || in->cipher == NULL) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_copy, CIPHER_R_INPUT_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INPUT_NOT_INITIALIZED);
     return 0;
   }
 
@@ -125,7 +131,7 @@
   if (in->cipher_data && in->cipher->ctx_size) {
     out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size);
     if (!out->cipher_data) {
-      OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_copy, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
       return 0;
     }
     memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size);
@@ -165,7 +171,7 @@
       ctx->cipher_data = OPENSSL_malloc(ctx->cipher->ctx_size);
       if (!ctx->cipher_data) {
         ctx->cipher = NULL;
-        OPENSSL_PUT_ERROR(CIPHER, EVP_CipherInit_ex, ERR_R_MALLOC_FAILURE);
+        OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
         return 0;
       }
     } else {
@@ -178,12 +184,12 @@
     if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) {
       if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) {
         ctx->cipher = NULL;
-        OPENSSL_PUT_ERROR(CIPHER, EVP_CipherInit_ex, CIPHER_R_INITIALIZATION_ERROR);
+        OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INITIALIZATION_ERROR);
         return 0;
       }
     }
   } else if (!ctx->cipher) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_CipherInit_ex, CIPHER_R_NO_CIPHER_SET);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_CIPHER_SET);
     return 0;
   }
 
@@ -338,8 +344,7 @@
   bl = ctx->buf_len;
   if (ctx->flags & EVP_CIPH_NO_PADDING) {
     if (bl) {
-      OPENSSL_PUT_ERROR(CIPHER, EVP_EncryptFinal_ex,
-                        CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
+      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
       return 0;
     }
     *out_len = 0;
@@ -434,8 +439,7 @@
   b = ctx->cipher->block_size;
   if (ctx->flags & EVP_CIPH_NO_PADDING) {
     if (ctx->buf_len) {
-      OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex,
-                        CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
+      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH);
       return 0;
     }
     *out_len = 0;
@@ -444,8 +448,7 @@
 
   if (b > 1) {
     if (ctx->buf_len || !ctx->final_used) {
-      OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex,
-                        CIPHER_R_WRONG_FINAL_BLOCK_LENGTH);
+      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_WRONG_FINAL_BLOCK_LENGTH);
       return 0;
     }
     assert(b <= sizeof(ctx->final));
@@ -454,13 +457,13 @@
      * Otherwise it provides a padding oracle. */
     n = ctx->final[b - 1];
     if (n == 0 || n > (int)b) {
-      OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex, CIPHER_R_BAD_DECRYPT);
+      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
       return 0;
     }
 
     for (i = 0; i < n; i++) {
       if (ctx->final[--b] != n) {
-        OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex, CIPHER_R_BAD_DECRYPT);
+        OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
         return 0;
       }
     }
@@ -538,19 +541,18 @@
 int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int command, int arg, void *ptr) {
   int ret;
   if (!ctx->cipher) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_ctrl, CIPHER_R_NO_CIPHER_SET);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_CIPHER_SET);
     return 0;
   }
 
   if (!ctx->cipher->ctrl) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_ctrl, CIPHER_R_CTRL_NOT_IMPLEMENTED);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED);
     return 0;
   }
 
   ret = ctx->cipher->ctrl(ctx, command, arg, ptr);
   if (ret == -1) {
-    OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_ctrl,
-                      CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED);
     return 0;
   }
 
@@ -572,8 +574,7 @@
   }
 
   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);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_KEY_LENGTH);
     return 0;
   }
 
@@ -630,7 +631,7 @@
     return EVP_rc4();
   } else if (OPENSSL_strcasecmp(name, "des-cbc") == 0) {
     return EVP_des_cbc();
-  } else if (OPENSSL_strcasecmp(name, "3des-cbc") == 0 ||
+  } else if (OPENSSL_strcasecmp(name, "des-ede3-cbc") == 0 ||
              OPENSSL_strcasecmp(name, "3des") == 0) {
     return EVP_des_ede3_cbc();
   } else if (OPENSSL_strcasecmp(name, "aes-128-cbc") == 0) {
diff --git a/src/crypto/cipher/cipher_test.cc b/src/crypto/cipher/cipher_test.cc
index 97a84e0..5f04178 100644
--- a/src/crypto/cipher/cipher_test.cc
+++ b/src/crypto/cipher/cipher_test.cc
@@ -69,6 +69,12 @@
 static const EVP_CIPHER *GetCipher(const std::string &name) {
   if (name == "DES-CBC") {
     return EVP_des_cbc();
+  } else if (name == "DES-ECB") {
+    return EVP_des_ecb();
+  } else if (name == "DES-EDE") {
+    return EVP_des_ede();
+  } else if (name == "DES-EDE-CBC") {
+    return EVP_des_ede_cbc();
   } else if (name == "DES-EDE3-CBC") {
     return EVP_des_ede3_cbc();
   } else if (name == "RC4") {
@@ -104,6 +110,7 @@
 static bool TestOperation(FileTest *t,
                           const EVP_CIPHER *cipher,
                           bool encrypt,
+                          bool streaming,
                           const std::vector<uint8_t> &key,
                           const std::vector<uint8_t> &iv,
                           const std::vector<uint8_t> &plaintext,
@@ -160,11 +167,29 @@
       (!aad.empty() &&
        !EVP_CipherUpdate(ctx.get(), nullptr, &unused, bssl::vector_data(&aad),
                          aad.size())) ||
-      !EVP_CIPHER_CTX_set_padding(ctx.get(), 0) ||
-      (!in->empty() &&
-       !EVP_CipherUpdate(ctx.get(), bssl::vector_data(&result), &result_len1,
-                         bssl::vector_data(in), in->size())) ||
-      !EVP_CipherFinal_ex(ctx.get(), bssl::vector_data(&result) + result_len1,
+      !EVP_CIPHER_CTX_set_padding(ctx.get(), 0)) {
+    t->PrintLine("Operation failed.");
+    return false;
+  }
+  if (streaming) {
+    for (size_t i = 0; i < in->size(); i++) {
+      uint8_t c = (*in)[i];
+      int len;
+      if (!EVP_CipherUpdate(ctx.get(), bssl::vector_data(&result) + result_len1,
+                            &len, &c, 1)) {
+        t->PrintLine("Operation failed.");
+        return false;
+      }
+      result_len1 += len;
+    }
+  } else if (!in->empty() &&
+             !EVP_CipherUpdate(ctx.get(), bssl::vector_data(&result),
+                               &result_len1, bssl::vector_data(in),
+                               in->size())) {
+    t->PrintLine("Operation failed.");
+    return false;
+  }
+  if (!EVP_CipherFinal_ex(ctx.get(), bssl::vector_data(&result) + result_len1,
                           &result_len2)) {
     t->PrintLine("Operation failed.");
     return false;
@@ -236,15 +261,21 @@
   }
 
   // By default, both directions are run, unless overridden by the operation.
-  if (operation != kDecrypt &&
-      !TestOperation(t, cipher, true /* encrypt */, key, iv, plaintext,
-                     ciphertext, aad, tag)) {
-    return false;
+  if (operation != kDecrypt) {
+    if (!TestOperation(t, cipher, true /* encrypt */, false /* single-shot */,
+                       key, iv, plaintext, ciphertext, aad, tag) ||
+        !TestOperation(t, cipher, true /* encrypt */, true /* streaming */, key,
+                       iv, plaintext, ciphertext, aad, tag)) {
+      return false;
+    }
   }
-  if (operation != kEncrypt &&
-      !TestOperation(t, cipher, false /* decrypt */, key, iv, plaintext,
-                     ciphertext, aad, tag)) {
-    return false;
+  if (operation != kEncrypt) {
+    if (!TestOperation(t, cipher, false /* decrypt */, false /* single-shot */,
+                       key, iv, plaintext, ciphertext, aad, tag) ||
+        !TestOperation(t, cipher, false /* decrypt */, true /* streaming */,
+                       key, iv, plaintext, ciphertext, aad, tag)) {
+      return false;
+    }
   }
 
   return true;
diff --git a/src/crypto/cipher/e_aes.c b/src/crypto/cipher/e_aes.c
index 41d0aec..e8905f6 100644
--- a/src/crypto/cipher/e_aes.c
+++ b/src/crypto/cipher/e_aes.c
@@ -64,7 +64,7 @@
 #include "../modes/internal.h"
 
 #if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
-#include "../arm_arch.h"
+#include <openssl/arm_arch.h>
 #endif
 
 
@@ -98,8 +98,6 @@
 #if !defined(OPENSSL_NO_ASM) && \
     (defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
 #define VPAES
-extern unsigned int OPENSSL_ia32cap_P[];
-
 static char vpaes_capable(void) {
   return (OPENSSL_ia32cap_P[1] & (1 << (41 - 32))) != 0;
 }
@@ -113,7 +111,6 @@
 
 #elif !defined(OPENSSL_NO_ASM) && \
     (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
-#include "../arm_arch.h"
 
 #if defined(OPENSSL_ARM) && __ARM_MAX_ARCH__ >= 7
 #define BSAES
@@ -338,7 +335,7 @@
   }
 
   if (ret < 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aes_init_key, CIPHER_R_AES_KEY_SETUP_FAILED);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED);
     return 0;
   }
 
@@ -711,7 +708,7 @@
   } else {
     if (!ctx->encrypt) {
       if (gctx->taglen < 0 ||
-          !CRYPTO_gcm128_finish(&gctx->gcm, ctx->buf, gctx->taglen) != 0) {
+          !CRYPTO_gcm128_finish(&gctx->gcm, ctx->buf, gctx->taglen)) {
         return -1;
       }
       gctx->iv_set = 0;
@@ -853,7 +850,7 @@
   }
 
   if (ret < 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aesni_init_key, CIPHER_R_AES_KEY_SETUP_FAILED);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED);
     return 0;
   }
 
@@ -1066,7 +1063,7 @@
   const size_t key_bits = key_len * 8;
 
   if (key_bits != 128 && key_bits != 256) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_gcm_init, CIPHER_R_BAD_KEY_LENGTH);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
     return 0; /* EVP_AEAD_CTX_init should catch this. */
   }
 
@@ -1075,7 +1072,7 @@
   }
 
   if (tag_len > EVP_AEAD_AES_GCM_TAG_LEN) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_gcm_init, CIPHER_R_TAG_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE);
     return 0;
   }
 
@@ -1108,12 +1105,12 @@
   GCM128_CONTEXT gcm;
 
   if (in_len + gcm_ctx->tag_len < in_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_gcm_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (max_out_len < in_len + gcm_ctx->tag_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_gcm_seal, CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
@@ -1152,14 +1149,14 @@
   GCM128_CONTEXT gcm;
 
   if (in_len < gcm_ctx->tag_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_gcm_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
   plaintext_len = in_len - gcm_ctx->tag_len;
 
   if (max_out_len < plaintext_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_gcm_open, CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
@@ -1185,7 +1182,7 @@
 
   CRYPTO_gcm128_tag(&gcm, tag, gcm_ctx->tag_len);
   if (CRYPTO_memcmp(tag, in + plaintext_len, gcm_ctx->tag_len) != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_gcm_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
@@ -1239,7 +1236,7 @@
   const size_t key_bits = key_len * 8;
 
   if (key_bits != 128 && key_bits != 256) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_init, CIPHER_R_BAD_KEY_LENGTH);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
     return 0; /* EVP_AEAD_CTX_init should catch this. */
   }
 
@@ -1248,14 +1245,13 @@
   }
 
   if (tag_len != 8) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_init,
-                      CIPHER_R_UNSUPPORTED_TAG_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE);
     return 0;
   }
 
   kw_ctx = OPENSSL_malloc(sizeof(struct aead_aes_key_wrap_ctx));
   if (kw_ctx == NULL) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_init, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -1293,8 +1289,7 @@
   uint8_t A[AES_BLOCK_SIZE];
 
   if (ad_len != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
-                      CIPHER_R_UNSUPPORTED_AD_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE);
     return 0;
   }
 
@@ -1304,14 +1299,12 @@
   }
 
   if (nonce_len != 8) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
-                      CIPHER_R_UNSUPPORTED_NONCE_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
     return 0;
   }
 
   if (in_len % 8 != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
-                      CIPHER_R_UNSUPPORTED_INPUT_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE);
     return 0;
   }
 
@@ -1320,32 +1313,29 @@
    * conservatively cap it to 2^32-16 to stop 32-bit platforms complaining that
    * a comparison is always true. */
   if (in_len > 0xfffffff0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   n = in_len / 8;
 
   if (n < 2) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
-                      CIPHER_R_UNSUPPORTED_INPUT_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE);
     return 0;
   }
 
   if (in_len + 8 < in_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (max_out_len < in_len + 8) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
-                      CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (AES_set_encrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
-                      CIPHER_R_AES_KEY_SETUP_FAILED);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED);
     return 0;
   }
 
@@ -1388,8 +1378,7 @@
   uint8_t A[AES_BLOCK_SIZE];
 
   if (ad_len != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
-                      CIPHER_R_UNSUPPORTED_AD_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE);
     return 0;
   }
 
@@ -1399,14 +1388,12 @@
   }
 
   if (nonce_len != 8) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
-                      CIPHER_R_UNSUPPORTED_NONCE_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
     return 0;
   }
 
   if (in_len % 8 != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
-                      CIPHER_R_UNSUPPORTED_INPUT_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE);
     return 0;
   }
 
@@ -1415,26 +1402,24 @@
    * conservatively cap it to 2^32-8 to stop 32-bit platforms complaining that
    * a comparison is always true. */
   if (in_len > 0xfffffff8) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (in_len < 24) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
   n = (in_len / 8) - 1;
 
   if (max_out_len < in_len - 8) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
-                      CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (AES_set_decrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
-                      CIPHER_R_AES_KEY_SETUP_FAILED);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED);
     return 0;
   }
 
@@ -1457,7 +1442,7 @@
   }
 
   if (CRYPTO_memcmp(A, nonce, 8) != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
@@ -1541,15 +1526,13 @@
   static const size_t hmac_key_len = 32;
 
   if (key_len < hmac_key_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_init,
-                      CIPHER_R_BAD_KEY_LENGTH);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
     return 0; /* EVP_AEAD_CTX_init should catch this. */
   }
 
   const size_t aes_key_len = key_len - hmac_key_len;
   if (aes_key_len != 16 && aes_key_len != 32) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_init,
-                      CIPHER_R_BAD_KEY_LENGTH);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
     return 0; /* EVP_AEAD_CTX_init should catch this. */
   }
 
@@ -1558,15 +1541,13 @@
   }
 
   if (tag_len > EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_init,
-                      CIPHER_R_TAG_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE);
     return 0;
   }
 
   aes_ctx = OPENSSL_malloc(sizeof(struct aead_aes_ctr_hmac_sha256_ctx));
   if (aes_ctx == NULL) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_init,
-                      ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -1666,20 +1647,17 @@
   if (in_len + aes_ctx->tag_len < in_len ||
       /* This input is so large it would overflow the 32-bit block counter. */
       in_len_64 >= (OPENSSL_U64(1) << 32) * AES_BLOCK_SIZE) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_seal,
-                      CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (max_out_len < in_len + aes_ctx->tag_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_seal,
-                      CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (nonce_len != EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_seal,
-                      CIPHER_R_UNSUPPORTED_NONCE_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
     return 0;
   }
 
@@ -1703,22 +1681,19 @@
   size_t plaintext_len;
 
   if (in_len < aes_ctx->tag_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_open,
-                      CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
   plaintext_len = in_len - aes_ctx->tag_len;
 
   if (max_out_len < plaintext_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_open,
-                      CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (nonce_len != EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_open,
-                      CIPHER_R_UNSUPPORTED_NONCE_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
     return 0;
   }
 
@@ -1727,8 +1702,7 @@
                  &aes_ctx->outer_init_state, ad, ad_len, nonce, in,
                  plaintext_len);
   if (CRYPTO_memcmp(hmac_result, in + plaintext_len, aes_ctx->tag_len) != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_aes_ctr_hmac_sha256_open,
-                      CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
diff --git a/src/crypto/cipher/e_chacha20poly1305.c b/src/crypto/cipher/e_chacha20poly1305.c
index ebf0088..9dda1b0 100644
--- a/src/crypto/cipher/e_chacha20poly1305.c
+++ b/src/crypto/cipher/e_chacha20poly1305.c
@@ -42,7 +42,7 @@
   }
 
   if (tag_len > POLY1305_TAG_LEN) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_init, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
@@ -107,23 +107,22 @@
    * Casting to uint64_t inside the conditional is not sufficient to stop
    * the warning. */
   if (in_len_64 >= (1ull << 32) * 64 - 64) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (in_len + c20_ctx->tag_len < in_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (max_out_len < in_len + c20_ctx->tag_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_seal,
-                      CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (nonce_len != CHACHA20_NONCE_LEN) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_seal, CIPHER_R_IV_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE);
     return 0;
   }
 
@@ -156,7 +155,7 @@
   const uint64_t in_len_64 = in_len;
 
   if (in_len < c20_ctx->tag_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
@@ -168,20 +167,19 @@
    * Casting to uint64_t inside the conditional is not sufficient to stop
    * the warning. */
   if (in_len_64 >= (1ull << 32) * 64 - 64) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (nonce_len != CHACHA20_NONCE_LEN) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_IV_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE);
     return 0;
   }
 
   plaintext_len = in_len - c20_ctx->tag_len;
 
   if (max_out_len < plaintext_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open,
-                      CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
@@ -195,7 +193,7 @@
   CRYPTO_poly1305_finish(&poly1305, mac);
 
   if (CRYPTO_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_chacha20_poly1305_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
diff --git a/src/crypto/cipher/e_des.c b/src/crypto/cipher/e_des.c
index 74e1fce..b1d312c 100644
--- a/src/crypto/cipher/e_des.c
+++ b/src/crypto/cipher/e_des.c
@@ -96,6 +96,31 @@
 const EVP_CIPHER *EVP_des_cbc(void) { return &des_cbc; }
 
 
+static int des_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+                          size_t in_len) {
+  if (in_len < ctx->cipher->block_size) {
+    return 1;
+  }
+  in_len -= ctx->cipher->block_size;
+
+  EVP_DES_KEY *dat = (EVP_DES_KEY *) ctx->cipher_data;
+  size_t i;
+  for (i = 0; i <= in_len; i += ctx->cipher->block_size) {
+    DES_ecb_encrypt((DES_cblock *) (in + i), (DES_cblock *) (out + i),
+                    &dat->ks.ks, ctx->encrypt);
+  }
+  return 1;
+}
+
+static const EVP_CIPHER des_ecb = {
+    NID_des_ecb,         8 /* block_size */,  8 /* key_size */,
+    0 /* iv_len */,      sizeof(EVP_DES_KEY), EVP_CIPH_ECB_MODE,
+    NULL /* app_data */, des_init_key,        des_ecb_cipher,
+    NULL /* cleanup */,  NULL /* ctrl */, };
+
+const EVP_CIPHER *EVP_des_ecb(void) { return &des_ecb; }
+
+
 typedef struct {
   union {
     double align;
@@ -126,10 +151,57 @@
   return 1;
 }
 
-static const EVP_CIPHER des3_cbc = {
-    NID_des_cbc,         8 /* block_size */,  24 /* key_size */,
+static const EVP_CIPHER des_ede3_cbc = {
+    NID_des_ede3_cbc,    8 /* block_size */,  24 /* key_size */,
     8 /* iv_len */,      sizeof(DES_EDE_KEY), EVP_CIPH_CBC_MODE,
     NULL /* app_data */, des_ede3_init_key,   des_ede3_cbc_cipher,
     NULL /* cleanup */,  NULL /* ctrl */, };
 
-const EVP_CIPHER *EVP_des_ede3_cbc(void) { return &des3_cbc; }
+const EVP_CIPHER *EVP_des_ede3_cbc(void) { return &des_ede3_cbc; }
+
+
+static int des_ede_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+                             const uint8_t *iv, int enc) {
+  DES_cblock *deskey = (DES_cblock *) key;
+  DES_EDE_KEY *dat = (DES_EDE_KEY *) ctx->cipher_data;
+
+  DES_set_key(&deskey[0], &dat->ks.ks[0]);
+  DES_set_key(&deskey[1], &dat->ks.ks[1]);
+  DES_set_key(&deskey[0], &dat->ks.ks[2]);
+
+  return 1;
+}
+
+static const EVP_CIPHER des_ede_cbc = {
+    NID_des_ede_cbc,     8 /* block_size */,  16 /* key_size */,
+    8 /* iv_len */,      sizeof(DES_EDE_KEY), EVP_CIPH_CBC_MODE,
+    NULL /* app_data */, des_ede_init_key ,   des_ede3_cbc_cipher,
+    NULL /* cleanup */,  NULL /* ctrl */, };
+
+const EVP_CIPHER *EVP_des_ede_cbc(void) { return &des_ede_cbc; }
+
+
+static int des_ede_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+                              const uint8_t *in, size_t in_len) {
+  if (in_len < ctx->cipher->block_size) {
+    return 1;
+  }
+  in_len -= ctx->cipher->block_size;
+
+  DES_EDE_KEY *dat = (DES_EDE_KEY *) ctx->cipher_data;
+  size_t i;
+  for (i = 0; i <= in_len; i += ctx->cipher->block_size) {
+    DES_ecb3_encrypt((DES_cblock *) (in + i), (DES_cblock *) (out + i),
+                     &dat->ks.ks[0], &dat->ks.ks[1], &dat->ks.ks[2],
+                     ctx->encrypt);
+  }
+  return 1;
+}
+
+static const EVP_CIPHER des_ede_ecb = {
+    NID_des_ede_cbc,     8 /* block_size */,  16 /* key_size */,
+    0 /* iv_len */,      sizeof(DES_EDE_KEY), EVP_CIPH_ECB_MODE,
+    NULL /* app_data */, des_ede_init_key ,   des_ede_ecb_cipher,
+    NULL /* cleanup */,  NULL /* ctrl */, };
+
+const EVP_CIPHER *EVP_des_ede(void) { return &des_ede_ecb; }
diff --git a/src/crypto/cipher/e_rc2.c b/src/crypto/cipher/e_rc2.c
index c90ab93..8ca7bba 100644
--- a/src/crypto/cipher/e_rc2.c
+++ b/src/crypto/cipher/e_rc2.c
@@ -395,13 +395,18 @@
     case EVP_CTRL_INIT:
       key->key_bits = EVP_CIPHER_CTX_key_length(ctx) * 8;
       return 1;
+    case EVP_CTRL_SET_RC2_KEY_BITS:
+      /* Should be overridden by later call to |EVP_CTRL_INIT|, but
+       * people call it, so it may as well work. */
+      key->key_bits = arg;
+      return 1;
 
     default:
       return -1;
   }
 }
 
-static const EVP_CIPHER rc2_40_cbc_cipher = {
+static const EVP_CIPHER rc2_40_cbc = {
     NID_rc2_40_cbc,
     8 /* block size */,
     5 /* 40 bit */,
@@ -416,5 +421,23 @@
 };
 
 const EVP_CIPHER *EVP_rc2_40_cbc(void) {
-  return &rc2_40_cbc_cipher;
+  return &rc2_40_cbc;
+}
+
+static const EVP_CIPHER rc2_cbc = {
+    NID_rc2_cbc,
+    8 /* block size */,
+    16 /* 128 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_cbc(void) {
+  return &rc2_cbc;
 }
diff --git a/src/crypto/cipher/e_rc4.c b/src/crypto/cipher/e_rc4.c
index 80dea36..e05b9fd 100644
--- a/src/crypto/cipher/e_rc4.c
+++ b/src/crypto/cipher/e_rc4.c
@@ -115,20 +115,20 @@
   }
 
   if (tag_len > MD5_DIGEST_LENGTH) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_init, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   /* The keys consists of |MD5_DIGEST_LENGTH| bytes of HMAC(MD5) key followed
    * by some number of bytes of RC4 key. */
   if (key_len <= MD5_DIGEST_LENGTH) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_init, CIPHER_R_BAD_KEY_LENGTH);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
     return 0;
   }
 
   rc4_ctx = OPENSSL_malloc(sizeof(struct aead_rc4_md5_tls_ctx));
   if (rc4_ctx == NULL) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_init, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
     return 0;
   }
   memset(rc4_ctx, 0, sizeof(struct aead_rc4_md5_tls_ctx));
@@ -185,22 +185,22 @@
   uint8_t digest[MD5_DIGEST_LENGTH];
 
   if (in_len + rc4_ctx->tag_len < in_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (nonce_len != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_seal, CIPHER_R_IV_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE);
     return 0;
   }
 
   if (max_out_len < in_len + rc4_ctx->tag_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_seal, CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (nonce_len != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
@@ -288,21 +288,21 @@
   uint8_t digest[MD5_DIGEST_LENGTH];
 
   if (in_len < rc4_ctx->tag_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
   plaintext_len = in_len - rc4_ctx->tag_len;
 
   if (nonce_len != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_open, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (max_out_len < in_len) {
     /* This requires that the caller provide space for the MAC, even though it
      * will always be removed on return. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_open, CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
@@ -366,7 +366,7 @@
   MD5_Final(digest, &md);
 
   if (CRYPTO_memcmp(out + plaintext_len, digest, rc4_ctx->tag_len)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_rc4_md5_tls_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
diff --git a/src/crypto/cipher/e_ssl3.c b/src/crypto/cipher/e_ssl3.c
index 1031d9b..389c52f 100644
--- a/src/crypto/cipher/e_ssl3.c
+++ b/src/crypto/cipher/e_ssl3.c
@@ -85,12 +85,12 @@
                           const EVP_CIPHER *cipher, const EVP_MD *md) {
   if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH &&
       tag_len != EVP_MD_size(md)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_init, CIPHER_R_UNSUPPORTED_TAG_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE);
     return 0;
   }
 
   if (key_len != EVP_AEAD_key_length(ctx->aead)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_init, CIPHER_R_BAD_KEY_LENGTH);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
     return 0;
   }
 
@@ -102,7 +102,7 @@
 
   AEAD_SSL3_CTX *ssl3_ctx = OPENSSL_malloc(sizeof(AEAD_SSL3_CTX));
   if (ssl3_ctx == NULL) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_init, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
     return 0;
   }
   EVP_CIPHER_CTX_init(&ssl3_ctx->cipher_ctx);
@@ -133,29 +133,29 @@
 
   if (!ssl3_ctx->cipher_ctx.encrypt) {
     /* Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_seal, CIPHER_R_INVALID_OPERATION);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION);
     return 0;
   }
 
   if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len ||
       in_len > INT_MAX) {
     /* EVP_CIPHER takes int as input. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (max_out_len < in_len + EVP_AEAD_max_overhead(ctx->aead)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_seal, CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (nonce_len != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_seal, CIPHER_R_IV_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE);
     return 0;
   }
 
   if (ad_len != 11 - 2 /* length bytes */) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_seal, CIPHER_R_INVALID_AD_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE);
     return 0;
   }
 
@@ -217,36 +217,36 @@
 
   if (ssl3_ctx->cipher_ctx.encrypt) {
     /* Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_INVALID_OPERATION);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION);
     return 0;
   }
 
   size_t mac_len = EVP_MD_CTX_size(&ssl3_ctx->md_ctx);
   if (in_len < mac_len) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
   if (max_out_len < in_len) {
     /* This requires that the caller provide space for the MAC, even though it
      * will always be removed on return. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (nonce_len != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (ad_len != 11 - 2 /* length bytes */) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_INVALID_AD_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE);
     return 0;
   }
 
   if (in_len > INT_MAX) {
     /* EVP_CIPHER takes int as input. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
@@ -270,12 +270,12 @@
   if (EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) {
     unsigned padding_length = out[total - 1];
     if (total < padding_length + 1 + mac_len) {
-      OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_BAD_DECRYPT);
+      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
       return 0;
     }
     /* The padding must be minimal. */
     if (padding_length + 1 > EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx)) {
-      OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_BAD_DECRYPT);
+      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
       return 0;
     }
     data_len = total - padding_length - 1 - mac_len;
@@ -289,7 +289,7 @@
     return 0;
   }
   if (CRYPTO_memcmp(&out[data_len], mac, mac_len) != 0) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_ssl3_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
@@ -340,6 +340,13 @@
                         EVP_sha1());
 }
 
+static int aead_null_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
+                                    size_t key_len, size_t tag_len,
+                                    enum evp_aead_direction_t dir) {
+  return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_enc_null(),
+                        EVP_sha1());
+}
+
 static const EVP_AEAD aead_rc4_md5_ssl3 = {
     MD5_DIGEST_LENGTH + 16, /* key len (MD5 + RC4) */
     0,                      /* nonce len */
@@ -405,6 +412,19 @@
     NULL,                        /* get_rc4_state */
 };
 
+static const EVP_AEAD aead_null_sha1_ssl3 = {
+    SHA_DIGEST_LENGTH,          /* key len */
+    0,                          /* nonce len */
+    SHA_DIGEST_LENGTH,          /* overhead (SHA1) */
+    SHA_DIGEST_LENGTH,          /* max tag length */
+    NULL,                       /* init */
+    aead_null_sha1_ssl3_init,
+    aead_ssl3_cleanup,
+    aead_ssl3_seal,
+    aead_ssl3_open,
+    NULL,                       /* get_rc4_state */
+};
+
 const EVP_AEAD *EVP_aead_rc4_md5_ssl3(void) { return &aead_rc4_md5_ssl3; }
 
 const EVP_AEAD *EVP_aead_rc4_sha1_ssl3(void) { return &aead_rc4_sha1_ssl3; }
@@ -420,3 +440,5 @@
 const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_ssl3(void) {
   return &aead_des_ede3_cbc_sha1_ssl3;
 }
+
+const EVP_AEAD *EVP_aead_null_sha1_ssl3(void) { return &aead_null_sha1_ssl3; }
diff --git a/src/crypto/cipher/e_tls.c b/src/crypto/cipher/e_tls.c
index bed02cb..2778881 100644
--- a/src/crypto/cipher/e_tls.c
+++ b/src/crypto/cipher/e_tls.c
@@ -57,12 +57,12 @@
                          char implicit_iv) {
   if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH &&
       tag_len != EVP_MD_size(md)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_init, CIPHER_R_UNSUPPORTED_TAG_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE);
     return 0;
   }
 
   if (key_len != EVP_AEAD_key_length(ctx->aead)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_init, CIPHER_R_BAD_KEY_LENGTH);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
     return 0;
   }
 
@@ -75,7 +75,7 @@
 
   AEAD_TLS_CTX *tls_ctx = OPENSSL_malloc(sizeof(AEAD_TLS_CTX));
   if (tls_ctx == NULL) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_init, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
     return 0;
   }
   EVP_CIPHER_CTX_init(&tls_ctx->cipher_ctx);
@@ -109,7 +109,7 @@
 
   if (!tls_ctx->cipher_ctx.encrypt) {
     /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_INVALID_OPERATION);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION);
     return 0;
 
   }
@@ -117,22 +117,22 @@
   if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len ||
       in_len > INT_MAX) {
     /* EVP_CIPHER takes int as input. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
   if (max_out_len < in_len + EVP_AEAD_max_overhead(ctx->aead)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_INVALID_NONCE_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE);
     return 0;
   }
 
   if (ad_len != 13 - 2 /* length bytes */) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_seal, CIPHER_R_INVALID_AD_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE);
     return 0;
   }
 
@@ -214,36 +214,36 @@
 
   if (tls_ctx->cipher_ctx.encrypt) {
     /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_INVALID_OPERATION);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION);
     return 0;
 
   }
 
   if (in_len < HMAC_size(&tls_ctx->hmac_ctx)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
   if (max_out_len < in_len) {
     /* This requires that the caller provide space for the MAC, even though it
      * will always be removed on return. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_INVALID_NONCE_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE);
     return 0;
   }
 
   if (ad_len != 13 - 2 /* length bytes */) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_INVALID_AD_SIZE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE);
     return 0;
   }
 
   if (in_len > INT_MAX) {
     /* EVP_CIPHER takes int as input. */
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_TOO_LARGE);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
     return 0;
   }
 
@@ -278,7 +278,7 @@
         (unsigned)HMAC_size(&tls_ctx->hmac_ctx));
     /* Publicly invalid. This can be rejected in non-constant time. */
     if (padding_ok == 0) {
-      OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT);
+      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
       return 0;
     }
   } else {
@@ -312,7 +312,7 @@
     if (!EVP_tls_cbc_digest_record(tls_ctx->hmac_ctx.md, mac, &mac_len,
                                    ad_fixed, out, data_plus_mac_len, total,
                                    tls_ctx->mac_key, tls_ctx->mac_key_len)) {
-      OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT);
+      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
       return 0;
     }
     assert(mac_len == HMAC_size(&tls_ctx->hmac_ctx));
@@ -349,7 +349,7 @@
                                        0);
   good &= constant_time_eq_int(padding_ok, 1);
   if (!good) {
-    OPENSSL_PUT_ERROR(CIPHER, aead_tls_open, CIPHER_R_BAD_DECRYPT);
+    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
     return 0;
   }
 
@@ -444,6 +444,13 @@
   return 1;
 }
 
+static int aead_null_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
+                                   size_t key_len, size_t tag_len,
+                                   enum evp_aead_direction_t dir) {
+  return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_enc_null(),
+                       EVP_sha1(), 1 /* implicit iv */);
+}
+
 static const EVP_AEAD aead_rc4_sha1_tls = {
     SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + RC4) */
     0,                      /* nonce len */
@@ -574,6 +581,19 @@
     NULL,                       /* get_rc4_state */
 };
 
+static const EVP_AEAD aead_null_sha1_tls = {
+    SHA_DIGEST_LENGTH,          /* key len */
+    0,                          /* nonce len */
+    SHA_DIGEST_LENGTH,          /* overhead (SHA1) */
+    SHA_DIGEST_LENGTH,          /* max tag length */
+    NULL,                       /* init */
+    aead_null_sha1_tls_init,
+    aead_tls_cleanup,
+    aead_tls_seal,
+    aead_tls_open,
+    NULL,                       /* get_rc4_state */
+};
+
 const EVP_AEAD *EVP_aead_rc4_sha1_tls(void) { return &aead_rc4_sha1_tls; }
 
 const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void) {
@@ -611,3 +631,5 @@
 const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(void) {
   return &aead_des_ede3_cbc_sha1_tls_implicit_iv;
 }
+
+const EVP_AEAD *EVP_aead_null_sha1_tls(void) { return &aead_null_sha1_tls; }
diff --git a/src/crypto/cipher/test/aes_128_gcm_tests.txt b/src/crypto/cipher/test/aes_128_gcm_tests.txt
index 5f7ad35..75466fe 100644
--- a/src/crypto/cipher/test/aes_128_gcm_tests.txt
+++ b/src/crypto/cipher/test/aes_128_gcm_tests.txt
@@ -418,3 +418,9 @@
 CT: 5f3627bd53f8da0bbe6f3c9246d6f96fe9abb91cdecf66ddd42f833d98f4d4634c2e1e1ad4088c84c22191bdb9d99ef227320e455dd112c4a9e9cca95724fcc9ae024ed12bf60a802d0b87b99d9bf22590786567c2962171d2b05bec9754c627608e9eba7bccc70540aa4da72e1e04b26d8f968b10230f707501c0091a8ac118f86e87aae1ac00257aee29c3345bd3839154977acd378fc1b2197f5c1fd8e12262f9c2974fb92dc481eeb51aadd44a8851f61b93a84ba57f2870df0423d289bfdcfe634f9ecb7d7c6110a95b49418a2dd6663377690275c205b3efa79a0a77c92567fb429d8ee437312a39df7516dc238f7b9414938223d7ec24d256d3fb3a5954a7c75dbd79486d49ba6bb38a7ccce0f58700260b71319adf98ab8684e34913abe2d9d97193e2
 TAG: e690e89af39ff367f5d40a1b7c7ccd4f
 
+KEY: 31323334353637383930313233343536
+NONCE: 31323334353637383930313233343536
+IN: 48656c6c6f2c20576f726c64
+AD:
+CT: cec189d0e8419b90fb16d555
+TAG: 32893832a8d609224d77c2e56a922282
diff --git a/src/crypto/cipher/test/cipher_test.txt b/src/crypto/cipher/test/cipher_test.txt
index 93cb8f3..21fffdb 100644
--- a/src/crypto/cipher/test/cipher_test.txt
+++ b/src/crypto/cipher/test/cipher_test.txt
@@ -38,6 +38,22 @@
 Ciphertext = 3FE301C962AC01D02213763C1CBD4CDC799657C064ECF5D41C673812CFDE9675
 
 
+# DES EDE CBC tests
+Cipher = DES-EDE-CBC
+Key = 0123456789abcdeff1e0d3c2b5a49786
+IV = fedcba9876543210
+Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000
+Ciphertext = 7948C0DA4FE91CD815DCA96DBC9B60A857EB954F4DEB08EB98722642AE69257B
+
+
+# DES EDE tests
+Cipher = DES-EDE
+Key = 0123456789abcdeff1e0d3c2b5a49786
+IV = fedcba9876543210
+Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000
+Ciphertext = 22E889402E28422F8167AD279D90A566DA75B734E12C671FC2669AECB3E4FE8F
+
+
 # AES 128 ECB tests (from FIPS-197 test vectors, encrypt)
 Cipher = AES-128-ECB
 Key = 000102030405060708090A0B0C0D0E0F
@@ -360,6 +376,13 @@
 AAD = 00000000000000000000000000000000101112131415161718191a1b1c1d1e1f
 Tag = 3b629ccfbc1119b7319e1dce2cd6fd6d
 
+Cipher = AES-128-GCM
+Key = 31323334353637383930313233343536
+IV = 31323334353637383930313233343536
+Plaintext = 48656c6c6f2c20576f726c64
+Ciphertext = cec189d0e8419b90fb16d555
+Tag = 32893832a8d609224d77c2e56a922282
+AAD =
 
 # OFB tests from OpenSSL upstream.
 
@@ -535,3 +558,40 @@
 Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
 Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
 Ciphertext = 9A4B41BA738D6C72FB16691603C18E0E
+
+# DES ECB tests
+
+Cipher = DES-ECB
+Key = 0000000000000000
+Plaintext = 0000000000000000
+Ciphertext = 8CA64DE9C1B123A7
+
+Cipher = DES-ECB
+Key = FFFFFFFFFFFFFFFF
+Plaintext = FFFFFFFFFFFFFFFF
+Ciphertext = 7359B2163E4EDC58
+
+Cipher = DES-ECB
+Key = 3000000000000000
+Plaintext = 1000000000000001
+Ciphertext = 958E6E627A05557B
+
+Cipher = DES-ECB
+Key = 1111111111111111
+Plaintext = 1111111111111111
+Ciphertext = F40379AB9E0EC533
+
+Cipher = DES-ECB
+Key = 0123456789ABCDEF
+Plaintext = 1111111111111111
+Ciphertext = 17668DFC7292532D
+
+Cipher = DES-ECB
+Key = 1111111111111111
+Plaintext = 0123456789ABCDEF
+Ciphertext = 8A5AE1F81AB8F2DD
+
+Cipher = DES-ECB
+Key = FEDCBA9876543210
+Plaintext = 0123456789ABCDEF
+Ciphertext = ED39D950FA74BCC4
diff --git a/src/crypto/cmac/CMakeLists.txt b/src/crypto/cmac/CMakeLists.txt
index 8ebd80c..bb3abc3 100644
--- a/src/crypto/cmac/CMakeLists.txt
+++ b/src/crypto/cmac/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   cmac
@@ -12,6 +12,8 @@
   cmac_test
 
   cmac_test.cc
+
+  $<TARGET_OBJECTS:test_support>
 )
 
 target_link_libraries(cmac_test crypto)
diff --git a/src/crypto/cmac/cmac_test.cc b/src/crypto/cmac/cmac_test.cc
index 0f06860..53f45d1 100644
--- a/src/crypto/cmac/cmac_test.cc
+++ b/src/crypto/cmac/cmac_test.cc
@@ -19,16 +19,13 @@
 #include <openssl/cmac.h>
 
 #include "../test/scoped_types.h"
+#include "../test/test_util.h"
 
 
-static void dump(const uint8_t *got, const uint8_t *expected, size_t len) {
-  ScopedBIO bio(BIO_new_fp(stderr, 0 /* don't close */));
-
-  BIO_puts(bio.get(), "\nGot:\n");
-  BIO_hexdump(bio.get(), got, len, 2 /* indent */);
-  BIO_puts(bio.get(), "Expected:\n");
-  BIO_hexdump(bio.get(), expected, len, 2 /* indent */);
-  BIO_flush(bio.get());
+static void dump(const uint8_t *got, const uint8_t *want, size_t len) {
+  hexdump(stderr, "got :", got, len);
+  hexdump(stderr, "want:", want, len);
+  fflush(stderr);
 }
 
 static int test(const char *name, const uint8_t *key, size_t key_len,
diff --git a/src/crypto/conf/CMakeLists.txt b/src/crypto/conf/CMakeLists.txt
index 8046bb8..0a3c795 100644
--- a/src/crypto/conf/CMakeLists.txt
+++ b/src/crypto/conf/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   conf
diff --git a/src/crypto/conf/conf.c b/src/crypto/conf/conf.c
index 213efc5..e098a2c 100644
--- a/src/crypto/conf/conf.c
+++ b/src/crypto/conf/conf.c
@@ -111,6 +111,16 @@
   return conf;
 }
 
+CONF_VALUE *CONF_VALUE_new(void) {
+  CONF_VALUE *v = OPENSSL_malloc(sizeof(CONF_VALUE));
+  if (!v) {
+    OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
+    return NULL;
+  }
+  memset(v, 0, sizeof(CONF_VALUE));
+  return v;
+}
+
 static void value_free_contents(CONF_VALUE *value) {
   if (value->section) {
     OPENSSL_free(value->section);
@@ -137,29 +147,26 @@
     return;
   }
 
-  lh_CONF_VALUE_doall(conf->data, value_free_contents);
+  lh_CONF_VALUE_doall(conf->data, value_free);
   lh_CONF_VALUE_free(conf->data);
   OPENSSL_free(conf);
 }
 
 CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) {
   STACK_OF(CONF_VALUE) *sk = NULL;
-  int ok = 0, i;
+  int ok = 0;
   CONF_VALUE *v = NULL, *old_value;
 
   sk = sk_CONF_VALUE_new_null();
-  v = OPENSSL_malloc(sizeof(CONF_VALUE));
+  v = CONF_VALUE_new();
   if (sk == NULL || v == NULL) {
     goto err;
   }
-  i = strlen(section) + 1;
-  v->section = OPENSSL_malloc(i);
+  v->section = OPENSSL_strdup(section);
   if (v->section == NULL) {
     goto err;
   }
 
-  memcpy(v->section, section, i);
-  v->section[i-1] = 0;
   v->name = NULL;
   v->value = (char *)sk;
 
@@ -285,7 +292,7 @@
       rp = e;
       if (q) {
         if (r != q) {
-          OPENSSL_PUT_ERROR(CONF, str_copy, CONF_R_NO_CLOSE_BRACE);
+          OPENSSL_PUT_ERROR(CONF, CONF_R_NO_CLOSE_BRACE);
           goto err;
         }
         e++;
@@ -304,7 +311,7 @@
       }
       *rp = r;
       if (p == NULL) {
-        OPENSSL_PUT_ERROR(CONF, str_copy, CONF_R_VARIABLE_HAS_NO_VALUE);
+        OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_HAS_NO_VALUE);
         goto err;
       }
       BUF_MEM_grow_clean(buf, (strlen(p) + buf->length - (e - from)));
@@ -372,11 +379,12 @@
   return value->value;
 }
 
-int add_string(const CONF *conf, CONF_VALUE *section, CONF_VALUE *value) {
+static int add_string(const CONF *conf, CONF_VALUE *section,
+                      CONF_VALUE *value) {
   STACK_OF(CONF_VALUE) *section_stack = (STACK_OF(CONF_VALUE)*) section->value;
   CONF_VALUE *old_value;
 
-  value->section = section->section;
+  value->section = OPENSSL_strdup(section->section);
   if (!sk_CONF_VALUE_push(section_stack, value)) {
     return 0;
   }
@@ -505,20 +513,19 @@
   char *start, *psection, *pname;
 
   if ((buff = BUF_MEM_new()) == NULL) {
-    OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_BUF_LIB);
+    OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
     goto err;
   }
 
-  section = (char *)OPENSSL_malloc(10);
+  section = OPENSSL_strdup("default");
   if (section == NULL) {
-    OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
     goto err;
   }
-  BUF_strlcpy(section, "default", 10);
 
   sv = NCONF_new_section(conf, section);
   if (sv == NULL) {
-    OPENSSL_PUT_ERROR(CONF, def_load_bio, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
+    OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
     goto err;
   }
 
@@ -526,7 +533,7 @@
   again = 0;
   for (;;) {
     if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) {
-      OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_BUF_LIB);
+      OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB);
       goto err;
     }
     p = &(buff->data[bufnum]);
@@ -595,7 +602,7 @@
           ss = p;
           goto again;
         }
-        OPENSSL_PUT_ERROR(CONF, def_load_bio, CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
+        OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
         goto err;
       }
       *end = '\0';
@@ -606,7 +613,7 @@
         sv = NCONF_new_section(conf, section);
       }
       if (sv == NULL) {
-        OPENSSL_PUT_ERROR(CONF, def_load_bio, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
+        OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
         goto err;
       }
       continue;
@@ -623,7 +630,7 @@
       }
       p = eat_ws(conf, end);
       if (*p != '=') {
-        OPENSSL_PUT_ERROR(CONF, def_load_bio, CONF_R_MISSING_EQUAL_SIGN);
+        OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_EQUAL_SIGN);
         goto err;
       }
       *end = '\0';
@@ -639,20 +646,17 @@
       p++;
       *p = '\0';
 
-      if (!(v = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) {
-        OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_MALLOC_FAILURE);
+      if (!(v = CONF_VALUE_new())) {
         goto err;
       }
       if (psection == NULL) {
         psection = section;
       }
-      v->name = (char *)OPENSSL_malloc(strlen(pname) + 1);
-      v->value = NULL;
+      v->name = OPENSSL_strdup(pname);
       if (v->name == NULL) {
-        OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_MALLOC_FAILURE);
+        OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
         goto err;
       }
-      BUF_strlcpy(v->name, pname, strlen(pname) + 1);
       if (!str_copy(conf, psection, &(v->value), start)) {
         goto err;
       }
@@ -662,14 +666,14 @@
           tv = NCONF_new_section(conf, psection);
         }
         if (tv == NULL) {
-          OPENSSL_PUT_ERROR(CONF, def_load_bio, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
+          OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
           goto err;
         }
       } else {
         tv = sv;
       }
       if (add_string(conf, tv, v) == 0) {
-        OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_MALLOC_FAILURE);
+        OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE);
         goto err;
       }
       v = NULL;
@@ -715,7 +719,7 @@
   int ret;
 
   if (in == NULL) {
-    OPENSSL_PUT_ERROR(CONF, NCONF_load, ERR_R_SYS_LIB);
+    OPENSSL_PUT_ERROR(CONF, ERR_R_SYS_LIB);
     return 0;
   }
 
@@ -736,7 +740,7 @@
   const char *lstart, *tmpend, *p;
 
   if (list == NULL) {
-    OPENSSL_PUT_ERROR(CONF, CONF_parse_list, CONF_R_LIST_CANNOT_BE_NULL);
+    OPENSSL_PUT_ERROR(CONF, CONF_R_LIST_CANNOT_BE_NULL);
     return 0;
   }
 
diff --git a/src/crypto/conf/internal.h b/src/crypto/conf/internal.h
new file mode 100644
index 0000000..03d1a8f
--- /dev/null
+++ b/src/crypto/conf/internal.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2015, 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_CRYPTO_CONF_INTERNAL_H
+#define OPENSSL_HEADER_CRYPTO_CONF_INTERNAL_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* CONF_VALUE_new returns a freshly allocated and zeroed |CONF_VALUE|. */
+CONF_VALUE *CONF_VALUE_new(void);
+
+
+#if defined(__cplusplus)
+}  /* extern C */
+#endif
+
+#endif  /* OPENSSL_HEADER_CRYPTO_CONF_INTERNAL_H */
diff --git a/src/crypto/cpu-arm.c b/src/crypto/cpu-arm.c
index 74e937b..6e037ab 100644
--- a/src/crypto/cpu-arm.c
+++ b/src/crypto/cpu-arm.c
@@ -24,7 +24,7 @@
 #include <signal.h>
 #endif
 
-#include "arm_arch.h"
+#include <openssl/arm_arch.h>
 
 
 /* We can't include <sys/auxv.h> because the Android SDK version against which
@@ -70,12 +70,12 @@
   siglongjmp(sigill_jmp, signal);
 }
 
-void CRYPTO_arm_neon_probe();
+void CRYPTO_arm_neon_probe(void);
 
 // probe_for_NEON returns 1 if a NEON instruction runs successfully. Because
 // getauxval doesn't exist on Android until Jelly Bean, supporting NEON on
 // older devices requires this.
-static int probe_for_NEON() {
+static int probe_for_NEON(void) {
   int supported = 0;
 
   sigset_t sigmask;
diff --git a/src/crypto/cpu-intel.c b/src/crypto/cpu-intel.c
index df0e127..924bab0 100644
--- a/src/crypto/cpu-intel.c
+++ b/src/crypto/cpu-intel.c
@@ -68,8 +68,58 @@
 #include <stdio.h>
 #include <string.h>
 
-/* OPENSSL_ia32_cpuid is defined in cpu-x86_64-asm.pl. */
-extern uint64_t OPENSSL_ia32_cpuid(uint32_t*);
+#if defined(OPENSSL_WINDOWS)
+#pragma warning(push, 3)
+#include <immintrin.h>
+#include <intrin.h>
+#pragma warning(pop)
+#endif
+
+
+/* OPENSSL_cpuid runs the cpuid instruction. |leaf| is passed in as EAX and ECX
+ * is set to zero. It writes EAX, EBX, ECX, and EDX to |*out_eax| through
+ * |*out_edx|. */
+static void OPENSSL_cpuid(uint32_t *out_eax, uint32_t *out_ebx,
+                          uint32_t *out_ecx, uint32_t *out_edx, uint32_t leaf) {
+#if defined(OPENSSL_WINDOWS)
+  int tmp[4];
+  __cpuid(tmp, (int)leaf);
+  *out_eax = (uint32_t)tmp[0];
+  *out_ebx = (uint32_t)tmp[1];
+  *out_ecx = (uint32_t)tmp[2];
+  *out_edx = (uint32_t)tmp[3];
+#elif defined(__pic__) && defined(OPENSSL_32_BIT)
+  /* Inline assembly may not clobber the PIC register. For 32-bit, this is EBX.
+   * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47602. */
+  __asm__ volatile (
+    "xor %%ecx, %%ecx\n"
+    "mov %%ebx, %%edi\n"
+    "cpuid\n"
+    "xchg %%edi, %%ebx\n"
+    : "=a"(*out_eax), "=D"(*out_ebx), "=c"(*out_ecx), "=d"(*out_edx)
+    : "a"(leaf)
+  );
+#else
+  __asm__ volatile (
+    "xor %%ecx, %%ecx\n"
+    "cpuid\n"
+    : "=a"(*out_eax), "=b"(*out_ebx), "=c"(*out_ecx), "=d"(*out_edx)
+    : "a"(leaf)
+  );
+#endif
+}
+
+/* OPENSSL_xgetbv returns the value of an Intel Extended Control Register (XCR).
+ * Currently only XCR0 is defined by Intel so |xcr| should always be zero. */
+static uint64_t OPENSSL_xgetbv(uint32_t xcr) {
+#if defined(OPENSSL_WINDOWS)
+  return (uint64_t)_xgetbv(xcr);
+#else
+  uint32_t eax, edx;
+  __asm__ volatile ("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
+  return (((uint64_t)edx) << 32) | eax;
+#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. */
@@ -91,18 +141,101 @@
 }
 
 void OPENSSL_cpuid_setup(void) {
+  /* Determine the vendor and maximum input value. */
+  uint32_t eax, ebx, ecx, edx;
+  OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0);
+
+  uint32_t num_ids = eax;
+
+  int is_intel = ebx == 0x756e6547 /* Genu */ &&
+                 edx == 0x49656e69 /* ineI */ &&
+                 ecx == 0x6c65746e /* ntel */;
+  int is_amd = ebx == 0x68747541 /* Auth */ &&
+               edx == 0x69746e65 /* enti */ &&
+               ecx == 0x444d4163 /* cAMD */;
+
+  int has_amd_xop = 0;
+  if (is_amd) {
+    /* AMD-specific logic.
+     * See http://developer.amd.com/wordpress/media/2012/10/254811.pdf */
+    OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000000);
+    uint32_t num_extended_ids = eax;
+    if (num_extended_ids >= 0x80000001) {
+      OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000001);
+      if (ecx & (1 << 11)) {
+        has_amd_xop = 1;
+      }
+    }
+  }
+
+  uint32_t extended_features = 0;
+  if (num_ids >= 7) {
+    OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 7);
+    extended_features = ebx;
+  }
+
+  /* Determine the number of cores sharing an L1 data cache to adjust the
+   * hyper-threading bit. */
+  uint32_t cores_per_cache = 0;
+  if (is_amd) {
+    /* AMD CPUs never share an L1 data cache between threads but do set the HTT
+     * bit on multi-core CPUs. */
+    cores_per_cache = 1;
+  } else if (num_ids >= 4) {
+    /* TODO(davidben): The Intel manual says this CPUID leaf enumerates all
+     * caches using ECX and doesn't say which is first. Does this matter? */
+    OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 4);
+    cores_per_cache = 1 + ((eax >> 14) & 0xfff);
+  }
+
+  OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 1);
+
+  /* Adjust the hyper-threading bit. */
+  if (edx & (1 << 28)) {
+    uint32_t num_logical_cores = (ebx >> 16) & 0xff;
+    if (cores_per_cache == 1 || num_logical_cores <= 1) {
+      edx &= ~(1 << 28);
+    }
+  }
+
+  /* Reserved bit #20 was historically repurposed to control the in-memory
+   * representation of RC4 state. Always set it to zero. */
+  edx &= ~(1 << 20);
+
+  /* Reserved bit #30 is repurposed to signal an Intel CPU. */
+  if (is_intel) {
+    edx |= (1 << 30);
+  } else {
+    edx &= ~(1 << 30);
+  }
+
+  /* The SDBG bit is repurposed to denote AMD XOP support. */
+  if (has_amd_xop) {
+    ecx |= (1 << 11);
+  } else {
+    ecx &= ~(1 << 11);
+  }
+
+  uint64_t xcr0 = 0;
+  if (ecx & (1 << 27)) {
+    /* XCR0 may only be queried if the OSXSAVE bit is set. */
+    xcr0 = OPENSSL_xgetbv(0);
+  }
+  /* See Intel manual, section 14.3. */
+  if ((xcr0 & 6) != 6) {
+    /* YMM registers cannot be used. */
+    ecx &= ~(1 << 28); /* AVX */
+    ecx &= ~(1 << 12); /* FMA */
+    ecx &= ~(1 << 11); /* AMD XOP */
+    extended_features &= ~(1 << 5); /* AVX2 */
+  }
+
+  OPENSSL_ia32cap_P[0] = edx;
+  OPENSSL_ia32cap_P[1] = ecx;
+  OPENSSL_ia32cap_P[2] = extended_features;
+  OPENSSL_ia32cap_P[3] = 0;
+
   const char *env1, *env2;
-
-#if defined(OPENSSL_X86_64)
-  OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P);
-#else
-  uint64_t vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P);
-  /* 1<<10 sets a reserved bit to indicate that the variable
-   * was already initialised. */
-  OPENSSL_ia32cap_P[0] = ((uint32_t)vec) | (1 << 10);
-  OPENSSL_ia32cap_P[1] = vec >> 32;
-#endif
-
   env1 = getenv("OPENSSL_ia32cap");
   if (env1 == NULL) {
     return;
diff --git a/src/crypto/cpu-x86-asm.pl b/src/crypto/cpu-x86-asm.pl
deleted file mode 100644
index 319c436..0000000
--- a/src/crypto/cpu-x86-asm.pl
+++ /dev/null
@@ -1,334 +0,0 @@
-#!/usr/bin/env perl
-
-$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
-push(@INC, "${dir}perlasm", "perlasm");
-require "x86asm.pl";
-
-&asm_init($ARGV[0],"crypto/cpu-x86-asm");
-
-for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
-
-&function_begin("OPENSSL_ia32_cpuid");
-	&xor	("edx","edx");
-	&pushf	();
-	&pop	("eax");
-	&mov	("ecx","eax");
-	&xor	("eax",1<<21);
-	&push	("eax");
-	&popf	();
-	&pushf	();
-	&pop	("eax");
-	&xor	("ecx","eax");
-	&xor	("eax","eax");
-	&bt	("ecx",21);
-	&jnc	(&label("nocpuid"));
-	&mov	("esi",&wparam(0));
-	&mov	(&DWP(8,"esi"),"eax");	# clear 3rd word
-	&cpuid	();
-	&mov	("edi","eax");		# max value for standard query level
-
-	&xor	("eax","eax");
-	&cmp	("ebx",0x756e6547);	# "Genu"
-	&setne	(&LB("eax"));
-	&mov	("ebp","eax");
-	&cmp	("edx",0x49656e69);	# "ineI"
-	&setne	(&LB("eax"));
-	&or	("ebp","eax");
-	&cmp	("ecx",0x6c65746e);	# "ntel"
-	&setne	(&LB("eax"));
-	&or	("ebp","eax");		# 0 indicates Intel CPU
-	&jz	(&label("intel"));
-
-	&cmp	("ebx",0x68747541);	# "Auth"
-	&setne	(&LB("eax"));
-	&mov	("esi","eax");
-	&cmp	("edx",0x69746E65);	# "enti"
-	&setne	(&LB("eax"));
-	&or	("esi","eax");
-	&cmp	("ecx",0x444D4163);	# "cAMD"
-	&setne	(&LB("eax"));
-	&or	("esi","eax");		# 0 indicates AMD CPU
-	&jnz	(&label("intel"));
-
-	# AMD specific
-	&mov	("eax",0x80000000);
-	&cpuid	();
-	&cmp	("eax",0x80000001);
-	&jb	(&label("intel"));
-	&mov	("esi","eax");
-	&mov	("eax",0x80000001);
-	&cpuid	();
-	&or	("ebp","ecx");
-	&and	("ebp",1<<11|1);	# isolate XOP bit
-	&cmp	("esi",0x80000008);
-	&jb	(&label("intel"));
-
-	&mov	("eax",0x80000008);
-	&cpuid	();
-	&movz	("esi",&LB("ecx"));	# number of cores - 1
-	&inc	("esi");		# number of cores
-
-	&mov	("eax",1);
-	&xor	("ecx","ecx");
-	&cpuid	();
-	&bt	("edx",28);
-	&jnc	(&label("generic"));
-	&shr	("ebx",16);
-	&and	("ebx",0xff);
-	&cmp	("ebx","esi");
-	&ja	(&label("generic"));
-	&and	("edx",0xefffffff);	# clear hyper-threading bit
-	&jmp	(&label("generic"));
-	
-&set_label("intel");
-	&cmp	("edi",7);
-	&jb	(&label("cacheinfo"));
-
-	&mov	("esi",&wparam(0));
-	&mov	("eax",7);
-	&xor	("ecx","ecx");
-	&cpuid	();
-	&mov	(&DWP(8,"esi"),"ebx");
-
-&set_label("cacheinfo");
-	&cmp	("edi",4);
-	&mov	("edi",-1);
-	&jb	(&label("nocacheinfo"));
-
-	&mov	("eax",4);
-	&mov	("ecx",0);		# query L1D
-	&cpuid	();
-	&mov	("edi","eax");
-	&shr	("edi",14);
-	&and	("edi",0xfff);		# number of cores -1 per L1D
-
-&set_label("nocacheinfo");
-	&mov	("eax",1);
-	&xor	("ecx","ecx");
-	&cpuid	();
-	&and	("edx",0xbfefffff);	# force reserved bits #20, #30 to 0
-	&cmp	("ebp",0);
-	&jne	(&label("notintel"));
-	&or	("edx",1<<30);		# set reserved bit#30 on Intel CPUs
-&set_label("notintel");
-	&bt	("edx",28);		# test hyper-threading bit
-	&jnc	(&label("generic"));
-	&and	("edx",0xefffffff);
-	&cmp	("edi",0);
-	&je	(&label("generic"));
-
-	&or	("edx",0x10000000);
-	&shr	("ebx",16);
-	&cmp	(&LB("ebx"),1);
-	&ja	(&label("generic"));
-	&and	("edx",0xefffffff);	# clear hyper-threading bit if not
-
-&set_label("generic");
-	&and	("ebp",1<<11);		# isolate AMD XOP flag
-	&and	("ecx",0xfffff7ff);	# force 11th bit to 0
-	&mov	("esi","edx");
-	&or	("ebp","ecx");		# merge AMD XOP flag
-
-	&bt	("ecx",27);		# check OSXSAVE bit
-	&jnc	(&label("clear_avx"));
-	&xor	("ecx","ecx");
-	&data_byte(0x0f,0x01,0xd0);	# xgetbv
-	&and	("eax",6);
-	&cmp	("eax",6);
-	&je	(&label("done"));
-	&cmp	("eax",2);
-	&je	(&label("clear_avx"));
-&set_label("clear_xmm");
-	&and	("ebp",0xfdfffffd);	# clear AESNI and PCLMULQDQ bits
-	&and	("esi",0xfeffffff);	# clear FXSR
-&set_label("clear_avx");
-	&and	("ebp",0xefffe7ff);	# clear AVX, FMA and AMD XOP bits
-	&mov	("edi",&wparam(0));
-	&and	(&DWP(8,"edi"),0xffffffdf);	# clear AVX2
-&set_label("done");
-	&mov	("eax","esi");
-	&mov	("edx","ebp");
-&set_label("nocpuid");
-&function_end("OPENSSL_ia32_cpuid");
-
-&external_label("OPENSSL_ia32cap_P");
-
-&function_begin_B("OPENSSL_rdtsc","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
-	&xor	("eax","eax");
-	&xor	("edx","edx");
-	&picmeup("ecx","OPENSSL_ia32cap_P");
-	&bt	(&DWP(0,"ecx"),4);
-	&jnc	(&label("notsc"));
-	&rdtsc	();
-&set_label("notsc");
-	&ret	();
-&function_end_B("OPENSSL_rdtsc");
-
-# This works in Ring 0 only [read DJGPP+MS-DOS+privileged DPMI host],
-# but it's safe to call it on any [supported] 32-bit platform...
-# Just check for [non-]zero return value...
-&function_begin_B("OPENSSL_instrument_halt","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
-	&picmeup("ecx","OPENSSL_ia32cap_P");
-	&bt	(&DWP(0,"ecx"),4);
-	&jnc	(&label("nohalt"));	# no TSC
-
-	&data_word(0x9058900e);		# push %cs; pop %eax
-	&and	("eax",3);
-	&jnz	(&label("nohalt"));	# not enough privileges
-
-	&pushf	();
-	&pop	("eax");
-	&bt	("eax",9);
-	&jnc	(&label("nohalt"));	# interrupts are disabled
-
-	&rdtsc	();
-	&push	("edx");
-	&push	("eax");
-	&halt	();
-	&rdtsc	();
-
-	&sub	("eax",&DWP(0,"esp"));
-	&sbb	("edx",&DWP(4,"esp"));
-	&add	("esp",8);
-	&ret	();
-
-&set_label("nohalt");
-	&xor	("eax","eax");
-	&xor	("edx","edx");
-	&ret	();
-&function_end_B("OPENSSL_instrument_halt");
-
-# Essentially there is only one use for this function. Under DJGPP:
-#
-#	#include <go32.h>
-#	...
-#	i=OPENSSL_far_spin(_dos_ds,0x46c);
-#	...
-# to obtain the number of spins till closest timer interrupt.
-
-&function_begin_B("OPENSSL_far_spin");
-	&pushf	();
-	&pop	("eax");
-	&bt	("eax",9);
-	&jnc	(&label("nospin"));	# interrupts are disabled
-
-	&mov	("eax",&DWP(4,"esp"));
-	&mov	("ecx",&DWP(8,"esp"));
-	&data_word (0x90d88e1e);	# push %ds, mov %eax,%ds
-	&xor	("eax","eax");
-	&mov	("edx",&DWP(0,"ecx"));
-	&jmp	(&label("spin"));
-
-	&align	(16);
-&set_label("spin");
-	&inc	("eax");
-	&cmp	("edx",&DWP(0,"ecx"));
-	&je	(&label("spin"));
-
-	&data_word (0x1f909090);	# pop	%ds
-	&ret	();
-
-&set_label("nospin");
-	&xor	("eax","eax");
-	&xor	("edx","edx");
-	&ret	();
-&function_end_B("OPENSSL_far_spin");
-
-&function_begin_B("OPENSSL_wipe_cpu","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
-	&xor	("eax","eax");
-	&xor	("edx","edx");
-	&picmeup("ecx","OPENSSL_ia32cap_P");
-	&mov	("ecx",&DWP(0,"ecx"));
-	&bt	(&DWP(0,"ecx"),1);
-	&jnc	(&label("no_x87"));
-	if ($sse2) {
-		&and	("ecx",1<<26|1<<24);	# check SSE2 and FXSR bits
-		&cmp	("ecx",1<<26|1<<24);
-		&jne	(&label("no_sse2"));
-		&pxor	("xmm0","xmm0");
-		&pxor	("xmm1","xmm1");
-		&pxor	("xmm2","xmm2");
-		&pxor	("xmm3","xmm3");
-		&pxor	("xmm4","xmm4");
-		&pxor	("xmm5","xmm5");
-		&pxor	("xmm6","xmm6");
-		&pxor	("xmm7","xmm7");
-	&set_label("no_sse2");
-	}
-	# just a bunch of fldz to zap the fp/mm bank followed by finit...
-	&data_word(0xeed9eed9,0xeed9eed9,0xeed9eed9,0xeed9eed9,0x90e3db9b);
-&set_label("no_x87");
-	&lea	("eax",&DWP(4,"esp"));
-	&ret	();
-&function_end_B("OPENSSL_wipe_cpu");
-
-&function_begin_B("OPENSSL_atomic_add");
-	&mov	("edx",&DWP(4,"esp"));	# fetch the pointer, 1st arg
-	&mov	("ecx",&DWP(8,"esp"));	# fetch the increment, 2nd arg
-	&push	("ebx");
-	&nop	();
-	&mov	("eax",&DWP(0,"edx"));
-&set_label("spin");
-	&lea	("ebx",&DWP(0,"eax","ecx"));
-	&nop	();
-	&data_word(0x1ab10ff0);	# lock;	cmpxchg	%ebx,(%edx)	# %eax is envolved and is always reloaded
-	&jne	(&label("spin"));
-	&mov	("eax","ebx");	# OpenSSL expects the new value
-	&pop	("ebx");
-	&ret	();
-&function_end_B("OPENSSL_atomic_add");
-
-# This function can become handy under Win32 in situations when
-# we don't know which calling convention, __stdcall or __cdecl(*),
-# indirect callee is using. In C it can be deployed as
-#
-#ifdef OPENSSL_CPUID_OBJ
-#	type OPENSSL_indirect_call(void *f,...);
-#	...
-#	OPENSSL_indirect_call(func,[up to $max arguments]);
-#endif
-#
-# (*)	it's designed to work even for __fastcall if number of
-#	arguments is 1 or 2!
-&function_begin_B("OPENSSL_indirect_call");
-	{
-	my ($max,$i)=(7,);	# $max has to be chosen as 4*n-1
-				# in order to preserve eventual
-				# stack alignment
-	&push	("ebp");
-	&mov	("ebp","esp");
-	&sub	("esp",$max*4);
-	&mov	("ecx",&DWP(12,"ebp"));
-	&mov	(&DWP(0,"esp"),"ecx");
-	&mov	("edx",&DWP(16,"ebp"));
-	&mov	(&DWP(4,"esp"),"edx");
-	for($i=2;$i<$max;$i++)
-		{
-		# Some copies will be redundant/bogus...
-		&mov	("eax",&DWP(12+$i*4,"ebp"));
-		&mov	(&DWP(0+$i*4,"esp"),"eax");
-		}
-	&call_ptr	(&DWP(8,"ebp"));# make the call...
-	&mov	("esp","ebp");	# ... and just restore the stack pointer
-				# without paying attention to what we called,
-				# (__cdecl *func) or (__stdcall *one).
-	&pop	("ebp");
-	&ret	();
-	}
-&function_end_B("OPENSSL_indirect_call");
-
-&function_begin_B("OPENSSL_ia32_rdrand");
-	&mov	("ecx",8);
-&set_label("loop");
-	&rdrand	("eax");
-	&jc	(&label("break"));
-	&loop	(&label("loop"));
-&set_label("break");
-	&cmp	("eax",0);
-	&cmove	("eax","ecx");
-	&ret	();
-&function_end_B("OPENSSL_ia32_rdrand");
-
-&hidden("OPENSSL_ia32cap_P");
-
-&asm_finish();
diff --git a/src/crypto/cpu-x86_64-asm.pl b/src/crypto/cpu-x86_64-asm.pl
deleted file mode 100644
index 89d7a6c..0000000
--- a/src/crypto/cpu-x86_64-asm.pl
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/usr/bin/env perl
-
-$flavour = shift;
-$output  = shift;
-if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
-
-$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
-
-$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
-( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
-( $xlate="${dir}perlasm/x86_64-xlate.pl" and -f $xlate) or
-die "can't locate x86_64-xlate.pl";
-
-open OUT,"| \"$^X\" $xlate $flavour $output";
-*STDOUT=*OUT;
-
-($arg1,$arg2,$arg3,$arg4)=$win64?("%rcx","%rdx","%r8", "%r9") :	# Win64 order
-				 ("%rdi","%rsi","%rdx","%rcx");	# Unix order
-
-print<<___;
-.text
-
-.globl	OPENSSL_ia32_cpuid
-.type	OPENSSL_ia32_cpuid,\@function,1
-.align	16
-OPENSSL_ia32_cpuid:
-	# On Windows, $arg1 is rcx, but that will be clobbered. So make Windows
-	# use the same register as Unix.
-	mov	$arg1,%rdi
-	mov	%rbx,%r8		# save %rbx
-
-	xor	%eax,%eax
-	mov	%eax,8(%rdi)		# clear 3rd word
-	cpuid
-	mov	%eax,%r11d		# max value for standard query level
-
-	xor	%eax,%eax
-	cmp	\$0x756e6547,%ebx	# "Genu"
-	setne	%al
-	mov	%eax,%r9d
-	cmp	\$0x49656e69,%edx	# "ineI"
-	setne	%al
-	or	%eax,%r9d
-	cmp	\$0x6c65746e,%ecx	# "ntel"
-	setne	%al
-	or	%eax,%r9d		# 0 indicates Intel CPU
-	jz	.Lintel
-
-	cmp	\$0x68747541,%ebx	# "Auth"
-	setne	%al
-	mov	%eax,%r10d
-	cmp	\$0x69746E65,%edx	# "enti"
-	setne	%al
-	or	%eax,%r10d
-	cmp	\$0x444D4163,%ecx	# "cAMD"
-	setne	%al
-	or	%eax,%r10d		# 0 indicates AMD CPU
-	jnz	.Lintel
-
-	# AMD specific
-	# See http://developer.amd.com/wordpress/media/2012/10/254811.pdf (1)
-
-	mov	\$0x80000000,%eax
-	cpuid
-	# Returns "The largest CPUID extended function input value supported by
-	# the processor implementation." in EAX.
-	cmp	\$0x80000001,%eax
-	jb	.Lintel
-	mov	%eax,%r10d
-	mov	\$0x80000001,%eax
-	cpuid
-	# Returns feature bits in ECX. See page 20 of [1].
-	# TODO(fork): I think this should be a MOV.
-	or	%ecx,%r9d
-	and	\$0x00000801,%r9d	# isolate AMD XOP bit, 1<<11
-
-	cmp	\$0x80000008,%r10d
-	jb	.Lintel
-
-	mov	\$0x80000008,%eax
-	cpuid
-	# Returns APIC ID and number of cores in ECX. See page 27 of [1].
-	movzb	%cl,%r10		# number of cores - 1
-	inc	%r10			# number of cores
-
-	mov	\$1,%eax
-	cpuid
-	# See page 13 of [1].
-	bt	\$28,%edx		# test hyper-threading bit
-	jnc	.Lgeneric
-	shr	\$16,%ebx		# number of logical processors
-	cmp	%r10b,%bl
-	ja	.Lgeneric
-	and	\$0xefffffff,%edx	# Clear hyper-threading bit.
-	jmp	.Lgeneric
-
-.Lintel:
-	cmp	\$4,%r11d
-	mov	\$-1,%r10d
-	jb	.Lnocacheinfo
-
-	mov	\$4,%eax
-	mov	\$0,%ecx		# query L1D
-	cpuid
-	mov	%eax,%r10d
-	shr	\$14,%r10d
-	and	\$0xfff,%r10d		# number of cores -1 per L1D
-
-	cmp	\$7,%r11d
-	jb	.Lnocacheinfo
-
-	mov	\$7,%eax
-	xor	%ecx,%ecx
-	cpuid
-	mov	%ebx,8(%rdi)
-
-.Lnocacheinfo:
-	mov	\$1,%eax
-	cpuid
-	# Gets feature information. See table 3-21 in the Intel manual.
-	and	\$0xbfefffff,%edx	# force reserved bits to 0
-	cmp	\$0,%r9d
-	jne	.Lnotintel
-	or	\$0x40000000,%edx	# set reserved bit#30 on Intel CPUs
-.Lnotintel:
-	bt	\$28,%edx		# test hyper-threading bit
-	jnc	.Lgeneric
-	and	\$0xefffffff,%edx	# ~(1<<28) - clear hyper-threading.
-	cmp	\$0,%r10d
-	je	.Lgeneric
-
-	or	\$0x10000000,%edx	# 1<<28
-	shr	\$16,%ebx
-	cmp	\$1,%bl			# see if cache is shared
-	ja	.Lgeneric
-	and	\$0xefffffff,%edx	# ~(1<<28)
-.Lgeneric:
-	and	\$0x00000800,%r9d	# isolate AMD XOP flag
-	and	\$0xfffff7ff,%ecx
-	or	%ecx,%r9d		# merge AMD XOP flag
-
-	mov	%edx,%r10d		# %r9d:%r10d is copy of %ecx:%edx
-	bt	\$27,%r9d		# check OSXSAVE bit
-	jnc	.Lclear_avx
-	xor	%ecx,%ecx		# XCR0
-	.byte	0x0f,0x01,0xd0		# xgetbv
-	and	\$6,%eax		# isolate XMM and YMM state support
-	cmp	\$6,%eax
-	je	.Ldone
-.Lclear_avx:
-	mov	\$0xefffe7ff,%eax	# ~(1<<28|1<<12|1<<11)
-	and	%eax,%r9d		# clear AVX, FMA and AMD XOP bits
-	andl	\$0xffffffdf,8(%rdi)	# cleax AVX2, ~(1<<5)
-.Ldone:
-	movl	%r9d,4(%rdi)
-	movl	%r10d,0(%rdi)
-	mov	%r8,%rbx		# restore %rbx
-	ret
-.size	OPENSSL_ia32_cpuid,.-OPENSSL_ia32_cpuid
-
-___
-
-close STDOUT;	# flush
diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c
index d9bb07e..34d04b4 100644
--- a/src/crypto/crypto.c
+++ b/src/crypto/crypto.c
@@ -55,7 +55,7 @@
 uint32_t OPENSSL_ia32cap_P[4] = {0};
 #elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
 
-#include "arm_arch.h"
+#include <openssl/arm_arch.h>
 
 #if defined(__ARM_NEON__)
 uint32_t OPENSSL_armcap_P = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL;
diff --git a/src/crypto/des/CMakeLists.txt b/src/crypto/des/CMakeLists.txt
index 7d49ff3..f61fa14 100644
--- a/src/crypto/des/CMakeLists.txt
+++ b/src/crypto/des/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   des
diff --git a/src/crypto/des/des.c b/src/crypto/des/des.c
index 9cd75f5..a5669a6 100644
--- a/src/crypto/des/des.c
+++ b/src/crypto/des/des.c
@@ -298,10 +298,8 @@
                                   0, 1, 1, 1, 1, 1, 1, 0};
   uint32_t c, d, t, s, t2;
   const uint8_t *in;
-  uint32_t *k;
   int i;
 
-  k = &schedule->ks->deslong[0];
   in = key->bytes;
 
   c2l(in, c);
@@ -344,10 +342,10 @@
 
     /* table contained 0213 4657 */
     t2 = ((t << 16L) | (s & 0x0000ffffL)) & 0xffffffffL;
-    *(k++) = ROTATE(t2, 30) & 0xffffffffL;
+    schedule->subkeys[i][0] = ROTATE(t2, 30) & 0xffffffffL;
 
     t2 = ((s >> 16L) | (t & 0xffff0000L));
-    *(k++) = ROTATE(t2, 26) & 0xffffffffL;
+    schedule->subkeys[i][1] = ROTATE(t2, 26) & 0xffffffffL;
   }
 }
 
@@ -382,7 +380,6 @@
 
 static void DES_encrypt1(uint32_t *data, const DES_key_schedule *ks, int enc) {
   uint32_t l, r, t, u;
-  const uint32_t *s;
 
   r = data[0];
   l = data[1];
@@ -398,43 +395,42 @@
   r = ROTATE(r, 29) & 0xffffffffL;
   l = ROTATE(l, 29) & 0xffffffffL;
 
-  s = ks->ks->deslong;
   /* I don't know if it is worth the effort of loop unrolling the
    * inner loop */
   if (enc) {
-    D_ENCRYPT(l, r, 0);  /*  1 */
-    D_ENCRYPT(r, l, 2);  /*  2 */
-    D_ENCRYPT(l, r, 4);  /*  3 */
-    D_ENCRYPT(r, l, 6);  /*  4 */
-    D_ENCRYPT(l, r, 8);  /*  5 */
-    D_ENCRYPT(r, l, 10); /*  6 */
-    D_ENCRYPT(l, r, 12); /*  7 */
-    D_ENCRYPT(r, l, 14); /*  8 */
-    D_ENCRYPT(l, r, 16); /*  9 */
-    D_ENCRYPT(r, l, 18); /*  10 */
-    D_ENCRYPT(l, r, 20); /*  11 */
-    D_ENCRYPT(r, l, 22); /*  12 */
-    D_ENCRYPT(l, r, 24); /*  13 */
-    D_ENCRYPT(r, l, 26); /*  14 */
-    D_ENCRYPT(l, r, 28); /*  15 */
-    D_ENCRYPT(r, l, 30); /*  16 */
+    D_ENCRYPT(ks, l, r, 0);
+    D_ENCRYPT(ks, r, l, 1);
+    D_ENCRYPT(ks, l, r, 2);
+    D_ENCRYPT(ks, r, l, 3);
+    D_ENCRYPT(ks, l, r, 4);
+    D_ENCRYPT(ks, r, l, 5);
+    D_ENCRYPT(ks, l, r, 6);
+    D_ENCRYPT(ks, r, l, 7);
+    D_ENCRYPT(ks, l, r, 8);
+    D_ENCRYPT(ks, r, l, 9);
+    D_ENCRYPT(ks, l, r, 10);
+    D_ENCRYPT(ks, r, l, 11);
+    D_ENCRYPT(ks, l, r, 12);
+    D_ENCRYPT(ks, r, l, 13);
+    D_ENCRYPT(ks, l, r, 14);
+    D_ENCRYPT(ks, r, l, 15);
   } else {
-    D_ENCRYPT(l, r, 30); /* 16 */
-    D_ENCRYPT(r, l, 28); /* 15 */
-    D_ENCRYPT(l, r, 26); /* 14 */
-    D_ENCRYPT(r, l, 24); /* 13 */
-    D_ENCRYPT(l, r, 22); /* 12 */
-    D_ENCRYPT(r, l, 20); /* 11 */
-    D_ENCRYPT(l, r, 18); /* 10 */
-    D_ENCRYPT(r, l, 16); /*  9 */
-    D_ENCRYPT(l, r, 14); /*  8 */
-    D_ENCRYPT(r, l, 12); /*  7 */
-    D_ENCRYPT(l, r, 10); /*  6 */
-    D_ENCRYPT(r, l, 8);  /*  5 */
-    D_ENCRYPT(l, r, 6);  /*  4 */
-    D_ENCRYPT(r, l, 4);  /*  3 */
-    D_ENCRYPT(l, r, 2);  /*  2 */
-    D_ENCRYPT(r, l, 0);  /*  1 */
+    D_ENCRYPT(ks, l, r, 15);
+    D_ENCRYPT(ks, r, l, 14);
+    D_ENCRYPT(ks, l, r, 13);
+    D_ENCRYPT(ks, r, l, 12);
+    D_ENCRYPT(ks, l, r, 11);
+    D_ENCRYPT(ks, r, l, 10);
+    D_ENCRYPT(ks, l, r, 9);
+    D_ENCRYPT(ks, r, l, 8);
+    D_ENCRYPT(ks, l, r, 7);
+    D_ENCRYPT(ks, r, l, 6);
+    D_ENCRYPT(ks, l, r, 5);
+    D_ENCRYPT(ks, r, l, 4);
+    D_ENCRYPT(ks, l, r, 3);
+    D_ENCRYPT(ks, r, l, 2);
+    D_ENCRYPT(ks, l, r, 1);
+    D_ENCRYPT(ks, r, l, 0);
   }
 
   /* rotate and clear the top bits on machines with 8byte longs */
@@ -448,7 +444,6 @@
 
 static void DES_encrypt2(uint32_t *data, const DES_key_schedule *ks, int enc) {
   uint32_t l, r, t, u;
-  const uint32_t *s;
 
   r = data[0];
   l = data[1];
@@ -462,52 +457,51 @@
   r = ROTATE(r, 29) & 0xffffffffL;
   l = ROTATE(l, 29) & 0xffffffffL;
 
-  s = ks->ks->deslong;
   /* I don't know if it is worth the effort of loop unrolling the
    * inner loop */
   if (enc) {
-    D_ENCRYPT(l, r, 0);  /*  1 */
-    D_ENCRYPT(r, l, 2);  /*  2 */
-    D_ENCRYPT(l, r, 4);  /*  3 */
-    D_ENCRYPT(r, l, 6);  /*  4 */
-    D_ENCRYPT(l, r, 8);  /*  5 */
-    D_ENCRYPT(r, l, 10); /*  6 */
-    D_ENCRYPT(l, r, 12); /*  7 */
-    D_ENCRYPT(r, l, 14); /*  8 */
-    D_ENCRYPT(l, r, 16); /*  9 */
-    D_ENCRYPT(r, l, 18); /*  10 */
-    D_ENCRYPT(l, r, 20); /*  11 */
-    D_ENCRYPT(r, l, 22); /*  12 */
-    D_ENCRYPT(l, r, 24); /*  13 */
-    D_ENCRYPT(r, l, 26); /*  14 */
-    D_ENCRYPT(l, r, 28); /*  15 */
-    D_ENCRYPT(r, l, 30); /*  16 */
+    D_ENCRYPT(ks, l, r, 0);
+    D_ENCRYPT(ks, r, l, 1);
+    D_ENCRYPT(ks, l, r, 2);
+    D_ENCRYPT(ks, r, l, 3);
+    D_ENCRYPT(ks, l, r, 4);
+    D_ENCRYPT(ks, r, l, 5);
+    D_ENCRYPT(ks, l, r, 6);
+    D_ENCRYPT(ks, r, l, 7);
+    D_ENCRYPT(ks, l, r, 8);
+    D_ENCRYPT(ks, r, l, 9);
+    D_ENCRYPT(ks, l, r, 10);
+    D_ENCRYPT(ks, r, l, 11);
+    D_ENCRYPT(ks, l, r, 12);
+    D_ENCRYPT(ks, r, l, 13);
+    D_ENCRYPT(ks, l, r, 14);
+    D_ENCRYPT(ks, r, l, 15);
   } else {
-    D_ENCRYPT(l, r, 30); /* 16 */
-    D_ENCRYPT(r, l, 28); /* 15 */
-    D_ENCRYPT(l, r, 26); /* 14 */
-    D_ENCRYPT(r, l, 24); /* 13 */
-    D_ENCRYPT(l, r, 22); /* 12 */
-    D_ENCRYPT(r, l, 20); /* 11 */
-    D_ENCRYPT(l, r, 18); /* 10 */
-    D_ENCRYPT(r, l, 16); /*  9 */
-    D_ENCRYPT(l, r, 14); /*  8 */
-    D_ENCRYPT(r, l, 12); /*  7 */
-    D_ENCRYPT(l, r, 10); /*  6 */
-    D_ENCRYPT(r, l, 8);  /*  5 */
-    D_ENCRYPT(l, r, 6);  /*  4 */
-    D_ENCRYPT(r, l, 4);  /*  3 */
-    D_ENCRYPT(l, r, 2);  /*  2 */
-    D_ENCRYPT(r, l, 0);  /*  1 */
+    D_ENCRYPT(ks, l, r, 15);
+    D_ENCRYPT(ks, r, l, 14);
+    D_ENCRYPT(ks, l, r, 13);
+    D_ENCRYPT(ks, r, l, 12);
+    D_ENCRYPT(ks, l, r, 11);
+    D_ENCRYPT(ks, r, l, 10);
+    D_ENCRYPT(ks, l, r, 9);
+    D_ENCRYPT(ks, r, l, 8);
+    D_ENCRYPT(ks, l, r, 7);
+    D_ENCRYPT(ks, r, l, 6);
+    D_ENCRYPT(ks, l, r, 5);
+    D_ENCRYPT(ks, r, l, 4);
+    D_ENCRYPT(ks, l, r, 3);
+    D_ENCRYPT(ks, r, l, 2);
+    D_ENCRYPT(ks, l, r, 1);
+    D_ENCRYPT(ks, r, l, 0);
   }
   /* rotate and clear the top bits on machines with 8byte longs */
   data[0] = ROTATE(l, 3) & 0xffffffffL;
   data[1] = ROTATE(r, 3) & 0xffffffffL;
 }
 
-static void DES_encrypt3(uint32_t *data, const DES_key_schedule *ks1,
-                         const DES_key_schedule *ks2,
-                         const DES_key_schedule *ks3) {
+/* DES_encrypt3 is not static because it's used in decrepit. */
+void DES_encrypt3(uint32_t *data, const DES_key_schedule *ks1,
+                  const DES_key_schedule *ks2, const DES_key_schedule *ks3) {
   uint32_t l, r;
 
   l = data[0];
@@ -525,9 +519,9 @@
   data[1] = r;
 }
 
-static void DES_decrypt3(uint32_t *data, const DES_key_schedule *ks1,
-                         const DES_key_schedule *ks2,
-                         const DES_key_schedule *ks3) {
+/* DES_decrypt3 is not static because it's used in decrepit. */
+void DES_decrypt3(uint32_t *data, const DES_key_schedule *ks1,
+                  const DES_key_schedule *ks2, const DES_key_schedule *ks3) {
   uint32_t l, r;
 
   l = data[0];
@@ -770,3 +764,10 @@
                           int enc) {
   DES_ede3_cbc_encrypt(in, out, len, ks1, ks2, ks1, ivec, enc);
 }
+
+
+/* Deprecated functions. */
+
+void DES_set_key_unchecked(const DES_cblock *key, DES_key_schedule *schedule) {
+  DES_set_key(key, schedule);
+}
diff --git a/src/crypto/des/internal.h b/src/crypto/des/internal.h
index d3a5cec..91559ff 100644
--- a/src/crypto/des/internal.h
+++ b/src/crypto/des/internal.h
@@ -183,13 +183,13 @@
     PERM_OP(l, r, tt, 4, 0x0f0f0f0fL);  \
   }
 
-#define LOAD_DATA(R, S, u, t, E0, E1) \
-  u = R ^ s[S];                            \
-  t = R ^ s[S + 1]
+#define LOAD_DATA(ks, R, S, u, t, E0, E1) \
+  u = R ^ ks->subkeys[S][0];              \
+  t = R ^ ks->subkeys[S][1]
 
-#define D_ENCRYPT(LL, R, S)                                                    \
+#define D_ENCRYPT(ks, LL, R, S)                                                \
   {                                                                            \
-    LOAD_DATA(R, S, u, t, E0, E1);                                             \
+    LOAD_DATA(ks, R, S, u, t, E0, E1);                                         \
     t = ROTATE(t, 4);                                                          \
     LL ^=                                                                      \
         DES_SPtrans[0][(u >> 2L) & 0x3f] ^ DES_SPtrans[2][(u >> 10L) & 0x3f] ^ \
diff --git a/src/crypto/dh/CMakeLists.txt b/src/crypto/dh/CMakeLists.txt
index d0c1da7..1a46512 100644
--- a/src/crypto/dh/CMakeLists.txt
+++ b/src/crypto/dh/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   dh
diff --git a/src/crypto/dh/dh.c b/src/crypto/dh/dh.c
index 96b85f3..d25f358 100644
--- a/src/crypto/dh/dh.c
+++ b/src/crypto/dh/dh.c
@@ -78,7 +78,7 @@
 DH *DH_new_method(const ENGINE *engine) {
   DH *dh = (DH *)OPENSSL_malloc(sizeof(DH));
   if (dh == NULL) {
-    OPENSSL_PUT_ERROR(DH, DH_new_method, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(DH, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
diff --git a/src/crypto/dh/dh_impl.c b/src/crypto/dh/dh_impl.c
index f269412..6cf0abb 100644
--- a/src/crypto/dh/dh_impl.c
+++ b/src/crypto/dh/dh_impl.c
@@ -117,7 +117,7 @@
   }
 
   if (generator <= 1) {
-    OPENSSL_PUT_ERROR(DH, generate_parameters, DH_R_BAD_GENERATOR);
+    OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
     goto err;
   }
   if (generator == DH_GENERATOR_2) {
@@ -165,7 +165,7 @@
 
 err:
   if (!ok) {
-    OPENSSL_PUT_ERROR(DH, generate_parameters, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB);
   }
 
   if (ctx != NULL) {
@@ -242,7 +242,7 @@
 
 err:
   if (ok != 1) {
-    OPENSSL_PUT_ERROR(DH, generate_key, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB);
   }
 
   if (dh->pub_key == NULL) {
@@ -264,7 +264,7 @@
   BIGNUM local_priv;
 
   if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) {
-    OPENSSL_PUT_ERROR(DH, compute_key, DH_R_MODULUS_TOO_LARGE);
+    OPENSSL_PUT_ERROR(DH, DH_R_MODULUS_TOO_LARGE);
     goto err;
   }
 
@@ -279,7 +279,7 @@
   }
 
   if (dh->priv_key == NULL) {
-    OPENSSL_PUT_ERROR(DH, compute_key, DH_R_NO_PRIVATE_VALUE);
+    OPENSSL_PUT_ERROR(DH, DH_R_NO_PRIVATE_VALUE);
     goto err;
   }
 
@@ -290,14 +290,14 @@
   }
 
   if (!DH_check_pub_key(dh, pub_key, &check_result) || check_result) {
-    OPENSSL_PUT_ERROR(DH, compute_key, DH_R_INVALID_PUBKEY);
+    OPENSSL_PUT_ERROR(DH, DH_R_INVALID_PUBKEY);
     goto err;
   }
 
   BN_with_flags(&local_priv, dh->priv_key, BN_FLG_CONSTTIME);
   if (!BN_mod_exp_mont(shared_key, pub_key, &local_priv, dh->p, ctx,
                        mont)) {
-    OPENSSL_PUT_ERROR(DH, compute_key, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB);
     goto err;
   }
 
diff --git a/src/crypto/digest/CMakeLists.txt b/src/crypto/digest/CMakeLists.txt
index 816d116..856e45a 100644
--- a/src/crypto/digest/CMakeLists.txt
+++ b/src/crypto/digest/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   digest
diff --git a/src/crypto/digest/digest.c b/src/crypto/digest/digest.c
index f09948b..eb71b07 100644
--- a/src/crypto/digest/digest.c
+++ b/src/crypto/digest/digest.c
@@ -116,8 +116,7 @@
   uint8_t *tmp_buf = NULL;
 
   if (in == NULL || in->digest == NULL) {
-    OPENSSL_PUT_ERROR(DIGEST, EVP_MD_CTX_copy_ex,
-                      DIGEST_R_INPUT_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_INPUT_NOT_INITIALIZED);
     return 0;
   }
 
@@ -130,15 +129,15 @@
   }
 
   EVP_MD_CTX_cleanup(out);
-  memcpy(out, in, sizeof(EVP_MD_CTX));
 
+  out->digest = in->digest;
   if (in->md_data && in->digest->ctx_size) {
     if (tmp_buf) {
       out->md_data = tmp_buf;
     } else {
       out->md_data = OPENSSL_malloc(in->digest->ctx_size);
       if (!out->md_data) {
-        OPENSSL_PUT_ERROR(DIGEST, EVP_MD_CTX_copy_ex, ERR_R_MALLOC_FAILURE);
+        OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
         return 0;
       }
     }
@@ -146,6 +145,7 @@
   }
 
   assert(in->pctx == NULL || in->pctx_ops != NULL);
+  out->pctx_ops = in->pctx_ops;
   if (in->pctx && in->pctx_ops) {
     out->pctx = in->pctx_ops->dup(in->pctx);
     if (!out->pctx) {
@@ -164,30 +164,20 @@
 
 int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *engine) {
   if (ctx->digest != type) {
-    if (ctx->digest && ctx->digest->ctx_size) {
+    if (ctx->digest && ctx->digest->ctx_size > 0) {
       OPENSSL_free(ctx->md_data);
     }
     ctx->digest = type;
-    if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) {
-      ctx->update = type->update;
+    if (type->ctx_size > 0) {
       ctx->md_data = OPENSSL_malloc(type->ctx_size);
       if (ctx->md_data == NULL) {
-        OPENSSL_PUT_ERROR(DIGEST, EVP_DigestInit_ex, ERR_R_MALLOC_FAILURE);
+        OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
         return 0;
       }
     }
   }
 
   assert(ctx->pctx == NULL || ctx->pctx_ops != NULL);
-  if (ctx->pctx_ops) {
-    if (!ctx->pctx_ops->begin_digest(ctx)) {
-      return 0;
-    }
-  }
-
-  if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) {
-    return 1;
-  }
 
   ctx->digest->init(ctx);
   return 1;
@@ -199,7 +189,7 @@
 }
 
 int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
-  ctx->update(ctx, data, len);
+  ctx->digest->update(ctx, data, len);
   return 1;
 }
 
@@ -214,7 +204,7 @@
 }
 
 int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md, unsigned int *size) {
-  EVP_DigestFinal_ex(ctx, md, size);
+  (void)EVP_DigestFinal_ex(ctx, md, size);
   EVP_MD_CTX_cleanup(ctx);
   return 1;
 }
@@ -253,10 +243,6 @@
   return EVP_MD_type(EVP_MD_CTX_md(ctx));
 }
 
-void EVP_MD_CTX_set_flags(EVP_MD_CTX *ctx, uint32_t flags) {
-  ctx->flags |= flags;
-}
-
 int EVP_add_digest(const EVP_MD *digest) {
   return 1;
 }
diff --git a/src/crypto/digest/digests.c b/src/crypto/digest/digests.c
index f5eda36..3307f26 100644
--- a/src/crypto/digest/digests.c
+++ b/src/crypto/digest/digests.c
@@ -67,7 +67,7 @@
 #include "internal.h"
 
 #if defined(NDEBUG)
-#define CHECK(x) x
+#define CHECK(x) (void) (x)
 #else
 #define CHECK(x) assert(x)
 #endif
@@ -262,6 +262,7 @@
 };
 
 static const struct nid_to_digest nid_to_digest_mapping[] = {
+  { NID_md4, EVP_md4, SN_md4, LN_md4 },
   { NID_md5, EVP_md5, SN_md5, LN_md5 },
   { NID_sha1, EVP_sha1, SN_sha1, LN_sha1 },
   { NID_sha224, EVP_sha224, SN_sha224, LN_sha224 },
diff --git a/src/crypto/digest/internal.h b/src/crypto/digest/internal.h
index 1572fa8..e3d812a 100644
--- a/src/crypto/digest/internal.h
+++ b/src/crypto/digest/internal.h
@@ -92,7 +92,7 @@
 };
 
 /* evp_md_pctx_ops contains function pointers to allow the |pctx| member of
- * |EVP_MD_CTX| to be manipulated without breaking laying by calling EVP
+ * |EVP_MD_CTX| to be manipulated without breaking layering by calling EVP
  * functions. */
 struct evp_md_pctx_ops {
   /* free is called when an |EVP_MD_CTX| is being freed and the |pctx| also
@@ -102,23 +102,8 @@
   /* dup is called when an |EVP_MD_CTX| is copied and so the |pctx| also needs
    * to be copied. */
   EVP_PKEY_CTX* (*dup) (EVP_PKEY_CTX *pctx);
-
-  /* begin_digest is called when a new digest operation is started. It returns
-   * one on success and zero otherwise. */
-  int (*begin_digest) (EVP_MD_CTX *ctx);
 };
 
-/* EVP_MD_CTX_set_flags ORs |flags| into the flags member of |ctx|. */
-OPENSSL_EXPORT void EVP_MD_CTX_set_flags(EVP_MD_CTX *ctx, uint32_t flags);
-
-/* EVP_MD_CTX_FLAG_NO_INIT causes the |EVP_MD|'s |init| function not to be
- * called, the |update| member not to be copied from the |EVP_MD| in
- * |EVP_DigestInit_ex| and for |md_data| not to be initialised.
- *
- * TODO(davidben): This is an implementation detail of |EVP_PKEY_HMAC| and can
- * be removed when it is gone. */
-#define EVP_MD_CTX_FLAG_NO_INIT 1
-
 
 #if defined(__cplusplus)
 }  /* extern C */
diff --git a/src/crypto/dsa/CMakeLists.txt b/src/crypto/dsa/CMakeLists.txt
index 1bb8b63..e8b7793 100644
--- a/src/crypto/dsa/CMakeLists.txt
+++ b/src/crypto/dsa/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   dsa
diff --git a/src/crypto/dsa/dsa.c b/src/crypto/dsa/dsa.c
index 65444b1..3ff29c4 100644
--- a/src/crypto/dsa/dsa.c
+++ b/src/crypto/dsa/dsa.c
@@ -82,7 +82,7 @@
 DSA *DSA_new_method(const ENGINE *engine) {
   DSA *dsa = (DSA *)OPENSSL_malloc(sizeof(DSA));
   if (dsa == NULL) {
-    OPENSSL_PUT_ERROR(DSA, DSA_new_method, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(DSA, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
diff --git a/src/crypto/dsa/dsa_asn1.c b/src/crypto/dsa/dsa_asn1.c
index 933fba7..b6b3fa4 100644
--- a/src/crypto/dsa/dsa_asn1.c
+++ b/src/crypto/dsa/dsa_asn1.c
@@ -73,7 +73,7 @@
   DSA_SIG *sig;
   sig = OPENSSL_malloc(sizeof(DSA_SIG));
   if (!sig) {
-    OPENSSL_PUT_ERROR(DSA, dsa_sig_cb, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(DSA, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
diff --git a/src/crypto/dsa/dsa_impl.c b/src/crypto/dsa/dsa_impl.c
index 2ab8ba8..b10610d 100644
--- a/src/crypto/dsa/dsa_impl.c
+++ b/src/crypto/dsa/dsa_impl.c
@@ -83,7 +83,7 @@
   int ret = 0;
 
   if (!dsa->p || !dsa->q || !dsa->g) {
-    OPENSSL_PUT_ERROR(DSA, sign_setup, DSA_R_MISSING_PARAMETERS);
+    OPENSSL_PUT_ERROR(DSA, DSA_R_MISSING_PARAMETERS);
     return 0;
   }
 
@@ -171,7 +171,7 @@
 
 err:
   if (!ret) {
-    OPENSSL_PUT_ERROR(DSA, sign_setup, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(DSA, ERR_R_BN_LIB);
     if (r != NULL) {
       BN_clear_free(r);
     }
@@ -269,7 +269,7 @@
 
 err:
   if (!ret) {
-    OPENSSL_PUT_ERROR(DSA, sign, reason);
+    OPENSSL_PUT_ERROR(DSA, reason);
     BN_free(r);
     BN_free(s);
   }
@@ -292,19 +292,19 @@
   *out_valid = 0;
 
   if (!dsa->p || !dsa->q || !dsa->g) {
-    OPENSSL_PUT_ERROR(DSA, verify, DSA_R_MISSING_PARAMETERS);
+    OPENSSL_PUT_ERROR(DSA, DSA_R_MISSING_PARAMETERS);
     return 0;
   }
 
   i = BN_num_bits(dsa->q);
   /* fips 186-3 allows only different sizes for q */
   if (i != 160 && i != 224 && i != 256) {
-    OPENSSL_PUT_ERROR(DSA, verify, DSA_R_BAD_Q_VALUE);
+    OPENSSL_PUT_ERROR(DSA, DSA_R_BAD_Q_VALUE);
     return 0;
   }
 
   if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS) {
-    OPENSSL_PUT_ERROR(DSA, verify, DSA_R_MODULUS_TOO_LARGE);
+    OPENSSL_PUT_ERROR(DSA, DSA_R_MODULUS_TOO_LARGE);
     return 0;
   }
 
@@ -381,7 +381,7 @@
 
 err:
   if (ret != 1) {
-    OPENSSL_PUT_ERROR(DSA, verify, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(DSA, ERR_R_BN_LIB);
   }
   BN_CTX_free(ctx);
   BN_free(&u1);
@@ -487,16 +487,14 @@
 
   bits = (bits + 63) / 64 * 64;
 
-  /* NB: seed_len == 0 is special case: copy generated seed to
-   * seed_in if it is not NULL. */
-  if (seed_len && (seed_len < (size_t)qsize)) {
-    seed_in = NULL; /* seed buffer too small -- ignore */
-  }
-  if (seed_len > (size_t)qsize) {
-    seed_len = qsize; /* App. 2.2 of FIPS PUB 186 allows larger SEED,
-                       * but our internal buffers are restricted to 160 bits*/
-  }
   if (seed_in != NULL) {
+    if (seed_len < (size_t)qsize) {
+      return 0;
+    }
+    if (seed_len > (size_t)qsize) {
+      /* Only consume as much seed as is expected. */
+      seed_len = qsize;
+    }
     memcpy(seed, seed_in, seed_len);
   }
 
@@ -527,21 +525,19 @@
   for (;;) {
     /* Find q. */
     for (;;) {
-      int seed_is_random;
-
       /* step 1 */
       if (!BN_GENCB_call(cb, 0, m++)) {
         goto err;
       }
 
-      if (!seed_len) {
+      int use_random_seed = (seed_in == NULL);
+      if (use_random_seed) {
         if (!RAND_bytes(seed, qsize)) {
           goto err;
         }
-        seed_is_random = 1;
       } else {
-        seed_is_random = 0;
-        seed_len = 0; /* use random seed if 'seed_in' turns out to be bad*/
+        /* If we come back through, use random seed next time. */
+        seed_in = NULL;
       }
       memcpy(buf, seed, qsize);
       memcpy(buf2, seed, qsize);
@@ -570,7 +566,7 @@
       }
 
       /* step 4 */
-      r = BN_is_prime_fasttest_ex(q, DSS_prime_checks, ctx, seed_is_random, cb);
+      r = BN_is_prime_fasttest_ex(q, DSS_prime_checks, ctx, use_random_seed, cb);
       if (r > 0) {
         break;
       }
diff --git a/src/crypto/ec/CMakeLists.txt b/src/crypto/ec/CMakeLists.txt
index b5ebefa..38a91f8 100644
--- a/src/crypto/ec/CMakeLists.txt
+++ b/src/crypto/ec/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   ec
diff --git a/src/crypto/ec/ec.c b/src/crypto/ec/ec.c
index f38eba6..3117f16 100644
--- a/src/crypto/ec/ec.c
+++ b/src/crypto/ec/ec.c
@@ -222,7 +222,11 @@
     {NID_secp224r1, &P224, 0},
     {
         NID_X9_62_prime256v1, &P256,
-#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS)
+    /* MSAN appears to have a bug that causes this P-256 code to be miscompiled
+     * in opt mode. While that is being looked at, don't run the uint128_t
+     * P-256 code under MSAN for now. */
+#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS) && \
+    !defined(MEMORY_SANITIZER)
         EC_GFp_nistp256_method,
 #else
         0,
@@ -237,18 +241,18 @@
   EC_GROUP *ret;
 
   if (meth == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new, EC_R_SLOT_FULL);
+    OPENSSL_PUT_ERROR(EC, EC_R_SLOT_FULL);
     return NULL;
   }
 
   if (meth->group_init == 0) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return NULL;
   }
 
   ret = OPENSSL_malloc(sizeof(EC_GROUP));
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
   memset(ret, 0, sizeof(EC_GROUP));
@@ -276,8 +280,7 @@
   }
 
   if (ret->meth->group_set_curve == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_GROUP_new_curve_GFp,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (!ret->meth->group_set_curve(ret, p, a, b, ctx)) {
@@ -329,7 +332,7 @@
   EC_GROUP *group = NULL;
   EC_POINT *P = NULL;
   BN_CTX *ctx = NULL;
-  BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL, *order = NULL;
+  BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL;
   int ok = 0;
   unsigned param_len;
   const EC_METHOD *meth;
@@ -337,7 +340,7 @@
   const uint8_t *params;
 
   if ((ctx = BN_CTX_new()) == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -348,7 +351,7 @@
   if (!(p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) ||
       !(a = BN_bin2bn(params + 1 * param_len, param_len, NULL)) ||
       !(b = BN_bin2bn(params + 2 * param_len, param_len, NULL))) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     goto err;
   }
 
@@ -356,45 +359,39 @@
     meth = curve->method();
     if (((group = ec_group_new(meth)) == NULL) ||
         (!(group->meth->group_set_curve(group, p, a, b, ctx)))) {
-      OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
       goto err;
     }
   } else {
     if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) {
-      OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
       goto err;
     }
   }
 
   if ((P = EC_POINT_new(group)) == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     goto err;
   }
 
   if (!(x = BN_bin2bn(params + 3 * param_len, param_len, NULL)) ||
       !(y = BN_bin2bn(params + 4 * param_len, param_len, NULL))) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     goto err;
   }
 
   if (!EC_POINT_set_affine_coordinates_GFp(group, P, x, y, ctx)) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     goto err;
   }
-  if (!(order = BN_bin2bn(params + 5 * param_len, param_len, NULL)) ||
-      !BN_set_word(x, (BN_ULONG)data->cofactor)) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_BN_LIB);
+  if (!BN_bin2bn(params + 5 * param_len, param_len, &group->order) ||
+      !BN_set_word(&group->cofactor, (BN_ULONG)data->cofactor)) {
+    OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     goto err;
   }
 
   group->generator = P;
   P = NULL;
-  if (!BN_copy(&group->order, order) ||
-      !BN_set_word(&group->cofactor, (BN_ULONG)data->cofactor)) {
-    OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_BN_LIB);
-    goto err;
-  }
-
   ok = 1;
 
 err:
@@ -407,7 +404,6 @@
   BN_free(p);
   BN_free(a);
   BN_free(b);
-  BN_free(order);
   BN_free(x);
   BN_free(y);
   return group;
@@ -427,7 +423,7 @@
   }
 
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(EC, EC_GROUP_new_by_curve_name, EC_R_UNKNOWN_GROUP);
+    OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
     return NULL;
   }
 
@@ -455,11 +451,11 @@
 
 int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
   if (dest->meth->group_copy == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_GROUP_copy, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (dest->meth != src->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_GROUP_copy, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   if (dest == src) {
@@ -554,8 +550,7 @@
 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);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   return group->meth->group_get_curve(group, out_p, out_a, out_b, ctx);
@@ -565,8 +560,7 @@
 
 int EC_GROUP_get_degree(const EC_GROUP *group) {
   if (group->meth->group_get_degree == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_GROUP_get_degree,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   return group->meth->group_get_degree(group);
@@ -602,17 +596,17 @@
   EC_POINT *ret;
 
   if (group == NULL) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_new, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return NULL;
   }
   if (group->meth->point_init == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_new, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return NULL;
   }
 
   ret = OPENSSL_malloc(sizeof *ret);
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -653,11 +647,11 @@
 
 int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src) {
   if (dest->meth->point_copy == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_copy, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (dest->meth != src->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_copy, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   if (dest == src) {
@@ -676,7 +670,7 @@
 
   t = EC_POINT_new(group);
   if (t == NULL) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_dup, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
   r = EC_POINT_copy(t, a);
@@ -690,12 +684,11 @@
 
 int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) {
   if (group->meth->point_set_to_infinity == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_set_to_infinity,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_set_to_infinity, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->point_set_to_infinity(group, point);
@@ -703,12 +696,11 @@
 
 int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) {
   if (group->meth->is_at_infinity == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_is_at_infinity,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_is_at_infinity, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->is_at_infinity(group, point);
@@ -717,12 +709,11 @@
 int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
                          BN_CTX *ctx) {
   if (group->meth->is_on_curve == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_is_on_curve,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_is_on_curve, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->is_on_curve(group, point, ctx);
@@ -731,11 +722,11 @@
 int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
                  BN_CTX *ctx) {
   if (group->meth->point_cmp == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_cmp, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return -1;
   }
   if ((group->meth != a->meth) || (a->meth != b->meth)) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_cmp, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return -1;
   }
   return group->meth->point_cmp(group, a, b, ctx);
@@ -743,12 +734,11 @@
 
 int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) {
   if (group->meth->make_affine == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_make_affine,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_make_affine, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->make_affine(group, point, ctx);
@@ -759,13 +749,12 @@
   size_t i;
 
   if (group->meth->points_make_affine == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINTs_make_affine,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   for (i = 0; i < num; i++) {
     if (group->meth != points[i]->meth) {
-      OPENSSL_PUT_ERROR(EC, EC_POINTs_make_affine, EC_R_INCOMPATIBLE_OBJECTS);
+      OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
       return 0;
     }
   }
@@ -776,13 +765,11 @@
                                         const EC_POINT *point, BIGNUM *x,
                                         BIGNUM *y, BN_CTX *ctx) {
   if (group->meth->point_get_affine_coordinates == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_get_affine_coordinates_GFp,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_get_affine_coordinates_GFp,
-                      EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->point_get_affine_coordinates(group, point, x, y, ctx);
@@ -792,13 +779,11 @@
                                         const BIGNUM *x, const BIGNUM *y,
                                         BN_CTX *ctx) {
   if (group->meth->point_set_affine_coordinates == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_set_affine_coordinates_GFp,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_set_affine_coordinates_GFp,
-                      EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->point_set_affine_coordinates(group, point, x, y, ctx);
@@ -807,12 +792,12 @@
 int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
                  const EC_POINT *b, BN_CTX *ctx) {
   if (group->meth->add == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_add, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if ((group->meth != r->meth) || (r->meth != a->meth) ||
       (a->meth != b->meth)) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_add, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->add(group, r, a, b, ctx);
@@ -822,11 +807,11 @@
 int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
                  BN_CTX *ctx) {
   if (group->meth->dbl == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_dbl, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if ((group->meth != r->meth) || (r->meth != a->meth)) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_dbl, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->dbl(group, r, a, ctx);
@@ -835,11 +820,11 @@
 
 int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) {
   if (group->meth->invert == 0) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_invert, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != a->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_invert, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->invert(group, a, ctx);
@@ -874,13 +859,11 @@
                                              const BIGNUM *x, const BIGNUM *y,
                                              const BIGNUM *z, BN_CTX *ctx) {
   if (group->meth->point_set_Jprojective_coordinates_GFp == 0) {
-    OPENSSL_PUT_ERROR(EC, ec_point_set_Jprojective_coordinates_GFp,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, ec_point_set_Jprojective_coordinates_GFp,
-                      EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   return group->meth->point_set_Jprojective_coordinates_GFp(group, point, x, y,
diff --git a/src/crypto/ec/ec_asn1.c b/src/crypto/ec/ec_asn1.c
index ff3dca6..31d8944 100644
--- a/src/crypto/ec/ec_asn1.c
+++ b/src/crypto/ec/ec_asn1.c
@@ -168,7 +168,7 @@
   if (ret == NULL) {
     ret = ECPKPARAMETERS_new();
     if (ret == NULL) {
-      OPENSSL_PUT_ERROR(EC, ec_asn1_group2pkparameters, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
       return NULL;
     }
   } else {
@@ -196,7 +196,7 @@
   int nid = NID_undef;
 
   if (params == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_MISSING_PARAMETERS);
+    OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
     return NULL;
   }
 
@@ -222,14 +222,13 @@
   }
 
   if (nid == NID_undef) {
-    OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_NON_NAMED_CURVE);
+    OPENSSL_PUT_ERROR(EC, EC_R_NON_NAMED_CURVE);
     return NULL;
   }
 
   ret = EC_GROUP_new_by_curve_name(nid);
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group,
-                      EC_R_EC_GROUP_NEW_BY_NAME_FAILURE);
+    OPENSSL_PUT_ERROR(EC, EC_R_EC_GROUP_NEW_BY_NAME_FAILURE);
     return NULL;
   }
 
@@ -243,14 +242,14 @@
 
   params = d2i_ECPKPARAMETERS(NULL, inp, len);
   if (params == NULL) {
-    OPENSSL_PUT_ERROR(EC, d2i_ECPKParameters, EC_R_D2I_ECPKPARAMETERS_FAILURE);
+    OPENSSL_PUT_ERROR(EC, EC_R_D2I_ECPKPARAMETERS_FAILURE);
     ECPKPARAMETERS_free(params);
     return NULL;
   }
 
   group = ec_asn1_pkparameters2group(params);
   if (group == NULL) {
-    OPENSSL_PUT_ERROR(EC, d2i_ECPKParameters, EC_R_PKPARAMETERS2GROUP_FAILURE);
+    OPENSSL_PUT_ERROR(EC, EC_R_PKPARAMETERS2GROUP_FAILURE);
     ECPKPARAMETERS_free(params);
     return NULL;
   }
@@ -268,12 +267,12 @@
   int ret = 0;
   ECPKPARAMETERS *tmp = ec_asn1_group2pkparameters(group, NULL);
   if (tmp == NULL) {
-    OPENSSL_PUT_ERROR(EC, i2d_ECPKParameters, EC_R_GROUP2PKPARAMETERS_FAILURE);
+    OPENSSL_PUT_ERROR(EC, EC_R_GROUP2PKPARAMETERS_FAILURE);
     return 0;
   }
   ret = i2d_ECPKPARAMETERS(tmp, outp);
   if (ret == 0) {
-    OPENSSL_PUT_ERROR(EC, i2d_ECPKParameters, EC_R_I2D_ECPKPARAMETERS_FAILURE);
+    OPENSSL_PUT_ERROR(EC, EC_R_I2D_ECPKPARAMETERS_FAILURE);
     ECPKPARAMETERS_free(tmp);
     return 0;
   }
@@ -288,14 +287,14 @@
 
   priv_key = d2i_EC_PRIVATEKEY(NULL, in, len);
   if (priv_key == NULL) {
-    OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     return NULL;
   }
 
   if (a == NULL || *a == NULL) {
     ret = EC_KEY_new();
     if (ret == NULL) {
-      OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
       goto err;
     }
   } else {
@@ -308,7 +307,7 @@
   }
 
   if (ret->group == NULL) {
-    OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     goto err;
   }
 
@@ -319,18 +318,18 @@
         BN_bin2bn(M_ASN1_STRING_data(priv_key->privateKey),
                   M_ASN1_STRING_length(priv_key->privateKey), ret->priv_key);
     if (ret->priv_key == NULL) {
-      OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_BN_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
       goto err;
     }
   } else {
-    OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, EC_R_MISSING_PRIVATE_KEY);
+    OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PRIVATE_KEY);
     goto err;
   }
 
   EC_POINT_free(ret->pub_key);
   ret->pub_key = EC_POINT_new(ret->group);
   if (ret->pub_key == NULL) {
-    OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     goto err;
   }
 
@@ -342,20 +341,20 @@
     pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey);
     /* The first byte (the point conversion form) must be present. */
     if (pub_oct_len <= 0) {
-      OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, EC_R_BUFFER_TOO_SMALL);
+      OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
       goto err;
     }
     /* Save the point conversion form. */
     ret->conv_form = (point_conversion_form_t)(pub_oct[0] & ~0x01);
     if (!EC_POINT_oct2point(ret->group, ret->pub_key, pub_oct, pub_oct_len,
                             NULL)) {
-      OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
       goto err;
     }
   } else {
     if (!EC_POINT_mul(ret->group, ret->pub_key, ret->priv_key, NULL, NULL,
                       NULL)) {
-      OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
       goto err;
     }
     /* Remember the original private-key-only encoding. */
@@ -387,13 +386,13 @@
   EC_PRIVATEKEY *priv_key = NULL;
 
   if (key == NULL || key->group == NULL || key->priv_key == NULL) {
-    OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     goto err;
   }
 
   priv_key = EC_PRIVATEKEY_new();
   if (priv_key == NULL) {
-    OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -402,17 +401,17 @@
   buf_len = BN_num_bytes(&key->group->order);
   buffer = OPENSSL_malloc(buf_len);
   if (buffer == NULL) {
-    OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
   if (!BN_bn2bin_padded(buffer, buf_len, key->priv_key)) {
-    OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     goto err;
   }
 
   if (!M_ASN1_OCTET_STRING_set(priv_key->privateKey, buffer, buf_len)) {
-    OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_ASN1_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_ASN1_LIB);
     goto err;
   }
 
@@ -420,7 +419,7 @@
   if (!(key->enc_flag & EC_PKEY_NO_PARAMETERS)) {
     if ((priv_key->parameters = ec_asn1_group2pkparameters(
              key->group, priv_key->parameters)) == NULL) {
-      OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
       goto err;
     }
   }
@@ -429,7 +428,7 @@
   if (!(key->enc_flag & EC_PKEY_NO_PUBKEY) && key->pub_key != NULL) {
     priv_key->publicKey = M_ASN1_BIT_STRING_new();
     if (priv_key->publicKey == NULL) {
-      OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
       goto err;
     }
 
@@ -439,7 +438,7 @@
     if (tmp_len > buf_len) {
       uint8_t *tmp_buffer = OPENSSL_realloc(buffer, tmp_len);
       if (!tmp_buffer) {
-        OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+        OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
         goto err;
       }
       buffer = tmp_buffer;
@@ -448,21 +447,21 @@
 
     if (!EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, buffer,
                             buf_len, NULL)) {
-      OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
       goto err;
     }
 
     priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
     priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT;
     if (!M_ASN1_BIT_STRING_set(priv_key->publicKey, buffer, buf_len)) {
-      OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_ASN1_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_ASN1_LIB);
       goto err;
     }
   }
 
   ret = i2d_EC_PRIVATEKEY(priv_key, outp);
   if (ret == 0) {
-    OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     goto err;
   }
   ok = 1;
@@ -475,7 +474,7 @@
 
 int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) {
   if (key == NULL) {
-    OPENSSL_PUT_ERROR(EC, i2d_ECParameters, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return 0;
   }
   return i2d_ECPKParameters(key->group, outp);
@@ -485,14 +484,14 @@
   EC_KEY *ret;
 
   if (inp == NULL || *inp == NULL) {
-    OPENSSL_PUT_ERROR(EC, d2i_ECParameters, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return NULL;
   }
 
   if (key == NULL || *key == NULL) {
     ret = EC_KEY_new();
     if (ret == NULL) {
-      OPENSSL_PUT_ERROR(EC, d2i_ECParameters, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
       return NULL;
     }
   } else {
@@ -500,7 +499,7 @@
   }
 
   if (!d2i_ECPKParameters(&ret->group, inp, len)) {
-    OPENSSL_PUT_ERROR(EC, d2i_ECParameters, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     if (key == NULL || *key == NULL) {
       EC_KEY_free(ret);
     }
@@ -517,17 +516,17 @@
   EC_KEY *ret = NULL;
 
   if (keyp == NULL || *keyp == NULL || (*keyp)->group == NULL) {
-    OPENSSL_PUT_ERROR(EC, o2i_ECPublicKey, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return 0;
   }
   ret = *keyp;
   if (ret->pub_key == NULL &&
       (ret->pub_key = EC_POINT_new(ret->group)) == NULL) {
-    OPENSSL_PUT_ERROR(EC, o2i_ECPublicKey, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     return 0;
   }
   if (!EC_POINT_oct2point(ret->group, ret->pub_key, *inp, len, NULL)) {
-    OPENSSL_PUT_ERROR(EC, o2i_ECPublicKey, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     return 0;
   }
   /* save the point conversion form */
@@ -541,7 +540,7 @@
   int new_buffer = 0;
 
   if (key == NULL) {
-    OPENSSL_PUT_ERROR(EC, i2o_ECPublicKey, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return 0;
   }
 
@@ -556,14 +555,14 @@
   if (*outp == NULL) {
     *outp = OPENSSL_malloc(buf_len);
     if (*outp == NULL) {
-      OPENSSL_PUT_ERROR(EC, i2o_ECPublicKey, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
       return 0;
     }
     new_buffer = 1;
   }
   if (!EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, *outp,
                           buf_len, NULL)) {
-    OPENSSL_PUT_ERROR(EC, i2o_ECPublicKey, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     if (new_buffer) {
       OPENSSL_free(*outp);
       *outp = NULL;
diff --git a/src/crypto/ec/ec_key.c b/src/crypto/ec/ec_key.c
index e5cbfed..0defa98 100644
--- a/src/crypto/ec/ec_key.c
+++ b/src/crypto/ec/ec_key.c
@@ -87,7 +87,7 @@
 EC_KEY *EC_KEY_new_method(const ENGINE *engine) {
   EC_KEY *ret = (EC_KEY *)OPENSSL_malloc(sizeof(EC_KEY));
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_new_method, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -127,7 +127,7 @@
 EC_KEY *EC_KEY_new_by_curve_name(int nid) {
   EC_KEY *ret = EC_KEY_new();
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_new_by_curve_name, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
   ret->group = EC_GROUP_new_by_curve_name(nid);
@@ -166,7 +166,7 @@
 
 EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) {
   if (dest == NULL || src == NULL) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_copy, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return NULL;
   }
   /* Copy the parameters. */
@@ -300,12 +300,12 @@
   EC_POINT *point = NULL;
 
   if (!eckey || !eckey->group || !eckey->pub_key) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return 0;
   }
 
   if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, EC_R_POINT_AT_INFINITY);
+    OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
     goto err;
   }
 
@@ -319,7 +319,7 @@
 
   /* testing whether the pub_key is on the elliptic curve */
   if (!EC_POINT_is_on_curve(eckey->group, eckey->pub_key, ctx)) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, EC_R_POINT_IS_NOT_ON_CURVE);
+    OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE);
     goto err;
   }
   /* testing whether pub_key * order is the point at infinity */
@@ -327,15 +327,15 @@
    * to check the private key, below? */
   order = &eckey->group->order;
   if (BN_is_zero(order)) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, EC_R_INVALID_GROUP_ORDER);
+    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER);
     goto err;
   }
   if (!EC_POINT_mul(eckey->group, point, NULL, eckey->pub_key, order, ctx)) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
     goto err;
   }
   if (!EC_POINT_is_at_infinity(eckey->group, point)) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, EC_R_WRONG_ORDER);
+    OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
     goto err;
   }
   /* in case the priv_key is present :
@@ -343,15 +343,15 @@
    */
   if (eckey->priv_key) {
     if (BN_cmp(eckey->priv_key, order) >= 0) {
-      OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, EC_R_WRONG_ORDER);
+      OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
       goto err;
     }
     if (!EC_POINT_mul(eckey->group, point, eckey->priv_key, NULL, NULL, ctx)) {
-      OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
       goto err;
     }
     if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) {
-      OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, EC_R_INVALID_PRIVATE_KEY);
+      OPENSSL_PUT_ERROR(EC, EC_R_INVALID_PRIVATE_KEY);
       goto err;
     }
   }
@@ -371,8 +371,7 @@
   int ok = 0;
 
   if (!key || !key->group || !x || !y) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_set_public_key_affine_coordinates,
-                      ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return 0;
   }
   ctx = BN_CTX_new();
@@ -394,8 +393,7 @@
   /* Check if retrieved coordinates match originals: if not values
    * are out of range. */
   if (BN_cmp(x, tx) || BN_cmp(y, ty)) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_set_public_key_affine_coordinates,
-                      EC_R_COORDINATES_OUT_OF_RANGE);
+    OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
     goto err;
   }
 
@@ -422,7 +420,7 @@
   EC_POINT *pub_key = NULL;
 
   if (!eckey || !eckey->group) {
-    OPENSSL_PUT_ERROR(EC, EC_KEY_generate_key, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return 0;
   }
 
diff --git a/src/crypto/ec/ec_montgomery.c b/src/crypto/ec/ec_montgomery.c
index 74dbc6c..b897000 100644
--- a/src/crypto/ec/ec_montgomery.c
+++ b/src/crypto/ec/ec_montgomery.c
@@ -200,7 +200,7 @@
     goto err;
   }
   if (!BN_MONT_CTX_set(mont, p, ctx)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_group_set_curve, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     goto err;
   }
   one = BN_new();
@@ -232,7 +232,7 @@
 int ec_GFp_mont_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
                           const BIGNUM *b, BN_CTX *ctx) {
   if (group->mont == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_mul, EC_R_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED);
     return 0;
   }
 
@@ -242,7 +242,7 @@
 int ec_GFp_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
                           BN_CTX *ctx) {
   if (group->mont == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_sqr, EC_R_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED);
     return 0;
   }
 
@@ -252,7 +252,7 @@
 int ec_GFp_mont_field_encode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
                              BN_CTX *ctx) {
   if (group->mont == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_encode, EC_R_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED);
     return 0;
   }
 
@@ -262,7 +262,7 @@
 int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
                              BN_CTX *ctx) {
   if (group->mont == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_decode, EC_R_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED);
     return 0;
   }
 
@@ -272,7 +272,7 @@
 int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r,
                                  BN_CTX *ctx) {
   if (group->one == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_set_to_one, EC_R_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED);
     return 0;
   }
 
diff --git a/src/crypto/ec/oct.c b/src/crypto/ec/oct.c
index 816a42f..cb50e17 100644
--- a/src/crypto/ec/oct.c
+++ b/src/crypto/ec/oct.c
@@ -85,7 +85,7 @@
 
   if ((form != POINT_CONVERSION_COMPRESSED) &&
       (form != POINT_CONVERSION_UNCOMPRESSED)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, EC_R_INVALID_FORM);
+    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FORM);
     goto err;
   }
 
@@ -93,7 +93,7 @@
     /* encodes to a single 0 octet */
     if (buf != NULL) {
       if (len < 1) {
-        OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, EC_R_BUFFER_TOO_SMALL);
+        OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
         return 0;
       }
       buf[0] = 0;
@@ -110,7 +110,7 @@
   /* if 'buf' is NULL, just return required length */
   if (buf != NULL) {
     if (len < ret) {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, EC_R_BUFFER_TOO_SMALL);
+      OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
       goto err;
     }
 
@@ -142,21 +142,21 @@
     i = 1;
 
     if (!BN_bn2bin_padded(buf + i, field_len, x)) {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, ERR_R_INTERNAL_ERROR);
+      OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
       goto err;
     }
     i += field_len;
 
     if (form == POINT_CONVERSION_UNCOMPRESSED) {
       if (!BN_bn2bin_padded(buf + i, field_len, y)) {
-        OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, ERR_R_INTERNAL_ERROR);
+        OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
         goto err;
       }
       i += field_len;
     }
 
     if (i != ret) {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, ERR_R_INTERNAL_ERROR);
+      OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
       goto err;
     }
   }
@@ -187,7 +187,7 @@
   int ret = 0;
 
   if (len == 0) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
     return 0;
   }
   form = buf[0];
@@ -195,17 +195,17 @@
   form = form & ~1U;
   if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED) &&
       (form != POINT_CONVERSION_UNCOMPRESSED)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
     return 0;
   }
   if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
     return 0;
   }
 
   if (form == 0) {
     if (len != 1) {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+      OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
       return 0;
     }
 
@@ -217,7 +217,7 @@
       (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
 
   if (len != enc_len) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
     return 0;
   }
 
@@ -231,7 +231,7 @@
   BN_CTX_start(ctx);
   x = BN_CTX_get(ctx);
   y = BN_CTX_get(ctx);
-  if (y == NULL) {
+  if (x == NULL || y == NULL) {
     goto err;
   }
 
@@ -239,7 +239,7 @@
     goto err;
   }
   if (BN_ucmp(x, &group->field) >= 0) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
     goto err;
   }
 
@@ -252,7 +252,7 @@
       goto err;
     }
     if (BN_ucmp(y, &group->field) >= 0) {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+      OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
       goto err;
     }
 
@@ -263,7 +263,7 @@
 
   /* test required by X9.62 */
   if (!EC_POINT_is_on_curve(group, point, ctx)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_POINT_IS_NOT_ON_CURVE);
+    OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE);
     goto err;
   }
 
@@ -279,12 +279,11 @@
                        const uint8_t *buf, size_t len, BN_CTX *ctx) {
   if (group->meth->oct2point == 0 &&
       !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_oct2point,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_oct2point, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
@@ -299,12 +298,11 @@
                           size_t len, BN_CTX *ctx) {
   if (group->meth->point2oct == 0 &&
       !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_point2oct,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_point2oct, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
@@ -406,9 +404,9 @@
     if (ERR_GET_LIB(err) == ERR_LIB_BN &&
         ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) {
       ERR_clear_error();
-      OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates, EC_R_INVALID_COMPRESSED_POINT);
+      OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT);
     } else {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates, ERR_R_BN_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     }
     goto err;
   }
@@ -423,12 +421,10 @@
       }
 
       if (kron == 1) {
-        OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates,
-                          EC_R_INVALID_COMPRESSION_BIT);
+        OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT);
       } else {
         /* BN_mod_sqrt() should have cought this error (not a square) */
-        OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates,
-                          EC_R_INVALID_COMPRESSED_POINT);
+        OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT);
       }
       goto err;
     }
@@ -437,8 +433,7 @@
     }
   }
   if (y_bit != BN_is_odd(y)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates,
-                      ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
     goto err;
   }
 
@@ -459,13 +454,11 @@
                                             int y_bit, BN_CTX *ctx) {
   if (group->meth->point_set_compressed_coordinates == 0 &&
       !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_set_compressed_coordinates_GFp,
-                      ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+    OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
     return 0;
   }
   if (group->meth != point->meth) {
-    OPENSSL_PUT_ERROR(EC, EC_POINT_set_compressed_coordinates_GFp,
-                      EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
   if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
diff --git a/src/crypto/ec/p256-64.c b/src/crypto/ec/p256-64.c
index fdb942c..3946b29 100644
--- a/src/crypto/ec/p256-64.c
+++ b/src/crypto/ec/p256-64.c
@@ -125,7 +125,7 @@
 /* BN_to_felem converts an OpenSSL BIGNUM into an felem. */
 static int BN_to_felem(felem out, const BIGNUM *bn) {
   if (BN_is_negative(bn)) {
-    OPENSSL_PUT_ERROR(EC, BN_to_felem, EC_R_BIGNUM_OUT_OF_RANGE);
+    OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE);
     return 0;
   }
 
@@ -134,7 +134,7 @@
   memset(b_out, 0, sizeof(b_out));
   unsigned num_bytes = BN_num_bytes(bn);
   if (num_bytes > sizeof(b_out)) {
-    OPENSSL_PUT_ERROR(EC, BN_to_felem, EC_R_BIGNUM_OUT_OF_RANGE);
+    OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE);
     return 0;
   }
 
@@ -1638,8 +1638,7 @@
   if (BN_cmp(curve_p, p) ||
       BN_cmp(curve_a, a) ||
       BN_cmp(curve_b, b)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_nistp256_group_set_curve,
-                      EC_R_WRONG_CURVE_PARAMETERS);
+    OPENSSL_PUT_ERROR(EC, EC_R_WRONG_CURVE_PARAMETERS);
     goto err;
   }
   ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
@@ -1661,8 +1660,7 @@
   longfelem tmp;
 
   if (EC_POINT_is_at_infinity(group, point)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_nistp256_point_get_affine_coordinates,
-                      EC_R_POINT_AT_INFINITY);
+    OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
     return 0;
   }
   if (!BN_to_felem(x_in, &point->X) ||
@@ -1677,8 +1675,7 @@
   felem_reduce(x_in, tmp);
   felem_contract(x_out, x_in);
   if (x != NULL && !smallfelem_to_BN(x, x_out)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_nistp256_point_get_affine_coordinates,
-                      ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     return 0;
   }
   felem_mul(tmp, z1, z2);
@@ -1687,8 +1684,7 @@
   felem_reduce(y_in, tmp);
   felem_contract(y_out, y_in);
   if (y != NULL && !smallfelem_to_BN(y, y_out)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_nistp256_point_get_affine_coordinates,
-                      ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     return 0;
   }
   return 1;
@@ -1763,7 +1759,7 @@
     if (!smallfelem_to_BN(x, g_pre_comp[0][1][0]) ||
         !smallfelem_to_BN(y, g_pre_comp[0][1][1]) ||
         !smallfelem_to_BN(z, g_pre_comp[0][1][2])) {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_nistp256_points_mul, ERR_R_BN_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
       goto err;
     }
     if (!ec_point_set_Jprojective_coordinates_GFp(group, generator, x, y, z,
@@ -1794,7 +1790,7 @@
     }
     if (secrets == NULL || pre_comp == NULL ||
         (mixed && tmp_smallfelems == NULL)) {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_nistp256_points_mul, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
       goto err;
     }
 
@@ -1818,7 +1814,7 @@
           /* this is an unusual input, and we don't guarantee
            * constant-timeness. */
           if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) {
-            OPENSSL_PUT_ERROR(EC, ec_GFp_nistp256_points_mul, ERR_R_BN_LIB);
+            OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
             goto err;
           }
           num_bytes = BN_bn2bin(tmp_scalar, tmp);
@@ -1863,7 +1859,7 @@
       /* this is an unusual input, and we don't guarantee
        * constant-timeness. */
       if (!BN_nnmod(tmp_scalar, scalar, &group->order, ctx)) {
-        OPENSSL_PUT_ERROR(EC, ec_GFp_nistp256_points_mul, ERR_R_BN_LIB);
+        OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
         goto err;
       }
       num_bytes = BN_bn2bin(tmp_scalar, tmp);
@@ -1889,7 +1885,7 @@
   if (!smallfelem_to_BN(x, x_in) ||
       !smallfelem_to_BN(y, y_in) ||
       !smallfelem_to_BN(z, z_in)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_nistp256_points_mul, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     goto err;
   }
   ret = ec_point_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx);
diff --git a/src/crypto/ec/simple.c b/src/crypto/ec/simple.c
index 69fd2e4..c62199c 100644
--- a/src/crypto/ec/simple.c
+++ b/src/crypto/ec/simple.c
@@ -172,7 +172,7 @@
 
   /* p must be a prime > 3 */
   if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_group_set_curve, EC_R_INVALID_FIELD);
+    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FIELD);
     return 0;
   }
 
@@ -283,8 +283,7 @@
   if (ctx == NULL) {
     ctx = new_ctx = BN_CTX_new();
     if (ctx == NULL) {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_simple_group_check_discriminant,
-                        ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
       goto err;
     }
   }
@@ -492,8 +491,7 @@
                                                const BIGNUM *y, BN_CTX *ctx) {
   if (x == NULL || y == NULL) {
     /* unlike for projective coordinates, we do not tolerate this */
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point_set_affine_coordinates,
-                      ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return 0;
   }
 
@@ -510,8 +508,7 @@
   int ret = 0;
 
   if (EC_POINT_is_at_infinity(group, point)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point_get_affine_coordinates,
-                      EC_R_POINT_AT_INFINITY);
+    OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
     return 0;
   }
 
@@ -527,7 +524,7 @@
   Z_1 = BN_CTX_get(ctx);
   Z_2 = BN_CTX_get(ctx);
   Z_3 = BN_CTX_get(ctx);
-  if (Z_3 == NULL) {
+  if (Z == NULL || Z_1 == NULL || Z_2 == NULL || Z_3 == NULL) {
     goto err;
   }
 
@@ -560,8 +557,7 @@
     }
   } else {
     if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) {
-      OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point_get_affine_coordinates,
-                        ERR_R_BN_LIB);
+      OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
       goto err;
     }
 
@@ -1183,7 +1179,7 @@
     goto err;
   }
   if (!point->Z_is_one) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_make_affine, ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
     goto err;
   }
 
@@ -1269,7 +1265,7 @@
    * non-zero points[i]->Z by its inverse. */
 
   if (!BN_mod_inverse(tmp, prod_Z[num - 1], &group->field, ctx)) {
-    OPENSSL_PUT_ERROR(EC, ec_GFp_simple_points_make_affine, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
     goto err;
   }
 
diff --git a/src/crypto/ec/wnaf.c b/src/crypto/ec/wnaf.c
index ae0d73f..7fa0e1b 100644
--- a/src/crypto/ec/wnaf.c
+++ b/src/crypto/ec/wnaf.c
@@ -100,7 +100,7 @@
 
   ret = (EC_PRE_COMP *)OPENSSL_malloc(sizeof(EC_PRE_COMP));
   if (!ret) {
-    OPENSSL_PUT_ERROR(EC, ec_pre_comp_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     return ret;
   }
   ret->blocksize = 8; /* default */
@@ -158,7 +158,7 @@
   if (BN_is_zero(scalar)) {
     r = OPENSSL_malloc(1);
     if (!r) {
-      OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
       goto err;
     }
     r[0] = 0;
@@ -169,7 +169,7 @@
   if (w <= 0 || w > 7) /* 'signed char' can represent integers with absolute
                           values less than 2^7 */
   {
-    OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
     goto err;
   }
   bit = 1 << w;        /* at most 128 */
@@ -181,7 +181,7 @@
   }
 
   if (scalar->d == NULL || scalar->top == 0) {
-    OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
     goto err;
   }
 
@@ -192,7 +192,7 @@
            * (*ret_len will be set to the actual length, i.e. at most
            * BN_num_bits(scalar) + 1) */
   if (r == NULL) {
-    OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     goto err;
   }
   window_val = scalar->d[0] & mask;
@@ -225,7 +225,7 @@
       }
 
       if (digit <= -bit || digit >= bit || !(digit & 1)) {
-        OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_INTERNAL_ERROR);
+        OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
         goto err;
       }
 
@@ -235,7 +235,7 @@
        * for modified window NAFs, it may also be 2^w
        */
       if (window_val != 0 && window_val != next_bit && window_val != bit) {
-        OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_INTERNAL_ERROR);
+        OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
         goto err;
       }
     }
@@ -246,13 +246,13 @@
     window_val += bit * BN_is_bit_set(scalar, j + w);
 
     if (window_val > next_bit) {
-      OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_INTERNAL_ERROR);
+      OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
       goto err;
     }
   }
 
   if (j > len + 1) {
-    OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
     goto err;
   }
   len = j;
@@ -316,7 +316,7 @@
   int ret = 0;
 
   if (group->meth != r->meth) {
-    OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, EC_R_INCOMPATIBLE_OBJECTS);
+    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
 
@@ -326,7 +326,7 @@
 
   for (i = 0; i < num; i++) {
     if (group->meth != points[i]->meth) {
-      OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, EC_R_INCOMPATIBLE_OBJECTS);
+      OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
       return 0;
     }
   }
@@ -341,7 +341,7 @@
   if (scalar != NULL) {
     generator = EC_GROUP_get0_generator(group);
     if (generator == NULL) {
-      OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, EC_R_UNDEFINED_GENERATOR);
+      OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR);
       goto err;
     }
 
@@ -366,7 +366,7 @@
 
       /* check that pre_comp looks sane */
       if (pre_comp->num != (pre_comp->numblocks * pre_points_per_block)) {
-        OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+        OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
         goto err;
       }
     } else {
@@ -391,7 +391,7 @@
   }
 
   if (!wsize || !wNAF_len || !wNAF || !val_sub) {
-    OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -420,7 +420,7 @@
 
     if (pre_comp == NULL) {
       if (num_scalar != 1) {
-        OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+        OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
         goto err;
       }
       /* we have already generated a wNAF for 'scalar' */
@@ -429,7 +429,7 @@
       size_t tmp_len = 0;
 
       if (num_scalar != 0) {
-        OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+        OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
         goto err;
       }
 
@@ -463,7 +463,8 @@
           /* possibly we can do with fewer blocks than estimated */
           numblocks = (tmp_len + blocksize - 1) / blocksize;
           if (numblocks > pre_comp->numblocks) {
-            OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+            OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
+            OPENSSL_free(tmp_wNAF);
             goto err;
           }
           totalnum = num + numblocks;
@@ -477,7 +478,8 @@
           if (i < totalnum - 1) {
             wNAF_len[i] = blocksize;
             if (tmp_len < blocksize) {
-              OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+              OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
+              OPENSSL_free(tmp_wNAF);
               goto err;
             }
             tmp_len -= blocksize;
@@ -490,7 +492,7 @@
           wNAF[i + 1] = NULL;
           wNAF[i] = OPENSSL_malloc(wNAF_len[i]);
           if (wNAF[i] == NULL) {
-            OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_MALLOC_FAILURE);
+            OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
             OPENSSL_free(tmp_wNAF);
             goto err;
           }
@@ -500,7 +502,7 @@
           }
 
           if (*tmp_points == NULL) {
-            OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+            OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
             OPENSSL_free(tmp_wNAF);
             goto err;
           }
@@ -519,7 +521,7 @@
    */
   val = OPENSSL_malloc((num_val + 1) * sizeof val[0]);
   if (val == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     goto err;
   }
   val[num_val] = NULL; /* pivot element */
@@ -537,7 +539,7 @@
     }
   }
   if (!(v == val + num_val)) {
-    OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
     goto err;
   }
 
@@ -695,7 +697,7 @@
 
   generator = EC_GROUP_get0_generator(group);
   if (generator == NULL) {
-    OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, EC_R_UNDEFINED_GENERATOR);
+    OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR);
     return 0;
   }
 
@@ -721,7 +723,7 @@
     goto err;
   }
   if (BN_is_zero(order)) {
-    OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, EC_R_UNKNOWN_ORDER);
+    OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_ORDER);
     goto err;
   }
 
@@ -749,7 +751,7 @@
 
   points = OPENSSL_malloc(sizeof(EC_POINT *) * (num + 1));
   if (!points) {
-    OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -757,13 +759,13 @@
   var[num] = NULL; /* pivot */
   for (i = 0; i < num; i++) {
     if ((var[i] = EC_POINT_new(group)) == NULL) {
-      OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
       goto err;
     }
   }
 
   if (!(tmp_point = EC_POINT_new(group)) || !(base = EC_POINT_new(group))) {
-    OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -795,7 +797,7 @@
       size_t k;
 
       if (blocksize <= 2) {
-        OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, ERR_R_INTERNAL_ERROR);
+        OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
         goto err;
       }
 
diff --git a/src/crypto/ecdh/CMakeLists.txt b/src/crypto/ecdh/CMakeLists.txt
index 346e72d..8eaeae5 100644
--- a/src/crypto/ecdh/CMakeLists.txt
+++ b/src/crypto/ecdh/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   ecdh
diff --git a/src/crypto/ecdh/ecdh.c b/src/crypto/ecdh/ecdh.c
index a011bab..14856db 100644
--- a/src/crypto/ecdh/ecdh.c
+++ b/src/crypto/ecdh/ecdh.c
@@ -95,7 +95,7 @@
 
   priv = EC_KEY_get0_private_key(priv_key);
   if (priv == NULL) {
-    OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ECDH_R_NO_PRIVATE_VALUE);
+    OPENSSL_PUT_ERROR(ECDH, ECDH_R_NO_PRIVATE_VALUE);
     goto err;
   }
 
@@ -103,35 +103,35 @@
 
   tmp = EC_POINT_new(group);
   if (tmp == NULL) {
-    OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
   if (!EC_POINT_mul(group, tmp, NULL, pub_key, priv, ctx)) {
-    OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ECDH_R_POINT_ARITHMETIC_FAILURE);
+    OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE);
     goto err;
   }
 
   if (!EC_POINT_get_affine_coordinates_GFp(group, tmp, x, y, ctx)) {
-    OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ECDH_R_POINT_ARITHMETIC_FAILURE);
+    OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE);
     goto err;
   }
 
   buflen = (EC_GROUP_get_degree(group) + 7) / 8;
   buf = OPENSSL_malloc(buflen);
   if (buf == NULL) {
-    OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
   if (!BN_bn2bin_padded(buf, buflen, x)) {
-    OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(ECDH, ERR_R_INTERNAL_ERROR);
     goto err;
   }
 
   if (KDF != 0) {
     if (KDF(buf, buflen, out, &outlen) == NULL) {
-      OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ECDH_R_KDF_FAILED);
+      OPENSSL_PUT_ERROR(ECDH, ECDH_R_KDF_FAILED);
       goto err;
     }
     ret = outlen;
diff --git a/src/crypto/ecdsa/CMakeLists.txt b/src/crypto/ecdsa/CMakeLists.txt
index f431e59..e7581be 100644
--- a/src/crypto/ecdsa/CMakeLists.txt
+++ b/src/crypto/ecdsa/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   ecdsa
diff --git a/src/crypto/ecdsa/ecdsa.c b/src/crypto/ecdsa/ecdsa.c
index b71799e..8403d60 100644
--- a/src/crypto/ecdsa/ecdsa.c
+++ b/src/crypto/ecdsa/ecdsa.c
@@ -52,9 +52,11 @@
 
 #include <openssl/ecdsa.h>
 
+#include <assert.h>
 #include <string.h>
 
 #include <openssl/bn.h>
+#include <openssl/bytestring.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
 
@@ -81,16 +83,18 @@
     return eckey->ecdsa_meth->verify(digest, digest_len, sig, sig_len, eckey);
   }
 
-  s = ECDSA_SIG_new();
-  const uint8_t *sigp = sig;
-  if (s == NULL || d2i_ECDSA_SIG(&s, &sigp, sig_len) == NULL ||
-      sigp != sig + sig_len) {
+  /* Decode the ECDSA signature. */
+  s = ECDSA_SIG_from_bytes(sig, sig_len);
+  if (s == NULL) {
     goto err;
   }
 
-  /* Ensure that the signature uses DER and doesn't have trailing garbage. */
-  const int der_len = i2d_ECDSA_SIG(s, &der);
-  if (der_len < 0 || (size_t) der_len != sig_len || memcmp(sig, der, sig_len)) {
+  /* Defend against potential laxness in the DER parser. */
+  size_t der_len;
+  if (!ECDSA_SIG_to_bytes(&der, &der_len, s) ||
+      der_len != sig_len || memcmp(sig, der, sig_len) != 0) {
+    /* This should never happen. crypto/bytestring is strictly DER. */
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_INTERNAL_ERROR);
     goto err;
   }
 
@@ -116,14 +120,14 @@
     digest_len = (num_bits + 7) / 8;
   }
   if (!BN_bin2bn(digest, digest_len, out)) {
-    OPENSSL_PUT_ERROR(ECDSA, digest_to_bn, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     return 0;
   }
 
   /* If still too long truncate remaining bits with a shift */
   if ((8 * digest_len > num_bits) &&
       !BN_rshift(out, out, 8 - (num_bits & 0x7))) {
-    OPENSSL_PUT_ERROR(ECDSA, digest_to_bn, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     return 0;
   }
 
@@ -145,7 +149,7 @@
   const EC_POINT *pub_key;
 
   if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED);
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
     return 0;
   }
 
@@ -153,13 +157,13 @@
   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);
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_MISSING_PARAMETERS);
     return 0;
   }
 
   ctx = BN_CTX_new();
   if (!ctx) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
     return 0;
   }
   BN_CTX_start(ctx);
@@ -168,26 +172,26 @@
   u2 = BN_CTX_get(ctx);
   m = BN_CTX_get(ctx);
   X = BN_CTX_get(ctx);
-  if (!X) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
+  if (order == NULL || u1 == NULL || u2 == NULL || m == NULL || X == NULL) {
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     goto err;
   }
 
   if (!EC_GROUP_get_order(group, order, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
     goto err;
   }
 
   if (BN_is_zero(sig->r) || BN_is_negative(sig->r) ||
       BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) ||
       BN_is_negative(sig->s) || BN_ucmp(sig->s, order) >= 0) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_BAD_SIGNATURE);
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
     ret = 0; /* signature is invalid */
     goto err;
   }
   /* calculate tmp1 = inv(S) mod order */
   if (!BN_mod_inverse(u2, sig->s, order, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     goto err;
   }
   if (!digest_to_bn(m, digest, digest_len, order)) {
@@ -195,30 +199,30 @@
   }
   /* u1 = m * tmp mod order */
   if (!BN_mod_mul(u1, m, u2, order, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     goto err;
   }
   /* u2 = r * w mod q */
   if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     goto err;
   }
 
   point = EC_POINT_new(group);
   if (point == NULL) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
   if (!EC_POINT_mul(group, point, u1, pub_key, u2, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
     goto err;
   }
   if (!EC_POINT_get_affine_coordinates_GFp(group, point, X, NULL, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
     goto err;
   }
   if (!BN_nnmod(u1, X, order, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     goto err;
   }
   /* if the signature is correct u1 is equal to sig->r */
@@ -241,13 +245,13 @@
   int ret = 0;
 
   if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) {
-    OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
     return 0;
   }
 
   if (ctx_in == NULL) {
     if ((ctx = BN_CTX_new()) == NULL) {
-      OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
       return 0;
     }
   } else {
@@ -259,16 +263,16 @@
   order = BN_new();
   X = BN_new();
   if (!k || !r || !order || !X) {
-    OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
   tmp_point = EC_POINT_new(group);
   if (tmp_point == NULL) {
-    OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
     goto err;
   }
   if (!EC_GROUP_get_order(group, order, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
     goto err;
   }
 
@@ -286,8 +290,7 @@
         ok = BN_rand_range(k, order);
       }
       if (!ok) {
-        OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup,
-                          ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
+        OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
         goto err;
       }
     } while (BN_is_zero(k));
@@ -307,23 +310,23 @@
 
     /* compute r the x-coordinate of generator * k */
     if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) {
-      OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
       goto err;
     }
     if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, X, NULL, ctx)) {
-      OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
       goto err;
     }
 
     if (!BN_nnmod(r, X, order, ctx)) {
-      OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_BN_LIB);
+      OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
       goto err;
     }
   } while (BN_is_zero(r));
 
   /* compute the inverse of k */
   if (!BN_mod_inverse(k, k, order, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ecdsa_sign_setup, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
     goto err;
   }
   /* clear old values if necessary */
@@ -365,7 +368,7 @@
   const BIGNUM *priv_key;
 
   if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ECDSA_R_NOT_IMPLEMENTED);
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
     return NULL;
   }
 
@@ -373,25 +376,25 @@
   priv_key = EC_KEY_get0_private_key(eckey);
 
   if (group == NULL || priv_key == NULL) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_PASSED_NULL_PARAMETER);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
     return NULL;
   }
 
   ret = ECDSA_SIG_new();
   if (!ret) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
   s = ret->s;
 
   if ((ctx = BN_CTX_new()) == NULL || (order = BN_new()) == NULL ||
       (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
   if (!EC_GROUP_get_order(group, order, ctx)) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
     goto err;
   }
   if (!digest_to_bn(m, digest, digest_len, order)) {
@@ -400,35 +403,35 @@
   for (;;) {
     if (in_kinv == NULL || in_r == NULL) {
       if (!ecdsa_sign_setup(eckey, ctx, &kinv, &ret->r, digest, digest_len)) {
-        OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_ECDSA_LIB);
+        OPENSSL_PUT_ERROR(ECDSA, ERR_R_ECDSA_LIB);
         goto err;
       }
       ckinv = kinv;
     } else {
       ckinv = in_kinv;
       if (BN_copy(ret->r, in_r) == NULL) {
-        OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_MALLOC_FAILURE);
+        OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
         goto err;
       }
     }
 
     if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) {
-      OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_BN_LIB);
+      OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
       goto err;
     }
     if (!BN_mod_add_quick(s, tmp, m, order)) {
-      OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_BN_LIB);
+      OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
       goto err;
     }
     if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
-      OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_BN_LIB);
+      OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
       goto err;
     }
     if (BN_is_zero(s)) {
       /* if kinv and r have been supplied by the caller
        * don't to generate new kinv and r values */
       if (in_kinv != NULL && in_r != NULL) {
-        OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ECDSA_R_NEED_NEW_SETUP_VALUES);
+        OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NEED_NEW_SETUP_VALUES);
         goto err;
       }
     } else {
@@ -455,20 +458,36 @@
 int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len,
                   uint8_t *sig, unsigned int *sig_len, const BIGNUM *kinv,
                   const BIGNUM *r, EC_KEY *eckey) {
+  int ret = 0;
   ECDSA_SIG *s = NULL;
 
   if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
-    OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_ex, ECDSA_R_NOT_IMPLEMENTED);
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
     *sig_len = 0;
-    return 0;
+    goto err;
   }
 
   s = ECDSA_do_sign_ex(digest, digest_len, kinv, r, eckey);
   if (s == NULL) {
     *sig_len = 0;
-    return 0;
+    goto err;
   }
-  *sig_len = i2d_ECDSA_SIG(s, &sig);
+
+  CBB cbb;
+  CBB_zero(&cbb);
+  size_t len;
+  if (!CBB_init_fixed(&cbb, sig, ECDSA_size(eckey)) ||
+      !ECDSA_SIG_marshal(&cbb, s) ||
+      !CBB_finish(&cbb, NULL, &len)) {
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR);
+    CBB_cleanup(&cbb);
+    *sig_len = 0;
+    goto err;
+  }
+  *sig_len = (unsigned)len;
+  ret = 1;
+
+err:
   ECDSA_SIG_free(s);
-  return 1;
+  return ret;
 }
diff --git a/src/crypto/ecdsa/ecdsa_asn1.c b/src/crypto/ecdsa/ecdsa_asn1.c
index f557ca7..f2d7c36 100644
--- a/src/crypto/ecdsa/ecdsa_asn1.c
+++ b/src/crypto/ecdsa/ecdsa_asn1.c
@@ -52,45 +52,33 @@
 
 #include <openssl/ecdsa.h>
 
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
 #include <openssl/ec_key.h>
 #include <openssl/mem.h>
 
 #include "../ec/internal.h"
 
 
-DECLARE_ASN1_FUNCTIONS_const(ECDSA_SIG);
-DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECDSA_SIG, ECDSA_SIG);
-
-ASN1_SEQUENCE(ECDSA_SIG) = {
-    ASN1_SIMPLE(ECDSA_SIG, r, CBIGNUM),
-    ASN1_SIMPLE(ECDSA_SIG, s, CBIGNUM),
-} ASN1_SEQUENCE_END(ECDSA_SIG);
-
-IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ECDSA_SIG, ECDSA_SIG, ECDSA_SIG);
-
 size_t ECDSA_size(const EC_KEY *key) {
-  size_t ret, i, group_order_size;
-  ASN1_INTEGER bs;
-  BIGNUM *order = NULL;
-  unsigned char buf[4];
-  const EC_GROUP *group;
+  if (key == NULL) {
+    return 0;
+  }
 
+  size_t group_order_size;
   if (key->ecdsa_meth && key->ecdsa_meth->group_order_size) {
     group_order_size = key->ecdsa_meth->group_order_size(key);
   } else {
-    size_t num_bits;
-
-    if (key == NULL) {
-      return 0;
-    }
-    group = EC_KEY_get0_group(key);
+    const EC_GROUP *group = EC_KEY_get0_group(key);
     if (group == NULL) {
       return 0;
     }
 
-    order = BN_new();
+    BIGNUM *order = BN_new();
     if (order == NULL) {
       return 0;
     }
@@ -99,21 +87,11 @@
       return 0;
     }
 
-    num_bits = BN_num_bits(order);
-    group_order_size = (num_bits + 7) / 8;
+    group_order_size = BN_num_bytes(order);
+    BN_clear_free(order);
   }
 
-  bs.length = group_order_size;
-  bs.data = buf;
-  bs.type = V_ASN1_INTEGER;
-  /* If the top bit is set the ASN.1 encoding is 1 larger. */
-  buf[0] = 0xff;
-
-  i = i2d_ASN1_INTEGER(&bs, NULL);
-  i += i; /* r and s */
-  ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE);
-  BN_clear_free(order);
-  return ret;
+  return ECDSA_SIG_max_len(group_order_size);
 }
 
 ECDSA_SIG *ECDSA_SIG_new(void) {
@@ -139,3 +117,134 @@
   BN_free(sig->s);
   OPENSSL_free(sig);
 }
+
+ECDSA_SIG *ECDSA_SIG_parse(CBS *cbs) {
+  ECDSA_SIG *ret = ECDSA_SIG_new();
+  if (ret == NULL) {
+    return NULL;
+  }
+  CBS child;
+  if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
+      !BN_cbs2unsigned(&child, ret->r) ||
+      !BN_cbs2unsigned(&child, ret->s) ||
+      CBS_len(&child) != 0) {
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
+    ECDSA_SIG_free(ret);
+    return NULL;
+  }
+  return ret;
+}
+
+ECDSA_SIG *ECDSA_SIG_from_bytes(const uint8_t *in, size_t in_len) {
+  CBS cbs;
+  CBS_init(&cbs, in, in_len);
+  ECDSA_SIG *ret = ECDSA_SIG_parse(&cbs);
+  if (ret == NULL || CBS_len(&cbs) != 0) {
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
+    ECDSA_SIG_free(ret);
+    return NULL;
+  }
+  return ret;
+}
+
+int ECDSA_SIG_marshal(CBB *cbb, const ECDSA_SIG *sig) {
+  CBB child;
+  if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) ||
+      !BN_bn2cbb(&child, sig->r) ||
+      !BN_bn2cbb(&child, sig->s) ||
+      !CBB_flush(cbb)) {
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR);
+    return 0;
+  }
+  return 1;
+}
+
+int ECDSA_SIG_to_bytes(uint8_t **out_bytes, size_t *out_len,
+                       const ECDSA_SIG *sig) {
+  CBB cbb;
+  CBB_zero(&cbb);
+  if (!CBB_init(&cbb, 0) ||
+      !ECDSA_SIG_marshal(&cbb, sig) ||
+      !CBB_finish(&cbb, out_bytes, out_len)) {
+    OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR);
+    CBB_cleanup(&cbb);
+    return 0;
+  }
+  return 1;
+}
+
+/* der_len_len returns the number of bytes needed to represent a length of |len|
+ * in DER. */
+static size_t der_len_len(size_t len) {
+  if (len < 0x80) {
+    return 1;
+  }
+  size_t ret = 1;
+  while (len > 0) {
+    ret++;
+    len >>= 8;
+  }
+  return ret;
+}
+
+size_t ECDSA_SIG_max_len(size_t order_len) {
+  /* Compute the maximum length of an |order_len| byte integer. Defensively
+   * assume that the leading 0x00 is included. */
+  size_t integer_len = 1 /* tag */ + der_len_len(order_len + 1) + 1 + order_len;
+  if (integer_len < order_len) {
+    return 0;
+  }
+  /* An ECDSA signature is two INTEGERs. */
+  size_t value_len = 2 * integer_len;
+  if (value_len < integer_len) {
+    return 0;
+  }
+  /* Add the header. */
+  size_t ret = 1 /* tag */ + der_len_len(value_len) + value_len;
+  if (ret < value_len) {
+    return 0;
+  }
+  return ret;
+}
+
+ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **out, const uint8_t **inp, long len) {
+  if (len < 0) {
+    return NULL;
+  }
+  CBS cbs;
+  CBS_init(&cbs, *inp, (size_t)len);
+  ECDSA_SIG *ret = ECDSA_SIG_parse(&cbs);
+  if (ret == NULL) {
+    return NULL;
+  }
+  if (out != NULL) {
+    ECDSA_SIG_free(*out);
+    *out = ret;
+  }
+  *inp += (size_t)len - CBS_len(&cbs);
+  return ret;
+}
+
+int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp) {
+  uint8_t *der;
+  size_t der_len;
+  if (!ECDSA_SIG_to_bytes(&der, &der_len, sig)) {
+    return -1;
+  }
+  if (der_len > INT_MAX) {
+    OPENSSL_PUT_ERROR(ECDSA, ERR_R_OVERFLOW);
+    OPENSSL_free(der);
+    return -1;
+  }
+  if (outp != NULL) {
+    if (*outp == NULL) {
+      *outp = der;
+      der = NULL;
+    } else {
+      memcpy(*outp, der, der_len);
+      *outp += der_len;
+    }
+  }
+  OPENSSL_free(der);
+  return (int)der_len;
+}
diff --git a/src/crypto/ecdsa/ecdsa_test.cc b/src/crypto/ecdsa/ecdsa_test.cc
index a6bd7a1..b916509 100644
--- a/src/crypto/ecdsa/ecdsa_test.cc
+++ b/src/crypto/ecdsa/ecdsa_test.cc
@@ -78,18 +78,13 @@
 
   switch (api) {
     case kEncodedApi: {
-      int sig_len = i2d_ECDSA_SIG(ecdsa_sig, NULL);
-      if (sig_len <= 0) {
+      uint8_t *der;
+      size_t der_len;
+      if (!ECDSA_SIG_to_bytes(&der, &der_len, ecdsa_sig)) {
         return false;
       }
-      std::vector<uint8_t> signature(static_cast<size_t>(sig_len));
-      uint8_t *sig_ptr = bssl::vector_data(&signature);
-      sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr);
-      if (sig_len <= 0) {
-        return false;
-      }
-      actual_result = ECDSA_verify(0, digest, digest_len, bssl::vector_data(&signature),
-                                   signature.size(), eckey);
+      ScopedOpenSSLBytes delete_der(der);
+      actual_result = ECDSA_verify(0, digest, digest_len, der, der_len, eckey);
       break;
     }
 
@@ -267,8 +262,8 @@
     fprintf(out, ".");
     fflush(out);
     // Verify a tampered signature.
-    const uint8_t *sig_ptr = bssl::vector_data(&signature);
-    ScopedECDSA_SIG ecdsa_sig(d2i_ECDSA_SIG(NULL, &sig_ptr, signature.size()));
+    ScopedECDSA_SIG ecdsa_sig(ECDSA_SIG_from_bytes(
+        bssl::vector_data(&signature), signature.size()));
     if (!ecdsa_sig ||
         !TestTamperedSig(out, kEncodedApi, digest, 20, ecdsa_sig.get(),
                          eckey.get(), order.get())) {
@@ -325,11 +320,45 @@
   return true;
 }
 
+static bool TestECDSA_SIG_max_len(size_t order_len) {
+  /* Create the largest possible |ECDSA_SIG| of the given constraints. */
+  ScopedECDSA_SIG sig(ECDSA_SIG_new());
+  if (!sig) {
+    return false;
+  }
+  std::vector<uint8_t> bytes(order_len, 0xff);
+  if (!BN_bin2bn(bssl::vector_data(&bytes), bytes.size(), sig->r) ||
+      !BN_bin2bn(bssl::vector_data(&bytes), bytes.size(), sig->s)) {
+    return false;
+  }
+  /* Serialize it. */
+  uint8_t *der;
+  size_t der_len;
+  if (!ECDSA_SIG_to_bytes(&der, &der_len, sig.get())) {
+    return false;
+  }
+  ScopedOpenSSLBytes delete_der(der);
+
+  size_t max_len = ECDSA_SIG_max_len(order_len);
+  if (max_len != der_len) {
+    fprintf(stderr, "ECDSA_SIG_max_len(%u) returned %u, wanted %u\n",
+            static_cast<unsigned>(order_len), static_cast<unsigned>(max_len),
+            static_cast<unsigned>(der_len));
+    return false;
+  }
+  return true;
+}
+
 int main(void) {
   CRYPTO_library_init();
   ERR_load_crypto_strings();
 
-  if (!TestBuiltin(stdout)) {
+  if (!TestBuiltin(stdout) ||
+      !TestECDSA_SIG_max_len(224/8) ||
+      !TestECDSA_SIG_max_len(256/8) ||
+      !TestECDSA_SIG_max_len(384/8) ||
+      !TestECDSA_SIG_max_len(512/8) ||
+      !TestECDSA_SIG_max_len(10000)) {
     printf("\nECDSA test failed\n");
     ERR_print_errors_fp(stdout);
     return 1;
diff --git a/src/crypto/engine/CMakeLists.txt b/src/crypto/engine/CMakeLists.txt
index e03650e..5667f02 100644
--- a/src/crypto/engine/CMakeLists.txt
+++ b/src/crypto/engine/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   engine
diff --git a/src/crypto/err/CMakeLists.txt b/src/crypto/err/CMakeLists.txt
index 5215eec..8519e51 100644
--- a/src/crypto/err/CMakeLists.txt
+++ b/src/crypto/err/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_custom_command(
   OUTPUT err_data.c
@@ -8,10 +8,8 @@
   asn1.errordata
   bio.errordata
   bn.errordata
-  buf.errordata
   cipher.errordata
   conf.errordata
-  crypto.errordata
   dh.errordata
   digest.errordata
   dsa.errordata
diff --git a/src/crypto/err/asn1.errordata b/src/crypto/err/asn1.errordata
index 44b9c73..55342a0 100644
--- a/src/crypto/err/asn1.errordata
+++ b/src/crypto/err/asn1.errordata
@@ -1,152 +1,88 @@
-ASN1,function,100,ASN1_BIT_STRING_set_bit
-ASN1,function,101,ASN1_ENUMERATED_set
-ASN1,function,102,ASN1_ENUMERATED_to_BN
-ASN1,function,103,ASN1_GENERALIZEDTIME_adj
-ASN1,function,104,ASN1_INTEGER_set
-ASN1,function,105,ASN1_INTEGER_to_BN
-ASN1,function,106,ASN1_OBJECT_new
-ASN1,function,107,ASN1_PCTX_new
-ASN1,function,108,ASN1_STRING_TABLE_add
-ASN1,function,109,ASN1_STRING_set
-ASN1,function,110,ASN1_STRING_type_new
-ASN1,function,111,ASN1_TIME_adj
-ASN1,function,112,ASN1_UTCTIME_adj
-ASN1,function,113,ASN1_d2i_fp
-ASN1,function,114,ASN1_dup
-ASN1,function,115,ASN1_generate_v3
-ASN1,function,116,ASN1_get_object
-ASN1,function,117,ASN1_i2d_bio
-ASN1,function,118,ASN1_i2d_fp
-ASN1,function,119,ASN1_item_d2i_fp
-ASN1,function,120,ASN1_item_dup
-ASN1,function,121,ASN1_item_ex_d2i
-ASN1,function,122,ASN1_item_i2d_bio
-ASN1,function,123,ASN1_item_i2d_fp
-ASN1,function,124,ASN1_item_pack
-ASN1,function,125,ASN1_item_unpack
-ASN1,function,126,ASN1_mbstring_ncopy
-ASN1,function,127,ASN1_template_new
-ASN1,function,128,BIO_new_NDEF
-ASN1,function,129,BN_to_ASN1_ENUMERATED
-ASN1,function,130,BN_to_ASN1_INTEGER
-ASN1,function,131,a2d_ASN1_OBJECT
-ASN1,function,132,a2i_ASN1_ENUMERATED
-ASN1,function,133,a2i_ASN1_INTEGER
-ASN1,function,134,a2i_ASN1_STRING
-ASN1,function,135,append_exp
-ASN1,function,136,asn1_cb
-ASN1,function,137,asn1_check_tlen
-ASN1,function,138,asn1_collate_primitive
-ASN1,function,139,asn1_collect
-ASN1,function,140,asn1_d2i_ex_primitive
-ASN1,function,141,asn1_d2i_read_bio
-ASN1,function,142,asn1_do_adb
-ASN1,function,143,asn1_ex_c2i
-ASN1,function,144,asn1_find_end
-ASN1,function,145,asn1_item_ex_combine_new
-ASN1,function,146,asn1_str2type
-ASN1,function,147,asn1_template_ex_d2i
-ASN1,function,148,asn1_template_noexp_d2i
-ASN1,function,149,bitstr_cb
-ASN1,function,150,c2i_ASN1_BIT_STRING
-ASN1,function,151,c2i_ASN1_INTEGER
-ASN1,function,152,c2i_ASN1_OBJECT
-ASN1,function,153,collect_data
-ASN1,function,154,d2i_ASN1_BOOLEAN
-ASN1,function,155,d2i_ASN1_OBJECT
-ASN1,function,156,d2i_ASN1_UINTEGER
-ASN1,function,157,d2i_ASN1_UTCTIME
-ASN1,function,158,d2i_ASN1_bytes
-ASN1,function,159,d2i_ASN1_type_bytes
-ASN1,function,160,i2d_ASN1_TIME
-ASN1,function,161,i2d_PrivateKey
-ASN1,function,162,long_c2i
-ASN1,function,163,parse_tagging
-ASN1,reason,100,ASN1_LENGTH_MISMATCH
-ASN1,reason,101,AUX_ERROR
-ASN1,reason,102,BAD_GET_ASN1_OBJECT_CALL
-ASN1,reason,103,BAD_OBJECT_HEADER
-ASN1,reason,104,BMPSTRING_IS_WRONG_LENGTH
-ASN1,reason,105,BN_LIB
-ASN1,reason,106,BOOLEAN_IS_WRONG_LENGTH
-ASN1,reason,107,BUFFER_TOO_SMALL
-ASN1,reason,108,DECODE_ERROR
-ASN1,reason,109,DEPTH_EXCEEDED
-ASN1,reason,110,ENCODE_ERROR
-ASN1,reason,111,ERROR_GETTING_TIME
-ASN1,reason,112,EXPECTING_AN_ASN1_SEQUENCE
-ASN1,reason,113,EXPECTING_AN_INTEGER
-ASN1,reason,114,EXPECTING_AN_OBJECT
-ASN1,reason,115,EXPECTING_A_BOOLEAN
-ASN1,reason,116,EXPECTING_A_TIME
-ASN1,reason,117,EXPLICIT_LENGTH_MISMATCH
-ASN1,reason,118,EXPLICIT_TAG_NOT_CONSTRUCTED
-ASN1,reason,119,FIELD_MISSING
-ASN1,reason,120,FIRST_NUM_TOO_LARGE
-ASN1,reason,121,HEADER_TOO_LONG
-ASN1,reason,122,ILLEGAL_BITSTRING_FORMAT
-ASN1,reason,123,ILLEGAL_BOOLEAN
-ASN1,reason,124,ILLEGAL_CHARACTERS
-ASN1,reason,125,ILLEGAL_FORMAT
-ASN1,reason,126,ILLEGAL_HEX
-ASN1,reason,127,ILLEGAL_IMPLICIT_TAG
-ASN1,reason,128,ILLEGAL_INTEGER
-ASN1,reason,129,ILLEGAL_NESTED_TAGGING
-ASN1,reason,130,ILLEGAL_NULL
-ASN1,reason,131,ILLEGAL_NULL_VALUE
-ASN1,reason,132,ILLEGAL_OBJECT
-ASN1,reason,133,ILLEGAL_OPTIONAL_ANY
-ASN1,reason,134,ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE
-ASN1,reason,135,ILLEGAL_TAGGED_ANY
-ASN1,reason,136,ILLEGAL_TIME_VALUE
-ASN1,reason,137,INTEGER_NOT_ASCII_FORMAT
-ASN1,reason,138,INTEGER_TOO_LARGE_FOR_LONG
-ASN1,reason,139,INVALID_BIT_STRING_BITS_LEFT
-ASN1,reason,140,INVALID_BMPSTRING_LENGTH
-ASN1,reason,141,INVALID_DIGIT
-ASN1,reason,142,INVALID_MODIFIER
-ASN1,reason,143,INVALID_NUMBER
-ASN1,reason,144,INVALID_OBJECT_ENCODING
-ASN1,reason,145,INVALID_SEPARATOR
-ASN1,reason,146,INVALID_TIME_FORMAT
-ASN1,reason,147,INVALID_UNIVERSALSTRING_LENGTH
-ASN1,reason,148,INVALID_UTF8STRING
-ASN1,reason,149,LIST_ERROR
-ASN1,reason,150,MALLOC_FAILURE
-ASN1,reason,151,MISSING_ASN1_EOS
-ASN1,reason,152,MISSING_EOC
-ASN1,reason,153,MISSING_SECOND_NUMBER
-ASN1,reason,154,MISSING_VALUE
-ASN1,reason,155,MSTRING_NOT_UNIVERSAL
-ASN1,reason,156,MSTRING_WRONG_TAG
-ASN1,reason,157,NESTED_ASN1_ERROR
-ASN1,reason,158,NESTED_ASN1_STRING
-ASN1,reason,159,NON_HEX_CHARACTERS
-ASN1,reason,160,NOT_ASCII_FORMAT
-ASN1,reason,161,NOT_ENOUGH_DATA
-ASN1,reason,162,NO_MATCHING_CHOICE_TYPE
-ASN1,reason,163,NULL_IS_WRONG_LENGTH
-ASN1,reason,164,OBJECT_NOT_ASCII_FORMAT
-ASN1,reason,165,ODD_NUMBER_OF_CHARS
-ASN1,reason,166,SECOND_NUMBER_TOO_LARGE
-ASN1,reason,167,SEQUENCE_LENGTH_MISMATCH
-ASN1,reason,168,SEQUENCE_NOT_CONSTRUCTED
-ASN1,reason,169,SEQUENCE_OR_SET_NEEDS_CONFIG
-ASN1,reason,170,SHORT_LINE
-ASN1,reason,171,STREAMING_NOT_SUPPORTED
-ASN1,reason,172,STRING_TOO_LONG
-ASN1,reason,173,STRING_TOO_SHORT
-ASN1,reason,174,TAG_VALUE_TOO_HIGH
-ASN1,reason,175,TIME_NOT_ASCII_FORMAT
-ASN1,reason,176,TOO_LONG
-ASN1,reason,177,TYPE_NOT_CONSTRUCTED
-ASN1,reason,178,TYPE_NOT_PRIMITIVE
-ASN1,reason,179,UNEXPECTED_EOC
-ASN1,reason,180,UNIVERSALSTRING_IS_WRONG_LENGTH
-ASN1,reason,181,UNKNOWN_FORMAT
-ASN1,reason,182,UNKNOWN_TAG
-ASN1,reason,183,UNSUPPORTED_ANY_DEFINED_BY_TYPE
-ASN1,reason,184,UNSUPPORTED_PUBLIC_KEY_TYPE
-ASN1,reason,185,UNSUPPORTED_TYPE
-ASN1,reason,186,WRONG_TAG
-ASN1,reason,187,WRONG_TYPE
+ASN1,100,ASN1_LENGTH_MISMATCH
+ASN1,101,AUX_ERROR
+ASN1,102,BAD_GET_ASN1_OBJECT_CALL
+ASN1,103,BAD_OBJECT_HEADER
+ASN1,104,BMPSTRING_IS_WRONG_LENGTH
+ASN1,105,BN_LIB
+ASN1,106,BOOLEAN_IS_WRONG_LENGTH
+ASN1,107,BUFFER_TOO_SMALL
+ASN1,108,DECODE_ERROR
+ASN1,109,DEPTH_EXCEEDED
+ASN1,110,ENCODE_ERROR
+ASN1,111,ERROR_GETTING_TIME
+ASN1,112,EXPECTING_AN_ASN1_SEQUENCE
+ASN1,113,EXPECTING_AN_INTEGER
+ASN1,114,EXPECTING_AN_OBJECT
+ASN1,115,EXPECTING_A_BOOLEAN
+ASN1,116,EXPECTING_A_TIME
+ASN1,117,EXPLICIT_LENGTH_MISMATCH
+ASN1,118,EXPLICIT_TAG_NOT_CONSTRUCTED
+ASN1,119,FIELD_MISSING
+ASN1,120,FIRST_NUM_TOO_LARGE
+ASN1,121,HEADER_TOO_LONG
+ASN1,122,ILLEGAL_BITSTRING_FORMAT
+ASN1,123,ILLEGAL_BOOLEAN
+ASN1,124,ILLEGAL_CHARACTERS
+ASN1,125,ILLEGAL_FORMAT
+ASN1,126,ILLEGAL_HEX
+ASN1,127,ILLEGAL_IMPLICIT_TAG
+ASN1,128,ILLEGAL_INTEGER
+ASN1,129,ILLEGAL_NESTED_TAGGING
+ASN1,130,ILLEGAL_NULL
+ASN1,131,ILLEGAL_NULL_VALUE
+ASN1,132,ILLEGAL_OBJECT
+ASN1,133,ILLEGAL_OPTIONAL_ANY
+ASN1,134,ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE
+ASN1,135,ILLEGAL_TAGGED_ANY
+ASN1,136,ILLEGAL_TIME_VALUE
+ASN1,137,INTEGER_NOT_ASCII_FORMAT
+ASN1,138,INTEGER_TOO_LARGE_FOR_LONG
+ASN1,139,INVALID_BIT_STRING_BITS_LEFT
+ASN1,140,INVALID_BMPSTRING_LENGTH
+ASN1,141,INVALID_DIGIT
+ASN1,142,INVALID_MODIFIER
+ASN1,143,INVALID_NUMBER
+ASN1,144,INVALID_OBJECT_ENCODING
+ASN1,145,INVALID_SEPARATOR
+ASN1,146,INVALID_TIME_FORMAT
+ASN1,147,INVALID_UNIVERSALSTRING_LENGTH
+ASN1,148,INVALID_UTF8STRING
+ASN1,149,LIST_ERROR
+ASN1,150,MALLOC_FAILURE
+ASN1,151,MISSING_ASN1_EOS
+ASN1,152,MISSING_EOC
+ASN1,153,MISSING_SECOND_NUMBER
+ASN1,154,MISSING_VALUE
+ASN1,155,MSTRING_NOT_UNIVERSAL
+ASN1,156,MSTRING_WRONG_TAG
+ASN1,157,NESTED_ASN1_ERROR
+ASN1,158,NESTED_ASN1_STRING
+ASN1,159,NON_HEX_CHARACTERS
+ASN1,160,NOT_ASCII_FORMAT
+ASN1,161,NOT_ENOUGH_DATA
+ASN1,162,NO_MATCHING_CHOICE_TYPE
+ASN1,163,NULL_IS_WRONG_LENGTH
+ASN1,164,OBJECT_NOT_ASCII_FORMAT
+ASN1,165,ODD_NUMBER_OF_CHARS
+ASN1,166,SECOND_NUMBER_TOO_LARGE
+ASN1,167,SEQUENCE_LENGTH_MISMATCH
+ASN1,168,SEQUENCE_NOT_CONSTRUCTED
+ASN1,169,SEQUENCE_OR_SET_NEEDS_CONFIG
+ASN1,170,SHORT_LINE
+ASN1,171,STREAMING_NOT_SUPPORTED
+ASN1,172,STRING_TOO_LONG
+ASN1,173,STRING_TOO_SHORT
+ASN1,174,TAG_VALUE_TOO_HIGH
+ASN1,175,TIME_NOT_ASCII_FORMAT
+ASN1,176,TOO_LONG
+ASN1,177,TYPE_NOT_CONSTRUCTED
+ASN1,178,TYPE_NOT_PRIMITIVE
+ASN1,179,UNEXPECTED_EOC
+ASN1,180,UNIVERSALSTRING_IS_WRONG_LENGTH
+ASN1,181,UNKNOWN_FORMAT
+ASN1,182,UNKNOWN_TAG
+ASN1,183,UNSUPPORTED_ANY_DEFINED_BY_TYPE
+ASN1,184,UNSUPPORTED_PUBLIC_KEY_TYPE
+ASN1,185,UNSUPPORTED_TYPE
+ASN1,186,WRONG_TAG
+ASN1,187,WRONG_TYPE
diff --git a/src/crypto/err/bio.errordata b/src/crypto/err/bio.errordata
index 9f2af02..94b3c97 100644
--- a/src/crypto/err/bio.errordata
+++ b/src/crypto/err/bio.errordata
@@ -1,36 +1,17 @@
-BIO,function,100,BIO_callback_ctrl
-BIO,function,101,BIO_ctrl
-BIO,function,102,BIO_new
-BIO,function,103,BIO_new_file
-BIO,function,104,BIO_new_mem_buf
-BIO,function,118,BIO_printf
-BIO,function,105,BIO_zero_copy_get_read_buf
-BIO,function,106,BIO_zero_copy_get_read_buf_done
-BIO,function,107,BIO_zero_copy_get_write_buf
-BIO,function,108,BIO_zero_copy_get_write_buf_done
-BIO,function,109,bio_io
-BIO,function,110,bio_make_pair
-BIO,function,111,bio_write
-BIO,function,112,buffer_ctrl
-BIO,function,113,conn_ctrl
-BIO,function,114,conn_state
-BIO,function,115,file_ctrl
-BIO,function,116,file_read
-BIO,function,117,mem_write
-BIO,reason,100,BAD_FOPEN_MODE
-BIO,reason,101,BROKEN_PIPE
-BIO,reason,102,CONNECT_ERROR
-BIO,reason,103,ERROR_SETTING_NBIO
-BIO,reason,104,INVALID_ARGUMENT
-BIO,reason,105,IN_USE
-BIO,reason,106,KEEPALIVE
-BIO,reason,107,NBIO_CONNECT_ERROR
-BIO,reason,108,NO_HOSTNAME_SPECIFIED
-BIO,reason,109,NO_PORT_SPECIFIED
-BIO,reason,110,NO_SUCH_FILE
-BIO,reason,111,NULL_PARAMETER
-BIO,reason,112,SYS_LIB
-BIO,reason,113,UNABLE_TO_CREATE_SOCKET
-BIO,reason,114,UNINITIALIZED
-BIO,reason,115,UNSUPPORTED_METHOD
-BIO,reason,116,WRITE_TO_READ_ONLY_BIO
+BIO,100,BAD_FOPEN_MODE
+BIO,101,BROKEN_PIPE
+BIO,102,CONNECT_ERROR
+BIO,103,ERROR_SETTING_NBIO
+BIO,104,INVALID_ARGUMENT
+BIO,105,IN_USE
+BIO,106,KEEPALIVE
+BIO,107,NBIO_CONNECT_ERROR
+BIO,108,NO_HOSTNAME_SPECIFIED
+BIO,109,NO_PORT_SPECIFIED
+BIO,110,NO_SUCH_FILE
+BIO,111,NULL_PARAMETER
+BIO,112,SYS_LIB
+BIO,113,UNABLE_TO_CREATE_SOCKET
+BIO,114,UNINITIALIZED
+BIO,115,UNSUPPORTED_METHOD
+BIO,116,WRITE_TO_READ_ONLY_BIO
diff --git a/src/crypto/err/bn.errordata b/src/crypto/err/bn.errordata
index 6fd4968..76b6392 100644
--- a/src/crypto/err/bn.errordata
+++ b/src/crypto/err/bn.errordata
@@ -1,44 +1,19 @@
-BN,function,100,BN_CTX_get
-BN,function,101,BN_CTX_new
-BN,function,102,BN_CTX_start
-BN,function,103,BN_bn2dec
-BN,function,104,BN_bn2hex
-BN,function,105,BN_div
-BN,function,106,BN_div_recp
-BN,function,107,BN_exp
-BN,function,108,BN_generate_dsa_nonce
-BN,function,109,BN_generate_prime_ex
-BN,function,125,BN_lshift
-BN,function,110,BN_mod_exp2_mont
-BN,function,111,BN_mod_exp_mont
-BN,function,112,BN_mod_exp_mont_consttime
-BN,function,113,BN_mod_exp_mont_word
-BN,function,114,BN_mod_inverse
-BN,function,115,BN_mod_inverse_no_branch
-BN,function,116,BN_mod_lshift_quick
-BN,function,117,BN_mod_sqrt
-BN,function,118,BN_new
-BN,function,119,BN_rand
-BN,function,120,BN_rand_range
-BN,function,126,BN_rshift
-BN,function,121,BN_sqrt
-BN,function,122,BN_usub
-BN,function,123,bn_wexpand
-BN,function,124,mod_exp_recp
-BN,reason,100,ARG2_LT_ARG3
-BN,reason,101,BAD_RECIPROCAL
-BN,reason,102,BIGNUM_TOO_LONG
-BN,reason,103,BITS_TOO_SMALL
-BN,reason,104,CALLED_WITH_EVEN_MODULUS
-BN,reason,105,DIV_BY_ZERO
-BN,reason,106,EXPAND_ON_STATIC_BIGNUM_DATA
-BN,reason,107,INPUT_NOT_REDUCED
-BN,reason,108,INVALID_RANGE
-BN,reason,109,NEGATIVE_NUMBER
-BN,reason,110,NOT_A_SQUARE
-BN,reason,111,NOT_INITIALIZED
-BN,reason,112,NO_INVERSE
-BN,reason,113,PRIVATE_KEY_TOO_LARGE
-BN,reason,114,P_IS_NOT_PRIME
-BN,reason,115,TOO_MANY_ITERATIONS
-BN,reason,116,TOO_MANY_TEMPORARY_VARIABLES
+BN,100,ARG2_LT_ARG3
+BN,117,BAD_ENCODING
+BN,101,BAD_RECIPROCAL
+BN,102,BIGNUM_TOO_LONG
+BN,103,BITS_TOO_SMALL
+BN,104,CALLED_WITH_EVEN_MODULUS
+BN,105,DIV_BY_ZERO
+BN,118,ENCODE_ERROR
+BN,106,EXPAND_ON_STATIC_BIGNUM_DATA
+BN,107,INPUT_NOT_REDUCED
+BN,108,INVALID_RANGE
+BN,109,NEGATIVE_NUMBER
+BN,110,NOT_A_SQUARE
+BN,111,NOT_INITIALIZED
+BN,112,NO_INVERSE
+BN,113,PRIVATE_KEY_TOO_LARGE
+BN,114,P_IS_NOT_PRIME
+BN,115,TOO_MANY_ITERATIONS
+BN,116,TOO_MANY_TEMPORARY_VARIABLES
diff --git a/src/crypto/err/buf.errordata b/src/crypto/err/buf.errordata
deleted file mode 100644
index 01b6c9a..0000000
--- a/src/crypto/err/buf.errordata
+++ /dev/null
@@ -1,4 +0,0 @@
-BUF,function,100,BUF_MEM_new
-BUF,function,101,BUF_memdup
-BUF,function,102,BUF_strndup
-BUF,function,103,buf_mem_grow
diff --git a/src/crypto/err/cipher.errordata b/src/crypto/err/cipher.errordata
index ce8459b..1037505 100644
--- a/src/crypto/err/cipher.errordata
+++ b/src/crypto/err/cipher.errordata
@@ -1,60 +1,25 @@
-CIPHER,function,100,EVP_AEAD_CTX_init
-CIPHER,function,131,EVP_AEAD_CTX_init_with_direction
-CIPHER,function,101,EVP_AEAD_CTX_open
-CIPHER,function,102,EVP_AEAD_CTX_seal
-CIPHER,function,103,EVP_CIPHER_CTX_copy
-CIPHER,function,104,EVP_CIPHER_CTX_ctrl
-CIPHER,function,105,EVP_CIPHER_CTX_set_key_length
-CIPHER,function,106,EVP_CipherInit_ex
-CIPHER,function,107,EVP_DecryptFinal_ex
-CIPHER,function,108,EVP_EncryptFinal_ex
-CIPHER,function,132,aead_aes_ctr_hmac_sha256_init
-CIPHER,function,133,aead_aes_ctr_hmac_sha256_open
-CIPHER,function,134,aead_aes_ctr_hmac_sha256_seal
-CIPHER,function,109,aead_aes_gcm_init
-CIPHER,function,110,aead_aes_gcm_open
-CIPHER,function,111,aead_aes_gcm_seal
-CIPHER,function,112,aead_aes_key_wrap_init
-CIPHER,function,113,aead_aes_key_wrap_open
-CIPHER,function,114,aead_aes_key_wrap_seal
-CIPHER,function,115,aead_chacha20_poly1305_init
-CIPHER,function,116,aead_chacha20_poly1305_open
-CIPHER,function,117,aead_chacha20_poly1305_seal
-CIPHER,function,118,aead_rc4_md5_tls_init
-CIPHER,function,119,aead_rc4_md5_tls_open
-CIPHER,function,120,aead_rc4_md5_tls_seal
-CIPHER,function,121,aead_ssl3_ensure_cipher_init
-CIPHER,function,122,aead_ssl3_init
-CIPHER,function,123,aead_ssl3_open
-CIPHER,function,124,aead_ssl3_seal
-CIPHER,function,125,aead_tls_ensure_cipher_init
-CIPHER,function,126,aead_tls_init
-CIPHER,function,127,aead_tls_open
-CIPHER,function,128,aead_tls_seal
-CIPHER,function,129,aes_init_key
-CIPHER,function,130,aesni_init_key
-CIPHER,reason,100,AES_KEY_SETUP_FAILED
-CIPHER,reason,101,BAD_DECRYPT
-CIPHER,reason,102,BAD_KEY_LENGTH
-CIPHER,reason,103,BUFFER_TOO_SMALL
-CIPHER,reason,104,CTRL_NOT_IMPLEMENTED
-CIPHER,reason,105,CTRL_OPERATION_NOT_IMPLEMENTED
-CIPHER,reason,106,DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
-CIPHER,reason,107,INITIALIZATION_ERROR
-CIPHER,reason,108,INPUT_NOT_INITIALIZED
-CIPHER,reason,109,INVALID_AD_SIZE
-CIPHER,reason,110,INVALID_KEY_LENGTH
-CIPHER,reason,111,INVALID_NONCE_SIZE
-CIPHER,reason,112,INVALID_OPERATION
-CIPHER,reason,113,IV_TOO_LARGE
-CIPHER,reason,114,NO_CIPHER_SET
-CIPHER,reason,124,NO_DIRECTION_SET
-CIPHER,reason,115,OUTPUT_ALIASES_INPUT
-CIPHER,reason,116,TAG_TOO_LARGE
-CIPHER,reason,117,TOO_LARGE
-CIPHER,reason,118,UNSUPPORTED_AD_SIZE
-CIPHER,reason,119,UNSUPPORTED_INPUT_SIZE
-CIPHER,reason,120,UNSUPPORTED_KEY_SIZE
-CIPHER,reason,121,UNSUPPORTED_NONCE_SIZE
-CIPHER,reason,122,UNSUPPORTED_TAG_SIZE
-CIPHER,reason,123,WRONG_FINAL_BLOCK_LENGTH
+CIPHER,100,AES_KEY_SETUP_FAILED
+CIPHER,101,BAD_DECRYPT
+CIPHER,102,BAD_KEY_LENGTH
+CIPHER,103,BUFFER_TOO_SMALL
+CIPHER,104,CTRL_NOT_IMPLEMENTED
+CIPHER,105,CTRL_OPERATION_NOT_IMPLEMENTED
+CIPHER,106,DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
+CIPHER,107,INITIALIZATION_ERROR
+CIPHER,108,INPUT_NOT_INITIALIZED
+CIPHER,109,INVALID_AD_SIZE
+CIPHER,110,INVALID_KEY_LENGTH
+CIPHER,111,INVALID_NONCE_SIZE
+CIPHER,112,INVALID_OPERATION
+CIPHER,113,IV_TOO_LARGE
+CIPHER,114,NO_CIPHER_SET
+CIPHER,124,NO_DIRECTION_SET
+CIPHER,115,OUTPUT_ALIASES_INPUT
+CIPHER,116,TAG_TOO_LARGE
+CIPHER,117,TOO_LARGE
+CIPHER,118,UNSUPPORTED_AD_SIZE
+CIPHER,119,UNSUPPORTED_INPUT_SIZE
+CIPHER,120,UNSUPPORTED_KEY_SIZE
+CIPHER,121,UNSUPPORTED_NONCE_SIZE
+CIPHER,122,UNSUPPORTED_TAG_SIZE
+CIPHER,123,WRONG_FINAL_BLOCK_LENGTH
diff --git a/src/crypto/err/conf.errordata b/src/crypto/err/conf.errordata
index 0b96a32..651fabe 100644
--- a/src/crypto/err/conf.errordata
+++ b/src/crypto/err/conf.errordata
@@ -1,10 +1,6 @@
-CONF,function,100,CONF_parse_list
-CONF,function,101,NCONF_load
-CONF,function,102,def_load_bio
-CONF,function,103,str_copy
-CONF,reason,100,LIST_CANNOT_BE_NULL
-CONF,reason,101,MISSING_CLOSE_SQUARE_BRACKET
-CONF,reason,102,MISSING_EQUAL_SIGN
-CONF,reason,103,NO_CLOSE_BRACE
-CONF,reason,104,UNABLE_TO_CREATE_NEW_SECTION
-CONF,reason,105,VARIABLE_HAS_NO_VALUE
+CONF,100,LIST_CANNOT_BE_NULL
+CONF,101,MISSING_CLOSE_SQUARE_BRACKET
+CONF,102,MISSING_EQUAL_SIGN
+CONF,103,NO_CLOSE_BRACE
+CONF,104,UNABLE_TO_CREATE_NEW_SECTION
+CONF,105,VARIABLE_HAS_NO_VALUE
diff --git a/src/crypto/err/crypto.errordata b/src/crypto/err/crypto.errordata
deleted file mode 100644
index 1e0e9d5..0000000
--- a/src/crypto/err/crypto.errordata
+++ /dev/null
@@ -1,4 +0,0 @@
-CRYPTO,function,100,CRYPTO_get_ex_new_index
-CRYPTO,function,101,CRYPTO_set_ex_data
-CRYPTO,function,102,get_class
-CRYPTO,function,103,get_func_pointers
diff --git a/src/crypto/err/dh.errordata b/src/crypto/err/dh.errordata
index 1fd675b..571e218 100644
--- a/src/crypto/err/dh.errordata
+++ b/src/crypto/err/dh.errordata
@@ -1,8 +1,4 @@
-DH,function,100,DH_new_method
-DH,function,101,compute_key
-DH,function,102,generate_key
-DH,function,103,generate_parameters
-DH,reason,100,BAD_GENERATOR
-DH,reason,101,INVALID_PUBKEY
-DH,reason,102,MODULUS_TOO_LARGE
-DH,reason,103,NO_PRIVATE_VALUE
+DH,100,BAD_GENERATOR
+DH,101,INVALID_PUBKEY
+DH,102,MODULUS_TOO_LARGE
+DH,103,NO_PRIVATE_VALUE
diff --git a/src/crypto/err/digest.errordata b/src/crypto/err/digest.errordata
index 95a3622..411e778 100644
--- a/src/crypto/err/digest.errordata
+++ b/src/crypto/err/digest.errordata
@@ -1,3 +1 @@
-DIGEST,function,100,EVP_DigestInit_ex
-DIGEST,function,101,EVP_MD_CTX_copy_ex
-DIGEST,reason,100,INPUT_NOT_INITIALIZED
+DIGEST,100,INPUT_NOT_INITIALIZED
diff --git a/src/crypto/err/dsa.errordata b/src/crypto/err/dsa.errordata
index c2dff23..3c5764a 100644
--- a/src/crypto/err/dsa.errordata
+++ b/src/crypto/err/dsa.errordata
@@ -1,9 +1,4 @@
-DSA,function,100,DSA_new_method
-DSA,function,101,dsa_sig_cb
-DSA,function,102,sign
-DSA,function,103,sign_setup
-DSA,function,104,verify
-DSA,reason,100,BAD_Q_VALUE
-DSA,reason,101,MISSING_PARAMETERS
-DSA,reason,102,MODULUS_TOO_LARGE
-DSA,reason,103,NEED_NEW_SETUP_VALUES
+DSA,100,BAD_Q_VALUE
+DSA,101,MISSING_PARAMETERS
+DSA,102,MODULUS_TOO_LARGE
+DSA,103,NEED_NEW_SETUP_VALUES
diff --git a/src/crypto/err/ec.errordata b/src/crypto/err/ec.errordata
index 252f7ab..e7b4175 100644
--- a/src/crypto/err/ec.errordata
+++ b/src/crypto/err/ec.errordata
@@ -1,95 +1,28 @@
-EC,function,159,BN_to_felem
-EC,function,100,EC_GROUP_copy
-EC,function,101,EC_GROUP_get_curve_GFp
-EC,function,102,EC_GROUP_get_degree
-EC,function,103,EC_GROUP_new_by_curve_name
-EC,function,166,EC_GROUP_new_curve_GFp
-EC,function,104,EC_KEY_check_key
-EC,function,105,EC_KEY_copy
-EC,function,106,EC_KEY_generate_key
-EC,function,165,EC_KEY_new_by_curve_name
-EC,function,107,EC_KEY_new_method
-EC,function,108,EC_KEY_set_public_key_affine_coordinates
-EC,function,109,EC_POINT_add
-EC,function,110,EC_POINT_cmp
-EC,function,111,EC_POINT_copy
-EC,function,112,EC_POINT_dbl
-EC,function,113,EC_POINT_dup
-EC,function,114,EC_POINT_get_affine_coordinates_GFp
-EC,function,115,EC_POINT_invert
-EC,function,116,EC_POINT_is_at_infinity
-EC,function,117,EC_POINT_is_on_curve
-EC,function,118,EC_POINT_make_affine
-EC,function,119,EC_POINT_new
-EC,function,120,EC_POINT_oct2point
-EC,function,121,EC_POINT_point2oct
-EC,function,122,EC_POINT_set_affine_coordinates_GFp
-EC,function,123,EC_POINT_set_compressed_coordinates_GFp
-EC,function,124,EC_POINT_set_to_infinity
-EC,function,125,EC_POINTs_make_affine
-EC,function,126,compute_wNAF
-EC,function,127,d2i_ECPKParameters
-EC,function,128,d2i_ECParameters
-EC,function,129,d2i_ECPrivateKey
-EC,function,130,ec_GFp_mont_field_decode
-EC,function,131,ec_GFp_mont_field_encode
-EC,function,132,ec_GFp_mont_field_mul
-EC,function,133,ec_GFp_mont_field_set_to_one
-EC,function,134,ec_GFp_mont_field_sqr
-EC,function,135,ec_GFp_mont_group_set_curve
-EC,function,160,ec_GFp_nistp256_group_set_curve
-EC,function,161,ec_GFp_nistp256_point_get_affine_coordinates
-EC,function,162,ec_GFp_nistp256_points_mul
-EC,function,136,ec_GFp_simple_group_check_discriminant
-EC,function,137,ec_GFp_simple_group_set_curve
-EC,function,138,ec_GFp_simple_make_affine
-EC,function,139,ec_GFp_simple_oct2point
-EC,function,140,ec_GFp_simple_point2oct
-EC,function,141,ec_GFp_simple_point_get_affine_coordinates
-EC,function,142,ec_GFp_simple_point_set_affine_coordinates
-EC,function,143,ec_GFp_simple_points_make_affine
-EC,function,144,ec_GFp_simple_set_compressed_coordinates
-EC,function,145,ec_asn1_group2pkparameters
-EC,function,146,ec_asn1_pkparameters2group
-EC,function,163,ec_group_copy
-EC,function,147,ec_group_new
-EC,function,148,ec_group_new_curve_GFp
-EC,function,149,ec_group_new_from_data
-EC,function,150,ec_point_set_Jprojective_coordinates_GFp
-EC,function,151,ec_pre_comp_new
-EC,function,152,ec_wNAF_mul
-EC,function,153,ec_wNAF_precompute_mult
-EC,function,154,i2d_ECPKParameters
-EC,function,155,i2d_ECParameters
-EC,function,156,i2d_ECPrivateKey
-EC,function,157,i2o_ECPublicKey
-EC,function,164,nistp256_pre_comp_new
-EC,function,158,o2i_ECPublicKey
-EC,reason,126,BIGNUM_OUT_OF_RANGE
-EC,reason,100,BUFFER_TOO_SMALL
-EC,reason,101,COORDINATES_OUT_OF_RANGE
-EC,reason,102,D2I_ECPKPARAMETERS_FAILURE
-EC,reason,103,EC_GROUP_NEW_BY_NAME_FAILURE
-EC,reason,104,GROUP2PKPARAMETERS_FAILURE
-EC,reason,105,I2D_ECPKPARAMETERS_FAILURE
-EC,reason,106,INCOMPATIBLE_OBJECTS
-EC,reason,107,INVALID_COMPRESSED_POINT
-EC,reason,108,INVALID_COMPRESSION_BIT
-EC,reason,109,INVALID_ENCODING
-EC,reason,110,INVALID_FIELD
-EC,reason,111,INVALID_FORM
-EC,reason,112,INVALID_GROUP_ORDER
-EC,reason,113,INVALID_PRIVATE_KEY
-EC,reason,114,MISSING_PARAMETERS
-EC,reason,115,MISSING_PRIVATE_KEY
-EC,reason,116,NON_NAMED_CURVE
-EC,reason,117,NOT_INITIALIZED
-EC,reason,118,PKPARAMETERS2GROUP_FAILURE
-EC,reason,119,POINT_AT_INFINITY
-EC,reason,120,POINT_IS_NOT_ON_CURVE
-EC,reason,121,SLOT_FULL
-EC,reason,122,UNDEFINED_GENERATOR
-EC,reason,123,UNKNOWN_GROUP
-EC,reason,124,UNKNOWN_ORDER
-EC,reason,127,WRONG_CURVE_PARAMETERS
-EC,reason,125,WRONG_ORDER
+EC,126,BIGNUM_OUT_OF_RANGE
+EC,100,BUFFER_TOO_SMALL
+EC,101,COORDINATES_OUT_OF_RANGE
+EC,102,D2I_ECPKPARAMETERS_FAILURE
+EC,103,EC_GROUP_NEW_BY_NAME_FAILURE
+EC,104,GROUP2PKPARAMETERS_FAILURE
+EC,105,I2D_ECPKPARAMETERS_FAILURE
+EC,106,INCOMPATIBLE_OBJECTS
+EC,107,INVALID_COMPRESSED_POINT
+EC,108,INVALID_COMPRESSION_BIT
+EC,109,INVALID_ENCODING
+EC,110,INVALID_FIELD
+EC,111,INVALID_FORM
+EC,112,INVALID_GROUP_ORDER
+EC,113,INVALID_PRIVATE_KEY
+EC,114,MISSING_PARAMETERS
+EC,115,MISSING_PRIVATE_KEY
+EC,116,NON_NAMED_CURVE
+EC,117,NOT_INITIALIZED
+EC,118,PKPARAMETERS2GROUP_FAILURE
+EC,119,POINT_AT_INFINITY
+EC,120,POINT_IS_NOT_ON_CURVE
+EC,121,SLOT_FULL
+EC,122,UNDEFINED_GENERATOR
+EC,123,UNKNOWN_GROUP
+EC,124,UNKNOWN_ORDER
+EC,127,WRONG_CURVE_PARAMETERS
+EC,125,WRONG_ORDER
diff --git a/src/crypto/err/ecdh.errordata b/src/crypto/err/ecdh.errordata
index 0f1215e..f714c30 100644
--- a/src/crypto/err/ecdh.errordata
+++ b/src/crypto/err/ecdh.errordata
@@ -1,4 +1,3 @@
-ECDH,function,100,ECDH_compute_key
-ECDH,reason,100,KDF_FAILED
-ECDH,reason,101,NO_PRIVATE_VALUE
-ECDH,reason,102,POINT_ARITHMETIC_FAILURE
+ECDH,100,KDF_FAILED
+ECDH,101,NO_PRIVATE_VALUE
+ECDH,102,POINT_ARITHMETIC_FAILURE
diff --git a/src/crypto/err/ecdsa.errordata b/src/crypto/err/ecdsa.errordata
index 97c213e..58ba591 100644
--- a/src/crypto/err/ecdsa.errordata
+++ b/src/crypto/err/ecdsa.errordata
@@ -1,10 +1,6 @@
-ECDSA,function,100,ECDSA_do_sign_ex
-ECDSA,function,101,ECDSA_do_verify
-ECDSA,function,102,ECDSA_sign_ex
-ECDSA,function,103,digest_to_bn
-ECDSA,function,104,ecdsa_sign_setup
-ECDSA,reason,100,BAD_SIGNATURE
-ECDSA,reason,101,MISSING_PARAMETERS
-ECDSA,reason,102,NEED_NEW_SETUP_VALUES
-ECDSA,reason,103,NOT_IMPLEMENTED
-ECDSA,reason,104,RANDOM_NUMBER_GENERATION_FAILED
+ECDSA,100,BAD_SIGNATURE
+ECDSA,105,ENCODE_ERROR
+ECDSA,101,MISSING_PARAMETERS
+ECDSA,102,NEED_NEW_SETUP_VALUES
+ECDSA,103,NOT_IMPLEMENTED
+ECDSA,104,RANDOM_NUMBER_GENERATION_FAILED
diff --git a/src/crypto/err/engine.errordata b/src/crypto/err/engine.errordata
index 1185e88..edbd7b9 100644
--- a/src/crypto/err/engine.errordata
+++ b/src/crypto/err/engine.errordata
@@ -1 +1 @@
-ENGINE,reason,100,OPERATION_NOT_SUPPORTED
+ENGINE,100,OPERATION_NOT_SUPPORTED
diff --git a/src/crypto/err/err.c b/src/crypto/err/err.c
index de1b4a7..24824e8 100644
--- a/src/crypto/err/err.c
+++ b/src/crypto/err/err.c
@@ -125,10 +125,6 @@
 #include "../internal.h"
 
 
-extern const uint32_t kOpenSSLFunctionValues[];
-extern const size_t kOpenSSLFunctionValuesLen;
-extern const char kOpenSSLFunctionStringData[];
-
 extern const uint32_t kOpenSSLReasonValues[];
 extern const size_t kOpenSSLReasonValuesLen;
 extern const char kOpenSSLReasonStringData[];
@@ -259,42 +255,51 @@
 }
 
 uint32_t ERR_get_error(void) {
-  return get_error_values(1, 0, NULL, NULL, NULL, NULL);
+  return get_error_values(1 /* inc */, 0 /* bottom */, NULL, NULL, NULL, NULL);
 }
 
 uint32_t ERR_get_error_line(const char **file, int *line) {
-  return get_error_values(1, 0, file, line, NULL, NULL);
+  return get_error_values(1 /* inc */, 0 /* bottom */, file, line, NULL, NULL);
 }
 
 uint32_t ERR_get_error_line_data(const char **file, int *line,
                                  const char **data, int *flags) {
-  return get_error_values(1, 0, file, line, data, flags);
+  return get_error_values(1 /* inc */, 0 /* bottom */, file, line, data, flags);
 }
 
 uint32_t ERR_peek_error(void) {
-  return get_error_values(0, 0, NULL, NULL, NULL, NULL);
+  return get_error_values(0 /* peek */, 0 /* bottom */, NULL, NULL, NULL, NULL);
 }
 
 uint32_t ERR_peek_error_line(const char **file, int *line) {
-  return get_error_values(0, 0, file, line, NULL, NULL);
+  return get_error_values(0 /* peek */, 0 /* bottom */, file, line, NULL, NULL);
 }
 
 uint32_t ERR_peek_error_line_data(const char **file, int *line,
                                   const char **data, int *flags) {
-  return get_error_values(0, 0, file, line, data, flags);
+  return get_error_values(0 /* peek */, 0 /* bottom */, file, line, data,
+                          flags);
+}
+
+const char *ERR_peek_function(void) {
+  ERR_STATE *state = err_get_state();
+  if (state == NULL || state->bottom == state->top) {
+    return NULL;
+  }
+  return state->errors[(state->bottom + 1) % ERR_NUM_ERRORS].function;
 }
 
 uint32_t ERR_peek_last_error(void) {
-  return get_error_values(0, 1, NULL, NULL, NULL, NULL);
+  return get_error_values(0 /* peek */, 1 /* top */, NULL, NULL, NULL, NULL);
 }
 
 uint32_t ERR_peek_last_error_line(const char **file, int *line) {
-  return get_error_values(0, 1, file, line, NULL, NULL);
+  return get_error_values(0 /* peek */, 1 /* top */, file, line, NULL, NULL);
 }
 
 uint32_t ERR_peek_last_error_line_data(const char **file, int *line,
                                        const char **data, int *flags) {
-  return get_error_values(0, 1, file, line, data, flags);
+  return get_error_values(0 /* peek */, 1 /* top */, file, line, data, flags);
 }
 
 void ERR_clear_error(void) {
@@ -341,40 +346,20 @@
   errno = 0;
 }
 
-char *ERR_error_string(uint32_t packed_error, char *ret) {
-  static char buf[ERR_ERROR_STRING_BUF_LEN];
-
-  if (ret == NULL) {
-    /* TODO(fork): remove this. */
-    ret = buf;
-  }
-
-#if !defined(NDEBUG)
-  /* This is aimed to help catch callers who don't provide
-   * |ERR_ERROR_STRING_BUF_LEN| bytes of space. */
-  memset(ret, 0, ERR_ERROR_STRING_BUF_LEN);
-#endif
-
-  ERR_error_string_n(packed_error, ret, ERR_ERROR_STRING_BUF_LEN);
-
-  return ret;
-}
-
-void ERR_error_string_n(uint32_t packed_error, char *buf, size_t len) {
-  char lib_buf[64], func_buf[64], reason_buf[64];
-  const char *lib_str, *func_str, *reason_str;
-  unsigned lib, func, reason;
+static void err_error_string(uint32_t packed_error, const char *func_str,
+                             char *buf, size_t len) {
+  char lib_buf[64], reason_buf[64];
+  const char *lib_str, *reason_str;
+  unsigned lib, reason;
 
   if (len == 0) {
     return;
   }
 
   lib = ERR_GET_LIB(packed_error);
-  func = ERR_GET_FUNC(packed_error);
   reason = ERR_GET_REASON(packed_error);
 
   lib_str = ERR_lib_error_string(packed_error);
-  func_str = ERR_func_error_string(packed_error);
   reason_str = ERR_reason_error_string(packed_error);
 
   if (lib_str == NULL) {
@@ -383,8 +368,7 @@
   }
 
   if (func_str == NULL) {
-    BIO_snprintf(func_buf, sizeof(func_buf), "func(%u)", func);
-    func_str = func_buf;
+    func_str = "OPENSSL_internal";
   }
 
   if (reason_str == NULL) {
@@ -426,6 +410,29 @@
   }
 }
 
+char *ERR_error_string(uint32_t packed_error, char *ret) {
+  static char buf[ERR_ERROR_STRING_BUF_LEN];
+
+  if (ret == NULL) {
+    /* TODO(fork): remove this. */
+    ret = buf;
+  }
+
+#if !defined(NDEBUG)
+  /* This is aimed to help catch callers who don't provide
+   * |ERR_ERROR_STRING_BUF_LEN| bytes of space. */
+  memset(ret, 0, ERR_ERROR_STRING_BUF_LEN);
+#endif
+
+  ERR_error_string_n(packed_error, ret, ERR_ERROR_STRING_BUF_LEN);
+
+  return ret;
+}
+
+void ERR_error_string_n(uint32_t packed_error, char *buf, size_t len) {
+  err_error_string(packed_error, NULL, buf, len);
+}
+
 // err_string_cmp is a compare function for searching error values with
 // |bsearch| in |err_string_lookup|.
 static int err_string_cmp(const void *a, const void *b) {
@@ -505,8 +512,8 @@
     "HMAC routines",                              /* ERR_LIB_HMAC */
     "Digest functions",                           /* ERR_LIB_DIGEST */
     "Cipher functions",                           /* ERR_LIB_CIPHER */
-    "User defined functions",                     /* ERR_LIB_USER */
     "HKDF functions",                             /* ERR_LIB_HKDF */
+    "User defined functions",                     /* ERR_LIB_USER */
 };
 
 const char *ERR_lib_error_string(uint32_t packed_error) {
@@ -519,36 +526,7 @@
 }
 
 const char *ERR_func_error_string(uint32_t packed_error) {
-  const uint32_t lib = ERR_GET_LIB(packed_error);
-  const uint32_t func = ERR_GET_FUNC(packed_error);
-
-  if (lib == ERR_LIB_SYS) {
-    switch (func) {
-      case SYS_F_fopen:
-        return "fopen";
-      case SYS_F_fclose:
-        return "fclose";
-      case SYS_F_fread:
-        return "fread";
-      case SYS_F_fwrite:
-        return "fwrite";
-      case SYS_F_socket:
-        return "socket";
-      case SYS_F_setsockopt:
-        return "setsockopt";
-      case SYS_F_connect:
-        return "connect";
-      case SYS_F_getaddrinfo:
-        return "getaddrinfo";
-      default:
-        return NULL;
-    }
-  }
-
-  return err_string_lookup(ERR_GET_LIB(packed_error),
-                           ERR_GET_FUNC(packed_error), kOpenSSLFunctionValues,
-                           kOpenSSLFunctionValuesLen,
-                           kOpenSSLFunctionStringData);
+  return "OPENSSL_internal";
 }
 
 const char *ERR_reason_error_string(uint32_t packed_error) {
@@ -599,12 +577,13 @@
   const unsigned long thread_hash = (uintptr_t) err_get_state();
 
   for (;;) {
+    const char *function = ERR_peek_function();
     packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
     if (packed_error == 0) {
       break;
     }
 
-    ERR_error_string_n(packed_error, buf, sizeof(buf));
+    err_error_string(packed_error, function, buf, sizeof(buf));
     BIO_snprintf(buf2, sizeof(buf2), "%lu:%s:%s:%d:%s\n", thread_hash, buf,
                  file, line, (flags & ERR_FLAG_STRING) ? data : "");
     if (callback(buf2, strlen(buf2), ctx) <= 0) {
@@ -644,8 +623,8 @@
   error->flags = flags;
 }
 
-void ERR_put_error(int library, int func, int reason, const char *file,
-                   unsigned line) {
+void ERR_put_error(int library, int reason, const char *function,
+                   const char *file, unsigned line) {
   ERR_STATE *const state = err_get_state();
   struct err_error_st *error;
 
@@ -654,7 +633,7 @@
   }
 
   if (library == ERR_LIB_SYS && reason == 0) {
-#if defined(WIN32)
+#if defined(OPENSSL_WINDOWS)
     reason = GetLastError();
 #else
     reason = errno;
@@ -668,9 +647,10 @@
 
   error = &state->errors[state->top];
   err_clear(error);
+  error->function = function;
   error->file = file;
   error->line = line;
-  error->packed = ERR_PACK(library, func, reason);
+  error->packed = ERR_PACK(library, reason);
 }
 
 /* ERR_add_error_data_vdata takes a variable number of const char* pointers,
diff --git a/src/crypto/err/err_data_generate.go b/src/crypto/err/err_data_generate.go
index a5b4cb5..24e0d66 100644
--- a/src/crypto/err/err_data_generate.go
+++ b/src/crypto/err/err_data_generate.go
@@ -59,8 +59,8 @@
 	"HMAC",
 	"DIGEST",
 	"CIPHER",
-	"USER",
 	"HKDF",
+	"USER",
 }
 
 // stringList is a map from uint32 -> string which can output data for a sorted
@@ -69,7 +69,7 @@
 	// entries is an array of keys and offsets into |stringData|. The
 	// offsets are in the bottom 15 bits of each uint32 and the key is the
 	// top 17 bits.
-	entries         []uint32
+	entries []uint32
 	// internedStrings contains the same strings as are in |stringData|,
 	// but allows for easy deduplication. It maps a string to its offset in
 	// |stringData|.
@@ -146,7 +146,7 @@
 		fmt.Fprintf(out, "    0x%x,\n", v)
 	}
 	out.WriteString("};\n\n")
-	out.WriteString("const size_t " + values + "Len = sizeof(" + values + ") / sizeof(" + values + "[0]);\n\n");
+	out.WriteString("const size_t " + values + "Len = sizeof(" + values + ") / sizeof(" + values + "[0]);\n\n")
 
 	stringData := "kOpenSSL" + name + "StringData"
 	out.WriteString("const char " + stringData + "[] =\n    \"")
@@ -161,8 +161,8 @@
 }
 
 type errorData struct {
-	functions, reasons *stringList
-	libraryMap         map[string]uint32
+	reasons    *stringList
+	libraryMap map[string]uint32
 }
 
 func (e *errorData) readErrorDataFile(filename string) error {
@@ -184,8 +184,8 @@
 			continue
 		}
 		parts := bytes.Split(line, comma)
-		if len(parts) != 4 {
-			return fmt.Errorf("bad line %d in %s: found %d values but want 4", lineNo, filename, len(parts))
+		if len(parts) != 3 {
+			return fmt.Errorf("bad line %d in %s: found %d values but want 3", lineNo, filename, len(parts))
 		}
 		libNum, ok := e.libraryMap[string(parts[0])]
 		if !ok {
@@ -194,26 +194,18 @@
 		if libNum >= 64 {
 			return fmt.Errorf("bad line %d in %s: library value too large", lineNo, filename)
 		}
-		key, err := strconv.ParseUint(string(parts[2]), 10 /* base */, 32 /* bit size */)
+		key, err := strconv.ParseUint(string(parts[1]), 10 /* base */, 32 /* bit size */)
 		if err != nil {
 			return fmt.Errorf("bad line %d in %s: %s", lineNo, filename, err)
 		}
 		if key >= 2048 {
 			return fmt.Errorf("bad line %d in %s: key too large", lineNo, filename)
 		}
-		value := string(parts[3])
+		value := string(parts[2])
 
 		listKey := libNum<<26 | uint32(key)<<15
 
-		switch string(parts[1]) {
-		case "function":
-			err = e.functions.Add(listKey, value)
-		case "reason":
-			err = e.reasons.Add(listKey, value)
-		default:
-			return fmt.Errorf("bad line %d in %s: bad value type", lineNo, filename)
-		}
-
+		err = e.reasons.Add(listKey, value)
 		if err != nil {
 			return err
 		}
@@ -224,7 +216,6 @@
 
 func main() {
 	e := &errorData{
-		functions:  newStringList(),
 		reasons:    newStringList(),
 		libraryMap: make(map[string]uint32),
 	}
@@ -279,9 +270,8 @@
 	for i, name := range libraryNames {
 		fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_LIB_%s == %d, library_values_changed_%d);\n", name, i+1, i+1)
 	}
-	fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == %d, library_values_changed_num);\n", len(libraryNames) + 1)
+	fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == %d, library_values_changed_num);\n", len(libraryNames)+1)
 	out.WriteString("\n")
 
-	e.functions.WriteTo(out, "Function")
 	e.reasons.WriteTo(out, "Reason")
 }
diff --git a/src/crypto/err/err_test.cc b/src/crypto/err/err_test.cc
index 98dfb85..6643c68 100644
--- a/src/crypto/err/err_test.cc
+++ b/src/crypto/err/err_test.cc
@@ -22,7 +22,7 @@
 
 static bool TestOverflow() {
   for (unsigned i = 0; i < ERR_NUM_ERRORS*2; i++) {
-    ERR_put_error(1, 2, i+1, "test", 1);
+    ERR_put_error(1, i+1, "function", "test", 1);
   }
 
   for (unsigned i = 0; i < ERR_NUM_ERRORS - 1; i++) {
@@ -50,7 +50,7 @@
     return false;
   }
 
-  ERR_put_error(1, 2, 3, "test", 4);
+  ERR_put_error(1, 2, "function", "test", 4);
   ERR_add_error_data(1, "testing");
 
   int peeked_line, line, peeked_flags, flags;
@@ -58,6 +58,7 @@
   uint32_t peeked_packed_error =
       ERR_peek_error_line_data(&peeked_file, &peeked_line, &peeked_data,
                                &peeked_flags);
+  const char *function = ERR_peek_function();
   uint32_t packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
 
   if (peeked_packed_error != packed_error ||
@@ -68,12 +69,12 @@
     return false;
   }
 
-  if (strcmp(file, "test") != 0 ||
+  if (strcmp(function, "function") != 0 ||
+      strcmp(file, "test") != 0 ||
       line != 4 ||
       (flags & ERR_FLAG_STRING) == 0 ||
       ERR_GET_LIB(packed_error) != 1 ||
-      ERR_GET_FUNC(packed_error) != 2 ||
-      ERR_GET_REASON(packed_error) != 3 ||
+      ERR_GET_REASON(packed_error) != 2 ||
       strcmp(data, "testing") != 0) {
     fprintf(stderr, "Bad error data returned.\n");
     return false;
@@ -88,7 +89,7 @@
     return false;
   }
 
-  ERR_put_error(1, 2, 3, "test", 4);
+  ERR_put_error(1, 2, "function", "test", 4);
   ERR_clear_error();
 
   if (ERR_get_error() != 0) {
@@ -100,7 +101,7 @@
 }
 
 static bool TestPrint() {
-  ERR_put_error(1, 2, 3, "test", 4);
+  ERR_put_error(1, 2, "function", "test", 4);
   ERR_add_error_data(1, "testing");
   uint32_t packed_error = ERR_get_error();
 
@@ -113,11 +114,41 @@
 }
 
 static bool TestRelease() {
-  ERR_put_error(1, 2, 3, "test", 4);
+  ERR_put_error(1, 2, "function", "test", 4);
   ERR_remove_thread_state(NULL);
   return true;
 }
 
+static bool HasSuffix(const char *str, const char *suffix) {
+  size_t suffix_len = strlen(suffix);
+  size_t str_len = strlen(str);
+  if (str_len < suffix_len) {
+    return false;
+  }
+  return strcmp(str + str_len - suffix_len, suffix) == 0;
+}
+
+static bool TestPutMacro() {
+  int expected_line = __LINE__ + 1;
+  OPENSSL_PUT_ERROR(USER, ERR_R_INTERNAL_ERROR);
+
+  int line;
+  const char *file;
+  const char *function = ERR_peek_function();
+  uint32_t error = ERR_get_error_line(&file, &line);
+
+  if (strcmp(function, "TestPutMacro") != 0 ||
+      !HasSuffix(file, "err_test.cc") ||
+      line != expected_line ||
+      ERR_GET_LIB(error) != ERR_LIB_USER ||
+      ERR_GET_REASON(error) != ERR_R_INTERNAL_ERROR) {
+    fprintf(stderr, "Bad error data returned.\n");
+    return false;
+  }
+
+  return true;
+}
+
 int main() {
   CRYPTO_library_init();
 
@@ -125,7 +156,8 @@
       !TestPutError() ||
       !TestClearError() ||
       !TestPrint() ||
-      !TestRelease()) {
+      !TestRelease() ||
+      !TestPutMacro()) {
     return 1;
   }
 
diff --git a/src/crypto/err/evp.errordata b/src/crypto/err/evp.errordata
index 14dd27b..8f8dd48 100644
--- a/src/crypto/err/evp.errordata
+++ b/src/crypto/err/evp.errordata
@@ -1,114 +1,46 @@
-EVP,function,160,EVP_DigestSignAlgorithm
-EVP,function,161,EVP_DigestVerifyInitFromAlgorithm
-EVP,function,162,EVP_PKEY_CTX_ctrl
-EVP,function,163,EVP_PKEY_CTX_dup
-EVP,function,159,EVP_PKEY_CTX_get0_rsa_oaep_label
-EVP,function,164,EVP_PKEY_copy_parameters
-EVP,function,165,EVP_PKEY_decrypt
-EVP,function,166,EVP_PKEY_decrypt_init
-EVP,function,167,EVP_PKEY_derive
-EVP,function,108,EVP_PKEY_derive_init
-EVP,function,168,EVP_PKEY_derive_set_peer
-EVP,function,110,EVP_PKEY_encrypt
-EVP,function,111,EVP_PKEY_encrypt_init
-EVP,function,112,EVP_PKEY_get1_DH
-EVP,function,169,EVP_PKEY_get1_DSA
-EVP,function,114,EVP_PKEY_get1_EC_KEY
-EVP,function,115,EVP_PKEY_get1_RSA
-EVP,function,116,EVP_PKEY_keygen
-EVP,function,170,EVP_PKEY_keygen_init
-EVP,function,171,EVP_PKEY_new
-EVP,function,172,EVP_PKEY_set_type
-EVP,function,120,EVP_PKEY_sign
-EVP,function,121,EVP_PKEY_sign_init
-EVP,function,122,EVP_PKEY_verify
-EVP,function,123,EVP_PKEY_verify_init
-EVP,function,173,check_padding_md
-EVP,function,125,d2i_AutoPrivateKey
-EVP,function,126,d2i_PrivateKey
-EVP,function,127,do_EC_KEY_print
-EVP,function,174,do_dsa_print
-EVP,function,175,do_rsa_print
-EVP,function,129,do_sigver_init
-EVP,function,176,dsa_param_decode
-EVP,function,177,dsa_priv_decode
-EVP,function,178,dsa_priv_encode
-EVP,function,179,dsa_pub_decode
-EVP,function,180,dsa_pub_encode
-EVP,function,181,dsa_sig_print
-EVP,function,130,eckey_param2type
-EVP,function,131,eckey_param_decode
-EVP,function,132,eckey_priv_decode
-EVP,function,133,eckey_priv_encode
-EVP,function,134,eckey_pub_decode
-EVP,function,135,eckey_pub_encode
-EVP,function,136,eckey_type2param
-EVP,function,137,evp_pkey_ctx_new
-EVP,function,138,hmac_signctx
-EVP,function,139,i2d_PublicKey
-EVP,function,182,old_dsa_priv_decode
-EVP,function,140,old_ec_priv_decode
-EVP,function,141,old_rsa_priv_decode
-EVP,function,142,pkey_ec_ctrl
-EVP,function,143,pkey_ec_derive
-EVP,function,144,pkey_ec_keygen
-EVP,function,145,pkey_ec_paramgen
-EVP,function,146,pkey_ec_sign
-EVP,function,158,pkey_hmac_ctrl
-EVP,function,147,pkey_rsa_ctrl
-EVP,function,148,pkey_rsa_decrypt
-EVP,function,149,pkey_rsa_encrypt
-EVP,function,150,pkey_rsa_sign
-EVP,function,151,rsa_algor_to_md
-EVP,function,152,rsa_digest_verify_init_from_algorithm
-EVP,function,153,rsa_mgf1_to_md
-EVP,function,154,rsa_priv_decode
-EVP,function,155,rsa_priv_encode
-EVP,function,156,rsa_pss_to_ctx
-EVP,function,157,rsa_pub_decode
-EVP,reason,151,BN_DECODE_ERROR
-EVP,reason,100,BUFFER_TOO_SMALL
-EVP,reason,101,COMMAND_NOT_SUPPORTED
-EVP,reason,146,CONTEXT_NOT_INITIALISED
-EVP,reason,143,DECODE_ERROR
-EVP,reason,104,DIFFERENT_KEY_TYPES
-EVP,reason,105,DIFFERENT_PARAMETERS
-EVP,reason,147,DIGEST_AND_KEY_TYPE_NOT_SUPPORTED
-EVP,reason,107,EXPECTING_AN_EC_KEY_KEY
-EVP,reason,141,EXPECTING_AN_RSA_KEY
-EVP,reason,109,EXPECTING_A_DH_KEY
-EVP,reason,110,EXPECTING_A_DSA_KEY
-EVP,reason,111,ILLEGAL_OR_UNSUPPORTED_PADDING_MODE
-EVP,reason,112,INVALID_CURVE
-EVP,reason,113,INVALID_DIGEST_LENGTH
-EVP,reason,114,INVALID_DIGEST_TYPE
-EVP,reason,115,INVALID_KEYBITS
-EVP,reason,116,INVALID_MGF1_MD
-EVP,reason,142,INVALID_OPERATION
-EVP,reason,118,INVALID_PADDING_MODE
-EVP,reason,119,INVALID_PSS_PARAMETERS
-EVP,reason,144,INVALID_PSS_SALTLEN
-EVP,reason,121,INVALID_SALT_LENGTH
-EVP,reason,122,INVALID_TRAILER
-EVP,reason,123,KEYS_NOT_SET
-EVP,reason,124,MISSING_PARAMETERS
-EVP,reason,125,NO_DEFAULT_DIGEST
-EVP,reason,126,NO_KEY_SET
-EVP,reason,127,NO_MDC2_SUPPORT
-EVP,reason,128,NO_NID_FOR_CURVE
-EVP,reason,129,NO_OPERATION_SET
-EVP,reason,130,NO_PARAMETERS_SET
-EVP,reason,131,OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE
-EVP,reason,132,OPERATON_NOT_INITIALIZED
-EVP,reason,152,PARAMETER_ENCODING_ERROR
-EVP,reason,133,UNKNOWN_DIGEST
-EVP,reason,134,UNKNOWN_MASK_DIGEST
-EVP,reason,150,UNKNOWN_MESSAGE_DIGEST_ALGORITHM
-EVP,reason,145,UNKNOWN_PUBLIC_KEY_TYPE
-EVP,reason,149,UNKNOWN_SIGNATURE_ALGORITHM
-EVP,reason,138,UNSUPPORTED_ALGORITHM
-EVP,reason,139,UNSUPPORTED_MASK_ALGORITHM
-EVP,reason,140,UNSUPPORTED_MASK_PARAMETER
-EVP,reason,153,UNSUPPORTED_PUBLIC_KEY_TYPE
-EVP,reason,154,UNSUPPORTED_SIGNATURE_TYPE
-EVP,reason,148,WRONG_PUBLIC_KEY_TYPE
+EVP,151,BN_DECODE_ERROR
+EVP,100,BUFFER_TOO_SMALL
+EVP,101,COMMAND_NOT_SUPPORTED
+EVP,146,CONTEXT_NOT_INITIALISED
+EVP,143,DECODE_ERROR
+EVP,104,DIFFERENT_KEY_TYPES
+EVP,105,DIFFERENT_PARAMETERS
+EVP,147,DIGEST_AND_KEY_TYPE_NOT_SUPPORTED
+EVP,107,EXPECTING_AN_EC_KEY_KEY
+EVP,141,EXPECTING_AN_RSA_KEY
+EVP,109,EXPECTING_A_DH_KEY
+EVP,110,EXPECTING_A_DSA_KEY
+EVP,111,ILLEGAL_OR_UNSUPPORTED_PADDING_MODE
+EVP,112,INVALID_CURVE
+EVP,113,INVALID_DIGEST_LENGTH
+EVP,114,INVALID_DIGEST_TYPE
+EVP,115,INVALID_KEYBITS
+EVP,116,INVALID_MGF1_MD
+EVP,142,INVALID_OPERATION
+EVP,118,INVALID_PADDING_MODE
+EVP,119,INVALID_PSS_PARAMETERS
+EVP,144,INVALID_PSS_SALTLEN
+EVP,121,INVALID_SALT_LENGTH
+EVP,122,INVALID_TRAILER
+EVP,123,KEYS_NOT_SET
+EVP,124,MISSING_PARAMETERS
+EVP,125,NO_DEFAULT_DIGEST
+EVP,126,NO_KEY_SET
+EVP,127,NO_MDC2_SUPPORT
+EVP,128,NO_NID_FOR_CURVE
+EVP,129,NO_OPERATION_SET
+EVP,130,NO_PARAMETERS_SET
+EVP,131,OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE
+EVP,132,OPERATON_NOT_INITIALIZED
+EVP,152,PARAMETER_ENCODING_ERROR
+EVP,133,UNKNOWN_DIGEST
+EVP,134,UNKNOWN_MASK_DIGEST
+EVP,150,UNKNOWN_MESSAGE_DIGEST_ALGORITHM
+EVP,145,UNKNOWN_PUBLIC_KEY_TYPE
+EVP,149,UNKNOWN_SIGNATURE_ALGORITHM
+EVP,138,UNSUPPORTED_ALGORITHM
+EVP,139,UNSUPPORTED_MASK_ALGORITHM
+EVP,140,UNSUPPORTED_MASK_PARAMETER
+EVP,153,UNSUPPORTED_PUBLIC_KEY_TYPE
+EVP,154,UNSUPPORTED_SIGNATURE_TYPE
+EVP,148,WRONG_PUBLIC_KEY_TYPE
diff --git a/src/crypto/err/hkdf.errordata b/src/crypto/err/hkdf.errordata
index 878a802..84866de 100644
--- a/src/crypto/err/hkdf.errordata
+++ b/src/crypto/err/hkdf.errordata
@@ -1,2 +1 @@
-HKDF,function,100,HKDF
-HKDF,reason,100,OUTPUT_TOO_LARGE
+HKDF,100,OUTPUT_TOO_LARGE
diff --git a/src/crypto/err/obj.errordata b/src/crypto/err/obj.errordata
index 74e4629..c54435e 100644
--- a/src/crypto/err/obj.errordata
+++ b/src/crypto/err/obj.errordata
@@ -1,5 +1 @@
-OBJ,function,100,OBJ_create
-OBJ,function,101,OBJ_dup
-OBJ,function,102,OBJ_nid2obj
-OBJ,function,103,OBJ_txt2obj
-OBJ,reason,100,UNKNOWN_NID
+OBJ,100,UNKNOWN_NID
diff --git a/src/crypto/err/pem.errordata b/src/crypto/err/pem.errordata
index 42216a7..2a4b73a 100644
--- a/src/crypto/err/pem.errordata
+++ b/src/crypto/err/pem.errordata
@@ -1,39 +1,15 @@
-PEM,function,100,PEM_ASN1_read
-PEM,function,101,PEM_ASN1_read_bio
-PEM,function,102,PEM_ASN1_write
-PEM,function,103,PEM_ASN1_write_bio
-PEM,function,104,PEM_X509_INFO_read
-PEM,function,105,PEM_X509_INFO_read_bio
-PEM,function,106,PEM_X509_INFO_write_bio
-PEM,function,107,PEM_do_header
-PEM,function,108,PEM_get_EVP_CIPHER_INFO
-PEM,function,109,PEM_read
-PEM,function,110,PEM_read_DHparams
-PEM,function,111,PEM_read_PrivateKey
-PEM,function,112,PEM_read_bio
-PEM,function,113,PEM_read_bio_DHparams
-PEM,function,114,PEM_read_bio_Parameters
-PEM,function,115,PEM_read_bio_PrivateKey
-PEM,function,116,PEM_write
-PEM,function,117,PEM_write_PrivateKey
-PEM,function,118,PEM_write_bio
-PEM,function,119,d2i_PKCS8PrivateKey_bio
-PEM,function,120,d2i_PKCS8PrivateKey_fp
-PEM,function,121,do_pk8pkey
-PEM,function,122,do_pk8pkey_fp
-PEM,function,123,load_iv
-PEM,reason,100,BAD_BASE64_DECODE
-PEM,reason,101,BAD_DECRYPT
-PEM,reason,102,BAD_END_LINE
-PEM,reason,103,BAD_IV_CHARS
-PEM,reason,104,BAD_PASSWORD_READ
-PEM,reason,105,CIPHER_IS_NULL
-PEM,reason,106,ERROR_CONVERTING_PRIVATE_KEY
-PEM,reason,107,NOT_DEK_INFO
-PEM,reason,108,NOT_ENCRYPTED
-PEM,reason,109,NOT_PROC_TYPE
-PEM,reason,110,NO_START_LINE
-PEM,reason,111,READ_KEY
-PEM,reason,112,SHORT_HEADER
-PEM,reason,113,UNSUPPORTED_CIPHER
-PEM,reason,114,UNSUPPORTED_ENCRYPTION
+PEM,100,BAD_BASE64_DECODE
+PEM,101,BAD_DECRYPT
+PEM,102,BAD_END_LINE
+PEM,103,BAD_IV_CHARS
+PEM,104,BAD_PASSWORD_READ
+PEM,105,CIPHER_IS_NULL
+PEM,106,ERROR_CONVERTING_PRIVATE_KEY
+PEM,107,NOT_DEK_INFO
+PEM,108,NOT_ENCRYPTED
+PEM,109,NOT_PROC_TYPE
+PEM,110,NO_START_LINE
+PEM,111,READ_KEY
+PEM,112,SHORT_HEADER
+PEM,113,UNSUPPORTED_CIPHER
+PEM,114,UNSUPPORTED_ENCRYPTION
diff --git a/src/crypto/err/pkcs8.errordata b/src/crypto/err/pkcs8.errordata
index 936f3c5..0eb5083 100644
--- a/src/crypto/err/pkcs8.errordata
+++ b/src/crypto/err/pkcs8.errordata
@@ -1,43 +1,25 @@
-PKCS8,function,100,EVP_PKCS82PKEY
-PKCS8,function,101,EVP_PKEY2PKCS8
-PKCS8,function,102,PKCS12_get_key_and_certs
-PKCS8,function,103,PKCS12_handle_content_info
-PKCS8,function,104,PKCS12_handle_content_infos
-PKCS8,function,105,PKCS5_pbe2_set_iv
-PKCS8,function,106,PKCS5_pbe_set
-PKCS8,function,107,PKCS5_pbe_set0_algor
-PKCS8,function,108,PKCS5_pbkdf2_set
-PKCS8,function,109,PKCS8_decrypt
-PKCS8,function,110,PKCS8_encrypt
-PKCS8,function,111,PKCS8_encrypt_pbe
-PKCS8,function,112,pbe_cipher_init
-PKCS8,function,113,pbe_crypt
-PKCS8,function,114,pkcs12_item_decrypt_d2i
-PKCS8,function,115,pkcs12_item_i2d_encrypt
-PKCS8,function,116,pkcs12_key_gen_raw
-PKCS8,function,117,pkcs12_pbe_keyivgen
-PKCS8,reason,100,BAD_PKCS12_DATA
-PKCS8,reason,101,BAD_PKCS12_VERSION
-PKCS8,reason,102,CIPHER_HAS_NO_OBJECT_IDENTIFIER
-PKCS8,reason,103,CRYPT_ERROR
-PKCS8,reason,104,DECODE_ERROR
-PKCS8,reason,105,ENCODE_ERROR
-PKCS8,reason,106,ENCRYPT_ERROR
-PKCS8,reason,107,ERROR_SETTING_CIPHER_PARAMS
-PKCS8,reason,108,INCORRECT_PASSWORD
-PKCS8,reason,109,KEYGEN_FAILURE
-PKCS8,reason,110,KEY_GEN_ERROR
-PKCS8,reason,111,METHOD_NOT_SUPPORTED
-PKCS8,reason,112,MISSING_MAC
-PKCS8,reason,113,MULTIPLE_PRIVATE_KEYS_IN_PKCS12
-PKCS8,reason,114,PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED
-PKCS8,reason,115,PKCS12_TOO_DEEPLY_NESTED
-PKCS8,reason,116,PRIVATE_KEY_DECODE_ERROR
-PKCS8,reason,117,PRIVATE_KEY_ENCODE_ERROR
-PKCS8,reason,118,TOO_LONG
-PKCS8,reason,119,UNKNOWN_ALGORITHM
-PKCS8,reason,120,UNKNOWN_CIPHER
-PKCS8,reason,121,UNKNOWN_CIPHER_ALGORITHM
-PKCS8,reason,122,UNKNOWN_DIGEST
-PKCS8,reason,123,UNKNOWN_HASH
-PKCS8,reason,124,UNSUPPORTED_PRIVATE_KEY_ALGORITHM
+PKCS8,100,BAD_PKCS12_DATA
+PKCS8,101,BAD_PKCS12_VERSION
+PKCS8,102,CIPHER_HAS_NO_OBJECT_IDENTIFIER
+PKCS8,103,CRYPT_ERROR
+PKCS8,104,DECODE_ERROR
+PKCS8,105,ENCODE_ERROR
+PKCS8,106,ENCRYPT_ERROR
+PKCS8,107,ERROR_SETTING_CIPHER_PARAMS
+PKCS8,108,INCORRECT_PASSWORD
+PKCS8,109,KEYGEN_FAILURE
+PKCS8,110,KEY_GEN_ERROR
+PKCS8,111,METHOD_NOT_SUPPORTED
+PKCS8,112,MISSING_MAC
+PKCS8,113,MULTIPLE_PRIVATE_KEYS_IN_PKCS12
+PKCS8,114,PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED
+PKCS8,115,PKCS12_TOO_DEEPLY_NESTED
+PKCS8,116,PRIVATE_KEY_DECODE_ERROR
+PKCS8,117,PRIVATE_KEY_ENCODE_ERROR
+PKCS8,118,TOO_LONG
+PKCS8,119,UNKNOWN_ALGORITHM
+PKCS8,120,UNKNOWN_CIPHER
+PKCS8,121,UNKNOWN_CIPHER_ALGORITHM
+PKCS8,122,UNKNOWN_DIGEST
+PKCS8,123,UNKNOWN_HASH
+PKCS8,124,UNSUPPORTED_PRIVATE_KEY_ALGORITHM
diff --git a/src/crypto/err/rsa.errordata b/src/crypto/err/rsa.errordata
index 64b390d..c19f73c 100644
--- a/src/crypto/err/rsa.errordata
+++ b/src/crypto/err/rsa.errordata
@@ -1,69 +1,46 @@
-RSA,function,100,BN_BLINDING_convert_ex
-RSA,function,101,BN_BLINDING_create_param
-RSA,function,102,BN_BLINDING_invert_ex
-RSA,function,103,BN_BLINDING_new
-RSA,function,104,BN_BLINDING_update
-RSA,function,105,RSA_check_key
-RSA,function,106,RSA_new_method
-RSA,function,107,RSA_padding_add_PKCS1_OAEP_mgf1
-RSA,function,108,RSA_padding_add_PKCS1_PSS_mgf1
-RSA,function,109,RSA_padding_add_PKCS1_type_1
-RSA,function,110,RSA_padding_add_PKCS1_type_2
-RSA,function,111,RSA_padding_add_none
-RSA,function,112,RSA_padding_check_PKCS1_OAEP_mgf1
-RSA,function,113,RSA_padding_check_PKCS1_type_1
-RSA,function,114,RSA_padding_check_PKCS1_type_2
-RSA,function,115,RSA_padding_check_none
-RSA,function,116,RSA_recover_crt_params
-RSA,function,117,RSA_sign
-RSA,function,118,RSA_verify
-RSA,function,119,RSA_verify_PKCS1_PSS_mgf1
-RSA,function,120,decrypt
-RSA,function,121,encrypt
-RSA,function,122,keygen
-RSA,function,123,pkcs1_prefixed_msg
-RSA,function,124,private_transform
-RSA,function,125,rsa_setup_blinding
-RSA,function,126,sign_raw
-RSA,function,127,verify_raw
-RSA,reason,100,BAD_E_VALUE
-RSA,reason,101,BAD_FIXED_HEADER_DECRYPT
-RSA,reason,102,BAD_PAD_BYTE_COUNT
-RSA,reason,103,BAD_RSA_PARAMETERS
-RSA,reason,104,BAD_SIGNATURE
-RSA,reason,105,BLOCK_TYPE_IS_NOT_01
-RSA,reason,106,BN_NOT_INITIALIZED
-RSA,reason,107,CRT_PARAMS_ALREADY_GIVEN
-RSA,reason,108,CRT_VALUES_INCORRECT
-RSA,reason,109,DATA_LEN_NOT_EQUAL_TO_MOD_LEN
-RSA,reason,110,DATA_TOO_LARGE
-RSA,reason,111,DATA_TOO_LARGE_FOR_KEY_SIZE
-RSA,reason,112,DATA_TOO_LARGE_FOR_MODULUS
-RSA,reason,113,DATA_TOO_SMALL
-RSA,reason,114,DATA_TOO_SMALL_FOR_KEY_SIZE
-RSA,reason,115,DIGEST_TOO_BIG_FOR_RSA_KEY
-RSA,reason,116,D_E_NOT_CONGRUENT_TO_1
-RSA,reason,117,EMPTY_PUBLIC_KEY
-RSA,reason,118,FIRST_OCTET_INVALID
-RSA,reason,119,INCONSISTENT_SET_OF_CRT_VALUES
-RSA,reason,120,INTERNAL_ERROR
-RSA,reason,121,INVALID_MESSAGE_LENGTH
-RSA,reason,122,KEY_SIZE_TOO_SMALL
-RSA,reason,123,LAST_OCTET_INVALID
-RSA,reason,124,MODULUS_TOO_LARGE
-RSA,reason,125,NO_PUBLIC_EXPONENT
-RSA,reason,126,NULL_BEFORE_BLOCK_MISSING
-RSA,reason,127,N_NOT_EQUAL_P_Q
-RSA,reason,128,OAEP_DECODING_ERROR
-RSA,reason,129,ONLY_ONE_OF_P_Q_GIVEN
-RSA,reason,130,OUTPUT_BUFFER_TOO_SMALL
-RSA,reason,131,PADDING_CHECK_FAILED
-RSA,reason,132,PKCS_DECODING_ERROR
-RSA,reason,133,SLEN_CHECK_FAILED
-RSA,reason,134,SLEN_RECOVERY_FAILED
-RSA,reason,135,TOO_LONG
-RSA,reason,136,TOO_MANY_ITERATIONS
-RSA,reason,137,UNKNOWN_ALGORITHM_TYPE
-RSA,reason,138,UNKNOWN_PADDING_TYPE
-RSA,reason,139,VALUE_MISSING
-RSA,reason,140,WRONG_SIGNATURE_LENGTH
+RSA,143,BAD_ENCODING
+RSA,100,BAD_E_VALUE
+RSA,101,BAD_FIXED_HEADER_DECRYPT
+RSA,102,BAD_PAD_BYTE_COUNT
+RSA,103,BAD_RSA_PARAMETERS
+RSA,104,BAD_SIGNATURE
+RSA,145,BAD_VERSION
+RSA,105,BLOCK_TYPE_IS_NOT_01
+RSA,106,BN_NOT_INITIALIZED
+RSA,142,CANNOT_RECOVER_MULTI_PRIME_KEY
+RSA,107,CRT_PARAMS_ALREADY_GIVEN
+RSA,108,CRT_VALUES_INCORRECT
+RSA,109,DATA_LEN_NOT_EQUAL_TO_MOD_LEN
+RSA,110,DATA_TOO_LARGE
+RSA,111,DATA_TOO_LARGE_FOR_KEY_SIZE
+RSA,112,DATA_TOO_LARGE_FOR_MODULUS
+RSA,113,DATA_TOO_SMALL
+RSA,114,DATA_TOO_SMALL_FOR_KEY_SIZE
+RSA,115,DIGEST_TOO_BIG_FOR_RSA_KEY
+RSA,116,D_E_NOT_CONGRUENT_TO_1
+RSA,117,EMPTY_PUBLIC_KEY
+RSA,144,ENCODE_ERROR
+RSA,118,FIRST_OCTET_INVALID
+RSA,119,INCONSISTENT_SET_OF_CRT_VALUES
+RSA,120,INTERNAL_ERROR
+RSA,121,INVALID_MESSAGE_LENGTH
+RSA,122,KEY_SIZE_TOO_SMALL
+RSA,123,LAST_OCTET_INVALID
+RSA,124,MODULUS_TOO_LARGE
+RSA,141,MUST_HAVE_AT_LEAST_TWO_PRIMES
+RSA,125,NO_PUBLIC_EXPONENT
+RSA,126,NULL_BEFORE_BLOCK_MISSING
+RSA,127,N_NOT_EQUAL_P_Q
+RSA,128,OAEP_DECODING_ERROR
+RSA,129,ONLY_ONE_OF_P_Q_GIVEN
+RSA,130,OUTPUT_BUFFER_TOO_SMALL
+RSA,131,PADDING_CHECK_FAILED
+RSA,132,PKCS_DECODING_ERROR
+RSA,133,SLEN_CHECK_FAILED
+RSA,134,SLEN_RECOVERY_FAILED
+RSA,135,TOO_LONG
+RSA,136,TOO_MANY_ITERATIONS
+RSA,137,UNKNOWN_ALGORITHM_TYPE
+RSA,138,UNKNOWN_PADDING_TYPE
+RSA,139,VALUE_MISSING
+RSA,140,WRONG_SIGNATURE_LENGTH
diff --git a/src/crypto/err/ssl.errordata b/src/crypto/err/ssl.errordata
index 9464c3d..0b30b13 100644
--- a/src/crypto/err/ssl.errordata
+++ b/src/crypto/err/ssl.errordata
@@ -1,387 +1,217 @@
-SSL,function,276,SSL_AEAD_CTX_new
-SSL,function,277,SSL_AEAD_CTX_open
-SSL,function,278,SSL_AEAD_CTX_seal
-SSL,function,100,SSL_CTX_check_private_key
-SSL,function,101,SSL_CTX_new
-SSL,function,272,SSL_CTX_set1_tls_channel_id
-SSL,function,102,SSL_CTX_set_cipher_list
-SSL,function,103,SSL_CTX_set_cipher_list_tls11
-SSL,function,104,SSL_CTX_set_session_id_context
-SSL,function,268,SSL_CTX_set_tmp_dh
-SSL,function,269,SSL_CTX_set_tmp_ecdh
-SSL,function,105,SSL_CTX_use_PrivateKey
-SSL,function,106,SSL_CTX_use_PrivateKey_ASN1
-SSL,function,107,SSL_CTX_use_PrivateKey_file
-SSL,function,108,SSL_CTX_use_RSAPrivateKey
-SSL,function,109,SSL_CTX_use_RSAPrivateKey_ASN1
-SSL,function,110,SSL_CTX_use_RSAPrivateKey_file
-SSL,function,111,SSL_CTX_use_certificate
-SSL,function,112,SSL_CTX_use_certificate_ASN1
-SSL,function,113,SSL_CTX_use_certificate_chain_file
-SSL,function,114,SSL_CTX_use_certificate_file
-SSL,function,115,SSL_CTX_use_psk_identity_hint
-SSL,function,280,SSL_SESSION_from_bytes
-SSL,function,116,SSL_SESSION_new
-SSL,function,281,SSL_SESSION_parse
-SSL,function,150,SSL_SESSION_parse_octet_string
-SSL,function,151,SSL_SESSION_parse_string
-SSL,function,117,SSL_SESSION_print_fp
-SSL,function,118,SSL_SESSION_set1_id_context
-SSL,function,119,SSL_SESSION_to_bytes_full
-SSL,function,120,SSL_accept
-SSL,function,121,SSL_add_dir_cert_subjects_to_stack
-SSL,function,122,SSL_add_file_cert_subjects_to_stack
-SSL,function,123,SSL_check_private_key
-SSL,function,124,SSL_clear
-SSL,function,125,SSL_connect
-SSL,function,126,SSL_do_handshake
-SSL,function,127,SSL_load_client_CA_file
-SSL,function,128,SSL_new
-SSL,function,129,SSL_peek
-SSL,function,130,SSL_read
-SSL,function,131,SSL_renegotiate
-SSL,function,273,SSL_set1_tls_channel_id
-SSL,function,132,SSL_set_cipher_list
-SSL,function,133,SSL_set_fd
-SSL,function,134,SSL_set_rfd
-SSL,function,135,SSL_set_session_id_context
-SSL,function,274,SSL_set_tlsext_host_name
-SSL,function,270,SSL_set_tmp_dh
-SSL,function,271,SSL_set_tmp_ecdh
-SSL,function,136,SSL_set_wfd
-SSL,function,137,SSL_shutdown
-SSL,function,138,SSL_use_PrivateKey
-SSL,function,139,SSL_use_PrivateKey_ASN1
-SSL,function,140,SSL_use_PrivateKey_file
-SSL,function,141,SSL_use_RSAPrivateKey
-SSL,function,142,SSL_use_RSAPrivateKey_ASN1
-SSL,function,143,SSL_use_RSAPrivateKey_file
-SSL,function,144,SSL_use_certificate
-SSL,function,145,SSL_use_certificate_ASN1
-SSL,function,146,SSL_use_certificate_file
-SSL,function,147,SSL_use_psk_identity_hint
-SSL,function,148,SSL_write
-SSL,function,149,d2i_SSL_SESSION
-SSL,function,152,do_ssl3_write
-SSL,function,153,dtls1_accept
-SSL,function,154,dtls1_buffer_record
-SSL,function,155,dtls1_check_timeout_num
-SSL,function,156,dtls1_connect
-SSL,function,157,dtls1_do_write
-SSL,function,263,dtls1_get_buffered_message
-SSL,function,158,dtls1_get_hello_verify
-SSL,function,159,dtls1_get_message
-SSL,function,160,dtls1_get_message_fragment
-SSL,function,265,dtls1_hm_fragment_new
-SSL,function,161,dtls1_preprocess_fragment
-SSL,function,264,dtls1_process_fragment
-SSL,function,162,dtls1_process_record
-SSL,function,163,dtls1_read_bytes
-SSL,function,279,dtls1_seal_record
-SSL,function,164,dtls1_send_hello_verify_request
-SSL,function,165,dtls1_write_app_data
-SSL,function,166,i2d_SSL_SESSION
-SSL,function,167,ssl3_accept
-SSL,function,169,ssl3_cert_verify_hash
-SSL,function,170,ssl3_check_cert_and_algorithm
-SSL,function,282,ssl3_check_certificate_for_cipher
-SSL,function,171,ssl3_connect
-SSL,function,172,ssl3_ctrl
-SSL,function,173,ssl3_ctx_ctrl
-SSL,function,174,ssl3_digest_cached_records
-SSL,function,175,ssl3_do_change_cipher_spec
-SSL,function,176,ssl3_expect_change_cipher_spec
-SSL,function,177,ssl3_get_cert_status
-SSL,function,178,ssl3_get_cert_verify
-SSL,function,179,ssl3_get_certificate_request
-SSL,function,180,ssl3_get_channel_id
-SSL,function,181,ssl3_get_client_certificate
-SSL,function,182,ssl3_get_client_hello
-SSL,function,183,ssl3_get_client_key_exchange
-SSL,function,184,ssl3_get_finished
-SSL,function,185,ssl3_get_initial_bytes
-SSL,function,186,ssl3_get_message
-SSL,function,187,ssl3_get_new_session_ticket
-SSL,function,188,ssl3_get_next_proto
-SSL,function,189,ssl3_get_record
-SSL,function,190,ssl3_get_server_certificate
-SSL,function,191,ssl3_get_server_done
-SSL,function,192,ssl3_get_server_hello
-SSL,function,193,ssl3_get_server_key_exchange
-SSL,function,194,ssl3_get_v2_client_hello
-SSL,function,195,ssl3_handshake_mac
-SSL,function,275,ssl3_output_cert_chain
-SSL,function,196,ssl3_prf
-SSL,function,197,ssl3_read_bytes
-SSL,function,198,ssl3_read_n
-SSL,function,267,ssl3_record_sequence_update
-SSL,function,266,ssl3_seal_record
-SSL,function,199,ssl3_send_cert_verify
-SSL,function,200,ssl3_send_certificate_request
-SSL,function,201,ssl3_send_channel_id
-SSL,function,202,ssl3_send_client_certificate
-SSL,function,203,ssl3_send_client_hello
-SSL,function,204,ssl3_send_client_key_exchange
-SSL,function,205,ssl3_send_server_certificate
-SSL,function,206,ssl3_send_server_hello
-SSL,function,207,ssl3_send_server_key_exchange
-SSL,function,208,ssl3_setup_read_buffer
-SSL,function,209,ssl3_setup_write_buffer
-SSL,function,210,ssl3_write_bytes
-SSL,function,211,ssl3_write_pending
-SSL,function,212,ssl_add_cert_chain
-SSL,function,213,ssl_add_cert_to_buf
-SSL,function,214,ssl_add_clienthello_renegotiate_ext
-SSL,function,215,ssl_add_clienthello_tlsext
-SSL,function,216,ssl_add_clienthello_use_srtp_ext
-SSL,function,217,ssl_add_serverhello_renegotiate_ext
-SSL,function,218,ssl_add_serverhello_tlsext
-SSL,function,219,ssl_add_serverhello_use_srtp_ext
-SSL,function,220,ssl_build_cert_chain
-SSL,function,221,ssl_bytes_to_cipher_list
-SSL,function,222,ssl_cert_dup
-SSL,function,223,ssl_cert_inst
-SSL,function,224,ssl_cert_new
-SSL,function,225,ssl_check_serverhello_tlsext
-SSL,function,226,ssl_check_srvr_ecc_cert_and_alg
-SSL,function,227,ssl_cipher_process_rulestr
-SSL,function,228,ssl_cipher_strength_sort
-SSL,function,229,ssl_create_cipher_list
-SSL,function,230,ssl_ctx_log_master_secret
-SSL,function,231,ssl_ctx_log_rsa_client_key_exchange
-SSL,function,232,ssl_ctx_make_profiles
-SSL,function,233,ssl_get_new_session
-SSL,function,234,ssl_get_prev_session
-SSL,function,235,ssl_get_server_cert_index
-SSL,function,236,ssl_get_sign_pkey
-SSL,function,237,ssl_init_wbio_buffer
-SSL,function,238,ssl_parse_clienthello_renegotiate_ext
-SSL,function,239,ssl_parse_clienthello_tlsext
-SSL,function,240,ssl_parse_clienthello_use_srtp_ext
-SSL,function,241,ssl_parse_serverhello_renegotiate_ext
-SSL,function,242,ssl_parse_serverhello_tlsext
-SSL,function,243,ssl_parse_serverhello_use_srtp_ext
-SSL,function,244,ssl_scan_clienthello_tlsext
-SSL,function,245,ssl_scan_serverhello_tlsext
-SSL,function,246,ssl_sess_cert_new
-SSL,function,247,ssl_set_cert
-SSL,function,248,ssl_set_pkey
-SSL,function,252,ssl_verify_cert_chain
-SSL,function,253,tls12_check_peer_sigalg
-SSL,function,254,tls1_aead_ctx_init
-SSL,function,255,tls1_cert_verify_mac
-SSL,function,256,tls1_change_cipher_state
-SSL,function,257,tls1_change_cipher_state_aead
-SSL,function,258,tls1_check_duplicate_extensions
-SSL,function,259,tls1_enc
-SSL,function,260,tls1_export_keying_material
-SSL,function,261,tls1_prf
-SSL,function,262,tls1_setup_key_block
-SSL,reason,100,APP_DATA_IN_HANDSHAKE
-SSL,reason,101,ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT
-SSL,reason,102,BAD_ALERT
-SSL,reason,103,BAD_CHANGE_CIPHER_SPEC
-SSL,reason,104,BAD_DATA_RETURNED_BY_CALLBACK
-SSL,reason,105,BAD_DH_P_LENGTH
-SSL,reason,106,BAD_DIGEST_LENGTH
-SSL,reason,107,BAD_ECC_CERT
-SSL,reason,108,BAD_ECPOINT
-SSL,reason,109,BAD_HANDSHAKE_LENGTH
-SSL,reason,110,BAD_HANDSHAKE_RECORD
-SSL,reason,111,BAD_HELLO_REQUEST
-SSL,reason,112,BAD_LENGTH
-SSL,reason,113,BAD_PACKET_LENGTH
-SSL,reason,114,BAD_RSA_ENCRYPT
-SSL,reason,115,BAD_SIGNATURE
-SSL,reason,116,BAD_SRTP_MKI_VALUE
-SSL,reason,117,BAD_SRTP_PROTECTION_PROFILE_LIST
-SSL,reason,118,BAD_SSL_FILETYPE
-SSL,reason,119,BAD_WRITE_RETRY
-SSL,reason,120,BIO_NOT_SET
-SSL,reason,121,BN_LIB
-SSL,reason,272,BUFFER_TOO_SMALL
-SSL,reason,122,CANNOT_SERIALIZE_PUBLIC_KEY
-SSL,reason,123,CA_DN_LENGTH_MISMATCH
-SSL,reason,124,CA_DN_TOO_LONG
-SSL,reason,125,CCS_RECEIVED_EARLY
-SSL,reason,126,CERTIFICATE_VERIFY_FAILED
-SSL,reason,127,CERT_CB_ERROR
-SSL,reason,128,CERT_LENGTH_MISMATCH
-SSL,reason,129,CHANNEL_ID_NOT_P256
-SSL,reason,130,CHANNEL_ID_SIGNATURE_INVALID
-SSL,reason,131,CIPHER_CODE_WRONG_LENGTH
-SSL,reason,132,CIPHER_OR_HASH_UNAVAILABLE
-SSL,reason,133,CLIENTHELLO_PARSE_FAILED
-SSL,reason,134,CLIENTHELLO_TLSEXT
-SSL,reason,135,CONNECTION_REJECTED
-SSL,reason,136,CONNECTION_TYPE_NOT_SET
-SSL,reason,137,COOKIE_MISMATCH
-SSL,reason,138,D2I_ECDSA_SIG
-SSL,reason,139,DATA_BETWEEN_CCS_AND_FINISHED
-SSL,reason,140,DATA_LENGTH_TOO_LONG
-SSL,reason,141,DECODE_ERROR
-SSL,reason,142,DECRYPTION_FAILED
-SSL,reason,143,DECRYPTION_FAILED_OR_BAD_RECORD_MAC
-SSL,reason,144,DH_PUBLIC_VALUE_LENGTH_IS_WRONG
-SSL,reason,145,DIGEST_CHECK_FAILED
-SSL,reason,146,DTLS_MESSAGE_TOO_BIG
-SSL,reason,147,ECC_CERT_NOT_FOR_SIGNING
-SSL,reason,148,EMPTY_SRTP_PROTECTION_PROFILE_LIST
-SSL,reason,276,EMS_STATE_INCONSISTENT
-SSL,reason,149,ENCRYPTED_LENGTH_TOO_LONG
-SSL,reason,150,ERROR_IN_RECEIVED_CIPHER_LIST
-SSL,reason,151,EVP_DIGESTSIGNFINAL_FAILED
-SSL,reason,152,EVP_DIGESTSIGNINIT_FAILED
-SSL,reason,153,EXCESSIVE_MESSAGE_SIZE
-SSL,reason,154,EXTRA_DATA_IN_MESSAGE
-SSL,reason,271,FRAGMENT_MISMATCH
-SSL,reason,155,GOT_A_FIN_BEFORE_A_CCS
-SSL,reason,156,GOT_CHANNEL_ID_BEFORE_A_CCS
-SSL,reason,157,GOT_NEXT_PROTO_BEFORE_A_CCS
-SSL,reason,158,GOT_NEXT_PROTO_WITHOUT_EXTENSION
-SSL,reason,159,HANDSHAKE_FAILURE_ON_CLIENT_HELLO
-SSL,reason,160,HANDSHAKE_RECORD_BEFORE_CCS
-SSL,reason,161,HTTPS_PROXY_REQUEST
-SSL,reason,162,HTTP_REQUEST
-SSL,reason,163,INAPPROPRIATE_FALLBACK
-SSL,reason,164,INVALID_COMMAND
-SSL,reason,165,INVALID_MESSAGE
-SSL,reason,166,INVALID_SSL_SESSION
-SSL,reason,167,INVALID_TICKET_KEYS_LENGTH
-SSL,reason,168,LENGTH_MISMATCH
-SSL,reason,169,LIBRARY_HAS_NO_CIPHERS
-SSL,reason,170,MISSING_DH_KEY
-SSL,reason,171,MISSING_ECDSA_SIGNING_CERT
-SSL,reason,172,MISSING_RSA_CERTIFICATE
-SSL,reason,173,MISSING_RSA_ENCRYPTING_CERT
-SSL,reason,174,MISSING_RSA_SIGNING_CERT
-SSL,reason,175,MISSING_TMP_DH_KEY
-SSL,reason,176,MISSING_TMP_ECDH_KEY
-SSL,reason,177,MIXED_SPECIAL_OPERATOR_WITH_GROUPS
-SSL,reason,178,MTU_TOO_SMALL
-SSL,reason,179,NESTED_GROUP
-SSL,reason,180,NO_CERTIFICATES_RETURNED
-SSL,reason,181,NO_CERTIFICATE_ASSIGNED
-SSL,reason,182,NO_CERTIFICATE_SET
-SSL,reason,183,NO_CIPHERS_AVAILABLE
-SSL,reason,184,NO_CIPHERS_PASSED
-SSL,reason,185,NO_CIPHERS_SPECIFIED
-SSL,reason,186,NO_CIPHER_MATCH
-SSL,reason,187,NO_COMPRESSION_SPECIFIED
-SSL,reason,188,NO_METHOD_SPECIFIED
-SSL,reason,189,NO_P256_SUPPORT
-SSL,reason,190,NO_PRIVATE_KEY_ASSIGNED
-SSL,reason,191,NO_RENEGOTIATION
-SSL,reason,192,NO_REQUIRED_DIGEST
-SSL,reason,193,NO_SHARED_CIPHER
-SSL,reason,194,NO_SHARED_SIGATURE_ALGORITHMS
-SSL,reason,195,NO_SRTP_PROFILES
-SSL,reason,196,NULL_SSL_CTX
-SSL,reason,197,NULL_SSL_METHOD_PASSED
-SSL,reason,198,OLD_SESSION_CIPHER_NOT_RETURNED
-SSL,reason,273,OLD_SESSION_VERSION_NOT_RETURNED
-SSL,reason,274,OUTPUT_ALIASES_INPUT
-SSL,reason,199,PACKET_LENGTH_TOO_LONG
-SSL,reason,200,PARSE_TLSEXT
-SSL,reason,201,PATH_TOO_LONG
-SSL,reason,202,PEER_DID_NOT_RETURN_A_CERTIFICATE
-SSL,reason,203,PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE
-SSL,reason,204,PROTOCOL_IS_SHUTDOWN
-SSL,reason,205,PSK_IDENTITY_NOT_FOUND
-SSL,reason,206,PSK_NO_CLIENT_CB
-SSL,reason,207,PSK_NO_SERVER_CB
-SSL,reason,208,READ_BIO_NOT_SET
-SSL,reason,209,READ_TIMEOUT_EXPIRED
-SSL,reason,210,RECORD_LENGTH_MISMATCH
-SSL,reason,211,RECORD_TOO_LARGE
-SSL,reason,212,RENEGOTIATE_EXT_TOO_LONG
-SSL,reason,213,RENEGOTIATION_ENCODING_ERR
-SSL,reason,214,RENEGOTIATION_MISMATCH
-SSL,reason,215,REQUIRED_CIPHER_MISSING
-SSL,reason,275,RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION
-SSL,reason,277,RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION
-SSL,reason,216,SCSV_RECEIVED_WHEN_RENEGOTIATING
-SSL,reason,217,SERVERHELLO_TLSEXT
-SSL,reason,218,SESSION_ID_CONTEXT_UNINITIALIZED
-SSL,reason,219,SESSION_MAY_NOT_BE_CREATED
-SSL,reason,220,SIGNATURE_ALGORITHMS_ERROR
-SSL,reason,221,SRTP_COULD_NOT_ALLOCATE_PROFILES
-SSL,reason,222,SRTP_PROTECTION_PROFILE_LIST_TOO_LONG
-SSL,reason,223,SRTP_UNKNOWN_PROTECTION_PROFILE
-SSL,reason,224,SSL3_EXT_INVALID_SERVERNAME
-SSL,reason,225,SSL3_EXT_INVALID_SERVERNAME_TYPE
-SSL,reason,1042,SSLV3_ALERT_BAD_CERTIFICATE
-SSL,reason,1020,SSLV3_ALERT_BAD_RECORD_MAC
-SSL,reason,1045,SSLV3_ALERT_CERTIFICATE_EXPIRED
-SSL,reason,1044,SSLV3_ALERT_CERTIFICATE_REVOKED
-SSL,reason,1046,SSLV3_ALERT_CERTIFICATE_UNKNOWN
-SSL,reason,1000,SSLV3_ALERT_CLOSE_NOTIFY
-SSL,reason,1030,SSLV3_ALERT_DECOMPRESSION_FAILURE
-SSL,reason,1040,SSLV3_ALERT_HANDSHAKE_FAILURE
-SSL,reason,1047,SSLV3_ALERT_ILLEGAL_PARAMETER
-SSL,reason,1041,SSLV3_ALERT_NO_CERTIFICATE
-SSL,reason,1010,SSLV3_ALERT_UNEXPECTED_MESSAGE
-SSL,reason,1043,SSLV3_ALERT_UNSUPPORTED_CERTIFICATE
-SSL,reason,226,SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION
-SSL,reason,227,SSL_HANDSHAKE_FAILURE
-SSL,reason,228,SSL_SESSION_ID_CALLBACK_FAILED
-SSL,reason,229,SSL_SESSION_ID_CONFLICT
-SSL,reason,230,SSL_SESSION_ID_CONTEXT_TOO_LONG
-SSL,reason,231,SSL_SESSION_ID_HAS_BAD_LENGTH
-SSL,reason,1049,TLSV1_ALERT_ACCESS_DENIED
-SSL,reason,1050,TLSV1_ALERT_DECODE_ERROR
-SSL,reason,1021,TLSV1_ALERT_DECRYPTION_FAILED
-SSL,reason,1051,TLSV1_ALERT_DECRYPT_ERROR
-SSL,reason,1060,TLSV1_ALERT_EXPORT_RESTRICTION
-SSL,reason,1086,TLSV1_ALERT_INAPPROPRIATE_FALLBACK
-SSL,reason,1071,TLSV1_ALERT_INSUFFICIENT_SECURITY
-SSL,reason,1080,TLSV1_ALERT_INTERNAL_ERROR
-SSL,reason,1100,TLSV1_ALERT_NO_RENEGOTIATION
-SSL,reason,1070,TLSV1_ALERT_PROTOCOL_VERSION
-SSL,reason,1022,TLSV1_ALERT_RECORD_OVERFLOW
-SSL,reason,1048,TLSV1_ALERT_UNKNOWN_CA
-SSL,reason,1090,TLSV1_ALERT_USER_CANCELLED
-SSL,reason,1114,TLSV1_BAD_CERTIFICATE_HASH_VALUE
-SSL,reason,1113,TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE
-SSL,reason,1111,TLSV1_CERTIFICATE_UNOBTAINABLE
-SSL,reason,1112,TLSV1_UNRECOGNIZED_NAME
-SSL,reason,1110,TLSV1_UNSUPPORTED_EXTENSION
-SSL,reason,232,TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER
-SSL,reason,233,TLS_ILLEGAL_EXPORTER_LABEL
-SSL,reason,234,TLS_INVALID_ECPOINTFORMAT_LIST
-SSL,reason,235,TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST
-SSL,reason,236,TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG
-SSL,reason,237,TOO_MANY_EMPTY_FRAGMENTS
-SSL,reason,238,UNABLE_TO_FIND_ECDH_PARAMETERS
-SSL,reason,239,UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS
-SSL,reason,240,UNEXPECTED_GROUP_CLOSE
-SSL,reason,241,UNEXPECTED_MESSAGE
-SSL,reason,242,UNEXPECTED_OPERATOR_IN_GROUP
-SSL,reason,243,UNEXPECTED_RECORD
-SSL,reason,244,UNINITIALIZED
-SSL,reason,245,UNKNOWN_ALERT_TYPE
-SSL,reason,246,UNKNOWN_CERTIFICATE_TYPE
-SSL,reason,247,UNKNOWN_CIPHER_RETURNED
-SSL,reason,248,UNKNOWN_CIPHER_TYPE
-SSL,reason,249,UNKNOWN_DIGEST
-SSL,reason,250,UNKNOWN_KEY_EXCHANGE_TYPE
-SSL,reason,251,UNKNOWN_PROTOCOL
-SSL,reason,252,UNKNOWN_SSL_VERSION
-SSL,reason,253,UNKNOWN_STATE
-SSL,reason,254,UNPROCESSED_HANDSHAKE_DATA
-SSL,reason,255,UNSAFE_LEGACY_RENEGOTIATION_DISABLED
-SSL,reason,256,UNSUPPORTED_CIPHER
-SSL,reason,257,UNSUPPORTED_COMPRESSION_ALGORITHM
-SSL,reason,258,UNSUPPORTED_ELLIPTIC_CURVE
-SSL,reason,259,UNSUPPORTED_PROTOCOL
-SSL,reason,260,UNSUPPORTED_SSL_VERSION
-SSL,reason,261,USE_SRTP_NOT_NEGOTIATED
-SSL,reason,262,WRONG_CERTIFICATE_TYPE
-SSL,reason,263,WRONG_CIPHER_RETURNED
-SSL,reason,264,WRONG_CURVE
-SSL,reason,265,WRONG_MESSAGE_TYPE
-SSL,reason,266,WRONG_SIGNATURE_TYPE
-SSL,reason,267,WRONG_SSL_VERSION
-SSL,reason,268,WRONG_VERSION_NUMBER
-SSL,reason,269,X509_LIB
-SSL,reason,270,X509_VERIFICATION_SETUP_PROBLEMS
+SSL,100,APP_DATA_IN_HANDSHAKE
+SSL,101,ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT
+SSL,102,BAD_ALERT
+SSL,103,BAD_CHANGE_CIPHER_SPEC
+SSL,104,BAD_DATA_RETURNED_BY_CALLBACK
+SSL,105,BAD_DH_P_LENGTH
+SSL,106,BAD_DIGEST_LENGTH
+SSL,107,BAD_ECC_CERT
+SSL,108,BAD_ECPOINT
+SSL,109,BAD_HANDSHAKE_LENGTH
+SSL,110,BAD_HANDSHAKE_RECORD
+SSL,111,BAD_HELLO_REQUEST
+SSL,112,BAD_LENGTH
+SSL,113,BAD_PACKET_LENGTH
+SSL,114,BAD_RSA_ENCRYPT
+SSL,115,BAD_SIGNATURE
+SSL,116,BAD_SRTP_MKI_VALUE
+SSL,117,BAD_SRTP_PROTECTION_PROFILE_LIST
+SSL,118,BAD_SSL_FILETYPE
+SSL,119,BAD_WRITE_RETRY
+SSL,120,BIO_NOT_SET
+SSL,121,BN_LIB
+SSL,272,BUFFER_TOO_SMALL
+SSL,122,CANNOT_SERIALIZE_PUBLIC_KEY
+SSL,123,CA_DN_LENGTH_MISMATCH
+SSL,124,CA_DN_TOO_LONG
+SSL,125,CCS_RECEIVED_EARLY
+SSL,126,CERTIFICATE_VERIFY_FAILED
+SSL,127,CERT_CB_ERROR
+SSL,128,CERT_LENGTH_MISMATCH
+SSL,129,CHANNEL_ID_NOT_P256
+SSL,130,CHANNEL_ID_SIGNATURE_INVALID
+SSL,131,CIPHER_CODE_WRONG_LENGTH
+SSL,132,CIPHER_OR_HASH_UNAVAILABLE
+SSL,133,CLIENTHELLO_PARSE_FAILED
+SSL,134,CLIENTHELLO_TLSEXT
+SSL,135,CONNECTION_REJECTED
+SSL,136,CONNECTION_TYPE_NOT_SET
+SSL,137,COOKIE_MISMATCH
+SSL,284,CUSTOM_EXTENSION_CONTENTS_TOO_LARGE
+SSL,285,CUSTOM_EXTENSION_ERROR
+SSL,138,D2I_ECDSA_SIG
+SSL,139,DATA_BETWEEN_CCS_AND_FINISHED
+SSL,140,DATA_LENGTH_TOO_LONG
+SSL,141,DECODE_ERROR
+SSL,142,DECRYPTION_FAILED
+SSL,143,DECRYPTION_FAILED_OR_BAD_RECORD_MAC
+SSL,144,DH_PUBLIC_VALUE_LENGTH_IS_WRONG
+SSL,145,DIGEST_CHECK_FAILED
+SSL,146,DTLS_MESSAGE_TOO_BIG
+SSL,147,ECC_CERT_NOT_FOR_SIGNING
+SSL,148,EMPTY_SRTP_PROTECTION_PROFILE_LIST
+SSL,276,EMS_STATE_INCONSISTENT
+SSL,149,ENCRYPTED_LENGTH_TOO_LONG
+SSL,281,ERROR_ADDING_EXTENSION
+SSL,150,ERROR_IN_RECEIVED_CIPHER_LIST
+SSL,282,ERROR_PARSING_EXTENSION
+SSL,151,EVP_DIGESTSIGNFINAL_FAILED
+SSL,152,EVP_DIGESTSIGNINIT_FAILED
+SSL,153,EXCESSIVE_MESSAGE_SIZE
+SSL,154,EXTRA_DATA_IN_MESSAGE
+SSL,271,FRAGMENT_MISMATCH
+SSL,155,GOT_A_FIN_BEFORE_A_CCS
+SSL,156,GOT_CHANNEL_ID_BEFORE_A_CCS
+SSL,157,GOT_NEXT_PROTO_BEFORE_A_CCS
+SSL,158,GOT_NEXT_PROTO_WITHOUT_EXTENSION
+SSL,159,HANDSHAKE_FAILURE_ON_CLIENT_HELLO
+SSL,160,HANDSHAKE_RECORD_BEFORE_CCS
+SSL,161,HTTPS_PROXY_REQUEST
+SSL,162,HTTP_REQUEST
+SSL,163,INAPPROPRIATE_FALLBACK
+SSL,164,INVALID_COMMAND
+SSL,165,INVALID_MESSAGE
+SSL,166,INVALID_SSL_SESSION
+SSL,167,INVALID_TICKET_KEYS_LENGTH
+SSL,168,LENGTH_MISMATCH
+SSL,169,LIBRARY_HAS_NO_CIPHERS
+SSL,170,MISSING_DH_KEY
+SSL,171,MISSING_ECDSA_SIGNING_CERT
+SSL,283,MISSING_EXTENSION
+SSL,172,MISSING_RSA_CERTIFICATE
+SSL,173,MISSING_RSA_ENCRYPTING_CERT
+SSL,174,MISSING_RSA_SIGNING_CERT
+SSL,175,MISSING_TMP_DH_KEY
+SSL,176,MISSING_TMP_ECDH_KEY
+SSL,177,MIXED_SPECIAL_OPERATOR_WITH_GROUPS
+SSL,178,MTU_TOO_SMALL
+SSL,286,NEGOTIATED_BOTH_NPN_AND_ALPN
+SSL,179,NESTED_GROUP
+SSL,180,NO_CERTIFICATES_RETURNED
+SSL,181,NO_CERTIFICATE_ASSIGNED
+SSL,182,NO_CERTIFICATE_SET
+SSL,183,NO_CIPHERS_AVAILABLE
+SSL,184,NO_CIPHERS_PASSED
+SSL,185,NO_CIPHERS_SPECIFIED
+SSL,186,NO_CIPHER_MATCH
+SSL,187,NO_COMPRESSION_SPECIFIED
+SSL,188,NO_METHOD_SPECIFIED
+SSL,189,NO_P256_SUPPORT
+SSL,190,NO_PRIVATE_KEY_ASSIGNED
+SSL,191,NO_RENEGOTIATION
+SSL,192,NO_REQUIRED_DIGEST
+SSL,193,NO_SHARED_CIPHER
+SSL,194,NO_SHARED_SIGATURE_ALGORITHMS
+SSL,195,NO_SRTP_PROFILES
+SSL,196,NULL_SSL_CTX
+SSL,197,NULL_SSL_METHOD_PASSED
+SSL,198,OLD_SESSION_CIPHER_NOT_RETURNED
+SSL,273,OLD_SESSION_VERSION_NOT_RETURNED
+SSL,274,OUTPUT_ALIASES_INPUT
+SSL,199,PACKET_LENGTH_TOO_LONG
+SSL,200,PARSE_TLSEXT
+SSL,201,PATH_TOO_LONG
+SSL,202,PEER_DID_NOT_RETURN_A_CERTIFICATE
+SSL,203,PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE
+SSL,204,PROTOCOL_IS_SHUTDOWN
+SSL,205,PSK_IDENTITY_NOT_FOUND
+SSL,206,PSK_NO_CLIENT_CB
+SSL,207,PSK_NO_SERVER_CB
+SSL,208,READ_BIO_NOT_SET
+SSL,209,READ_TIMEOUT_EXPIRED
+SSL,210,RECORD_LENGTH_MISMATCH
+SSL,211,RECORD_TOO_LARGE
+SSL,212,RENEGOTIATE_EXT_TOO_LONG
+SSL,213,RENEGOTIATION_ENCODING_ERR
+SSL,214,RENEGOTIATION_MISMATCH
+SSL,215,REQUIRED_CIPHER_MISSING
+SSL,275,RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION
+SSL,277,RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION
+SSL,216,SCSV_RECEIVED_WHEN_RENEGOTIATING
+SSL,217,SERVERHELLO_TLSEXT
+SSL,218,SESSION_ID_CONTEXT_UNINITIALIZED
+SSL,219,SESSION_MAY_NOT_BE_CREATED
+SSL,220,SIGNATURE_ALGORITHMS_ERROR
+SSL,280,SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER
+SSL,221,SRTP_COULD_NOT_ALLOCATE_PROFILES
+SSL,222,SRTP_PROTECTION_PROFILE_LIST_TOO_LONG
+SSL,223,SRTP_UNKNOWN_PROTECTION_PROFILE
+SSL,224,SSL3_EXT_INVALID_SERVERNAME
+SSL,225,SSL3_EXT_INVALID_SERVERNAME_TYPE
+SSL,1042,SSLV3_ALERT_BAD_CERTIFICATE
+SSL,1020,SSLV3_ALERT_BAD_RECORD_MAC
+SSL,1045,SSLV3_ALERT_CERTIFICATE_EXPIRED
+SSL,1044,SSLV3_ALERT_CERTIFICATE_REVOKED
+SSL,1046,SSLV3_ALERT_CERTIFICATE_UNKNOWN
+SSL,1000,SSLV3_ALERT_CLOSE_NOTIFY
+SSL,1030,SSLV3_ALERT_DECOMPRESSION_FAILURE
+SSL,1040,SSLV3_ALERT_HANDSHAKE_FAILURE
+SSL,1047,SSLV3_ALERT_ILLEGAL_PARAMETER
+SSL,1041,SSLV3_ALERT_NO_CERTIFICATE
+SSL,1010,SSLV3_ALERT_UNEXPECTED_MESSAGE
+SSL,1043,SSLV3_ALERT_UNSUPPORTED_CERTIFICATE
+SSL,226,SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION
+SSL,227,SSL_HANDSHAKE_FAILURE
+SSL,228,SSL_SESSION_ID_CALLBACK_FAILED
+SSL,229,SSL_SESSION_ID_CONFLICT
+SSL,230,SSL_SESSION_ID_CONTEXT_TOO_LONG
+SSL,231,SSL_SESSION_ID_HAS_BAD_LENGTH
+SSL,1049,TLSV1_ALERT_ACCESS_DENIED
+SSL,1050,TLSV1_ALERT_DECODE_ERROR
+SSL,1021,TLSV1_ALERT_DECRYPTION_FAILED
+SSL,1051,TLSV1_ALERT_DECRYPT_ERROR
+SSL,1060,TLSV1_ALERT_EXPORT_RESTRICTION
+SSL,1086,TLSV1_ALERT_INAPPROPRIATE_FALLBACK
+SSL,1071,TLSV1_ALERT_INSUFFICIENT_SECURITY
+SSL,1080,TLSV1_ALERT_INTERNAL_ERROR
+SSL,1100,TLSV1_ALERT_NO_RENEGOTIATION
+SSL,1070,TLSV1_ALERT_PROTOCOL_VERSION
+SSL,1022,TLSV1_ALERT_RECORD_OVERFLOW
+SSL,1048,TLSV1_ALERT_UNKNOWN_CA
+SSL,1090,TLSV1_ALERT_USER_CANCELLED
+SSL,1114,TLSV1_BAD_CERTIFICATE_HASH_VALUE
+SSL,1113,TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE
+SSL,1111,TLSV1_CERTIFICATE_UNOBTAINABLE
+SSL,1112,TLSV1_UNRECOGNIZED_NAME
+SSL,1110,TLSV1_UNSUPPORTED_EXTENSION
+SSL,232,TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER
+SSL,233,TLS_ILLEGAL_EXPORTER_LABEL
+SSL,234,TLS_INVALID_ECPOINTFORMAT_LIST
+SSL,235,TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST
+SSL,236,TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG
+SSL,237,TOO_MANY_EMPTY_FRAGMENTS
+SSL,278,TOO_MANY_WARNING_ALERTS
+SSL,238,UNABLE_TO_FIND_ECDH_PARAMETERS
+SSL,239,UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS
+SSL,279,UNEXPECTED_EXTENSION
+SSL,240,UNEXPECTED_GROUP_CLOSE
+SSL,241,UNEXPECTED_MESSAGE
+SSL,242,UNEXPECTED_OPERATOR_IN_GROUP
+SSL,243,UNEXPECTED_RECORD
+SSL,244,UNINITIALIZED
+SSL,245,UNKNOWN_ALERT_TYPE
+SSL,246,UNKNOWN_CERTIFICATE_TYPE
+SSL,247,UNKNOWN_CIPHER_RETURNED
+SSL,248,UNKNOWN_CIPHER_TYPE
+SSL,249,UNKNOWN_DIGEST
+SSL,250,UNKNOWN_KEY_EXCHANGE_TYPE
+SSL,251,UNKNOWN_PROTOCOL
+SSL,252,UNKNOWN_SSL_VERSION
+SSL,253,UNKNOWN_STATE
+SSL,254,UNPROCESSED_HANDSHAKE_DATA
+SSL,255,UNSAFE_LEGACY_RENEGOTIATION_DISABLED
+SSL,256,UNSUPPORTED_CIPHER
+SSL,257,UNSUPPORTED_COMPRESSION_ALGORITHM
+SSL,258,UNSUPPORTED_ELLIPTIC_CURVE
+SSL,259,UNSUPPORTED_PROTOCOL
+SSL,260,UNSUPPORTED_SSL_VERSION
+SSL,261,USE_SRTP_NOT_NEGOTIATED
+SSL,262,WRONG_CERTIFICATE_TYPE
+SSL,263,WRONG_CIPHER_RETURNED
+SSL,264,WRONG_CURVE
+SSL,265,WRONG_MESSAGE_TYPE
+SSL,266,WRONG_SIGNATURE_TYPE
+SSL,267,WRONG_SSL_VERSION
+SSL,268,WRONG_VERSION_NUMBER
+SSL,269,X509_LIB
+SSL,270,X509_VERIFICATION_SETUP_PROBLEMS
diff --git a/src/crypto/err/x509.errordata b/src/crypto/err/x509.errordata
index 1b50e36..f4828ce 100644
--- a/src/crypto/err/x509.errordata
+++ b/src/crypto/err/x509.errordata
@@ -1,96 +1,37 @@
-X509,function,100,ASN1_digest
-X509,function,101,ASN1_item_sign_ctx
-X509,function,102,ASN1_item_verify
-X509,function,103,NETSCAPE_SPKI_b64_decode
-X509,function,104,NETSCAPE_SPKI_b64_encode
-X509,function,158,PKCS7_get_CRLs
-X509,function,105,PKCS7_get_certificates
-X509,function,106,X509_ATTRIBUTE_create_by_NID
-X509,function,107,X509_ATTRIBUTE_create_by_OBJ
-X509,function,108,X509_ATTRIBUTE_create_by_txt
-X509,function,109,X509_ATTRIBUTE_get0_data
-X509,function,110,X509_ATTRIBUTE_set1_data
-X509,function,111,X509_CRL_add0_revoked
-X509,function,112,X509_CRL_diff
-X509,function,113,X509_CRL_print_fp
-X509,function,114,X509_EXTENSION_create_by_NID
-X509,function,115,X509_EXTENSION_create_by_OBJ
-X509,function,116,X509_INFO_new
-X509,function,117,X509_NAME_ENTRY_create_by_NID
-X509,function,118,X509_NAME_ENTRY_create_by_txt
-X509,function,119,X509_NAME_ENTRY_set_object
-X509,function,120,X509_NAME_add_entry
-X509,function,121,X509_NAME_oneline
-X509,function,122,X509_NAME_print
-X509,function,123,X509_PKEY_new
-X509,function,124,X509_PUBKEY_get
-X509,function,125,X509_PUBKEY_set
-X509,function,126,X509_REQ_check_private_key
-X509,function,127,X509_REQ_to_X509
-X509,function,128,X509_STORE_CTX_get1_issuer
-X509,function,129,X509_STORE_CTX_init
-X509,function,130,X509_STORE_CTX_new
-X509,function,131,X509_STORE_CTX_purpose_inherit
-X509,function,132,X509_STORE_add_cert
-X509,function,133,X509_STORE_add_crl
-X509,function,134,X509_TRUST_add
-X509,function,135,X509_TRUST_set
-X509,function,136,X509_check_private_key
-X509,function,137,X509_get_pubkey_parameters
-X509,function,138,X509_load_cert_crl_file
-X509,function,139,X509_load_cert_file
-X509,function,140,X509_load_crl_file
-X509,function,141,X509_print_ex_fp
-X509,function,142,X509_to_X509_REQ
-X509,function,143,X509_verify_cert
-X509,function,144,X509at_add1_attr
-X509,function,145,X509v3_add_ext
-X509,function,146,add_cert_dir
-X509,function,147,by_file_ctrl
-X509,function,148,check_policy
-X509,function,149,dir_ctrl
-X509,function,150,get_cert_by_subject
-X509,function,151,i2d_DSA_PUBKEY
-X509,function,152,i2d_EC_PUBKEY
-X509,function,153,i2d_RSA_PUBKEY
-X509,function,157,pkcs7_parse_header
-X509,function,154,x509_name_encode
-X509,function,155,x509_name_ex_d2i
-X509,function,156,x509_name_ex_new
-X509,reason,100,AKID_MISMATCH
-X509,reason,101,BAD_PKCS7_VERSION
-X509,reason,102,BAD_X509_FILETYPE
-X509,reason,103,BASE64_DECODE_ERROR
-X509,reason,104,CANT_CHECK_DH_KEY
-X509,reason,105,CERT_ALREADY_IN_HASH_TABLE
-X509,reason,106,CRL_ALREADY_DELTA
-X509,reason,107,CRL_VERIFY_FAILURE
-X509,reason,108,IDP_MISMATCH
-X509,reason,109,INVALID_BIT_STRING_BITS_LEFT
-X509,reason,110,INVALID_DIRECTORY
-X509,reason,111,INVALID_FIELD_NAME
-X509,reason,112,INVALID_TRUST
-X509,reason,113,ISSUER_MISMATCH
-X509,reason,114,KEY_TYPE_MISMATCH
-X509,reason,115,KEY_VALUES_MISMATCH
-X509,reason,116,LOADING_CERT_DIR
-X509,reason,117,LOADING_DEFAULTS
-X509,reason,118,METHOD_NOT_SUPPORTED
-X509,reason,119,NEWER_CRL_NOT_NEWER
-X509,reason,120,NOT_PKCS7_SIGNED_DATA
-X509,reason,121,NO_CERTIFICATES_INCLUDED
-X509,reason,122,NO_CERT_SET_FOR_US_TO_VERIFY
-X509,reason,136,NO_CRLS_INCLUDED
-X509,reason,123,NO_CRL_NUMBER
-X509,reason,124,PUBLIC_KEY_DECODE_ERROR
-X509,reason,125,PUBLIC_KEY_ENCODE_ERROR
-X509,reason,126,SHOULD_RETRY
-X509,reason,127,UNABLE_TO_FIND_PARAMETERS_IN_CHAIN
-X509,reason,128,UNABLE_TO_GET_CERTS_PUBLIC_KEY
-X509,reason,129,UNKNOWN_KEY_TYPE
-X509,reason,130,UNKNOWN_NID
-X509,reason,131,UNKNOWN_PURPOSE_ID
-X509,reason,132,UNKNOWN_TRUST_ID
-X509,reason,133,UNSUPPORTED_ALGORITHM
-X509,reason,134,WRONG_LOOKUP_TYPE
-X509,reason,135,WRONG_TYPE
+X509,100,AKID_MISMATCH
+X509,101,BAD_PKCS7_VERSION
+X509,102,BAD_X509_FILETYPE
+X509,103,BASE64_DECODE_ERROR
+X509,104,CANT_CHECK_DH_KEY
+X509,105,CERT_ALREADY_IN_HASH_TABLE
+X509,106,CRL_ALREADY_DELTA
+X509,107,CRL_VERIFY_FAILURE
+X509,108,IDP_MISMATCH
+X509,109,INVALID_BIT_STRING_BITS_LEFT
+X509,110,INVALID_DIRECTORY
+X509,111,INVALID_FIELD_NAME
+X509,112,INVALID_TRUST
+X509,113,ISSUER_MISMATCH
+X509,114,KEY_TYPE_MISMATCH
+X509,115,KEY_VALUES_MISMATCH
+X509,116,LOADING_CERT_DIR
+X509,117,LOADING_DEFAULTS
+X509,118,METHOD_NOT_SUPPORTED
+X509,119,NEWER_CRL_NOT_NEWER
+X509,120,NOT_PKCS7_SIGNED_DATA
+X509,121,NO_CERTIFICATES_INCLUDED
+X509,122,NO_CERT_SET_FOR_US_TO_VERIFY
+X509,136,NO_CRLS_INCLUDED
+X509,123,NO_CRL_NUMBER
+X509,124,PUBLIC_KEY_DECODE_ERROR
+X509,125,PUBLIC_KEY_ENCODE_ERROR
+X509,126,SHOULD_RETRY
+X509,127,UNABLE_TO_FIND_PARAMETERS_IN_CHAIN
+X509,128,UNABLE_TO_GET_CERTS_PUBLIC_KEY
+X509,129,UNKNOWN_KEY_TYPE
+X509,130,UNKNOWN_NID
+X509,131,UNKNOWN_PURPOSE_ID
+X509,132,UNKNOWN_TRUST_ID
+X509,133,UNSUPPORTED_ALGORITHM
+X509,134,WRONG_LOOKUP_TYPE
+X509,135,WRONG_TYPE
diff --git a/src/crypto/err/x509v3.errordata b/src/crypto/err/x509v3.errordata
index 059e677..e53b780 100644
--- a/src/crypto/err/x509v3.errordata
+++ b/src/crypto/err/x509v3.errordata
@@ -1,120 +1,63 @@
-X509V3,function,100,SXNET_add_id_INTEGER
-X509V3,function,101,SXNET_add_id_asc
-X509V3,function,102,SXNET_add_id_ulong
-X509V3,function,103,SXNET_get_id_asc
-X509V3,function,104,SXNET_get_id_ulong
-X509V3,function,105,X509V3_EXT_add
-X509V3,function,106,X509V3_EXT_add_alias
-X509V3,function,107,X509V3_EXT_free
-X509V3,function,108,X509V3_EXT_i2d
-X509V3,function,109,X509V3_EXT_nconf
-X509V3,function,110,X509V3_add1_i2d
-X509V3,function,111,X509V3_add_value
-X509V3,function,112,X509V3_get_section
-X509V3,function,113,X509V3_get_string
-X509V3,function,114,X509V3_get_value_bool
-X509V3,function,115,X509V3_parse_list
-X509V3,function,116,X509_PURPOSE_add
-X509V3,function,117,X509_PURPOSE_set
-X509V3,function,118,a2i_GENERAL_NAME
-X509V3,function,119,copy_email
-X509V3,function,120,copy_issuer
-X509V3,function,121,do_dirname
-X509V3,function,122,do_ext_i2d
-X509V3,function,123,do_ext_nconf
-X509V3,function,124,gnames_from_sectname
-X509V3,function,125,hex_to_string
-X509V3,function,126,i2s_ASN1_ENUMERATED
-X509V3,function,127,i2s_ASN1_IA5STRING
-X509V3,function,128,i2s_ASN1_INTEGER
-X509V3,function,129,i2v_AUTHORITY_INFO_ACCESS
-X509V3,function,130,notice_section
-X509V3,function,131,nref_nos
-X509V3,function,132,policy_section
-X509V3,function,133,process_pci_value
-X509V3,function,134,r2i_certpol
-X509V3,function,135,r2i_pci
-X509V3,function,136,s2i_ASN1_IA5STRING
-X509V3,function,137,s2i_ASN1_INTEGER
-X509V3,function,138,s2i_ASN1_OCTET_STRING
-X509V3,function,139,s2i_skey_id
-X509V3,function,140,set_dist_point_name
-X509V3,function,141,string_to_hex
-X509V3,function,142,v2i_ASN1_BIT_STRING
-X509V3,function,143,v2i_AUTHORITY_INFO_ACCESS
-X509V3,function,144,v2i_AUTHORITY_KEYID
-X509V3,function,145,v2i_BASIC_CONSTRAINTS
-X509V3,function,146,v2i_EXTENDED_KEY_USAGE
-X509V3,function,147,v2i_GENERAL_NAMES
-X509V3,function,148,v2i_GENERAL_NAME_ex
-X509V3,function,149,v2i_NAME_CONSTRAINTS
-X509V3,function,150,v2i_POLICY_CONSTRAINTS
-X509V3,function,151,v2i_POLICY_MAPPINGS
-X509V3,function,152,v2i_crld
-X509V3,function,153,v2i_idp
-X509V3,function,154,v2i_issuer_alt
-X509V3,function,155,v2i_subject_alt
-X509V3,function,156,v3_generic_extension
-X509V3,reason,100,BAD_IP_ADDRESS
-X509V3,reason,101,BAD_OBJECT
-X509V3,reason,102,BN_DEC2BN_ERROR
-X509V3,reason,103,BN_TO_ASN1_INTEGER_ERROR
-X509V3,reason,104,CANNOT_FIND_FREE_FUNCTION
-X509V3,reason,105,DIRNAME_ERROR
-X509V3,reason,106,DISTPOINT_ALREADY_SET
-X509V3,reason,107,DUPLICATE_ZONE_ID
-X509V3,reason,108,ERROR_CONVERTING_ZONE
-X509V3,reason,109,ERROR_CREATING_EXTENSION
-X509V3,reason,110,ERROR_IN_EXTENSION
-X509V3,reason,111,EXPECTED_A_SECTION_NAME
-X509V3,reason,112,EXTENSION_EXISTS
-X509V3,reason,113,EXTENSION_NAME_ERROR
-X509V3,reason,114,EXTENSION_NOT_FOUND
-X509V3,reason,115,EXTENSION_SETTING_NOT_SUPPORTED
-X509V3,reason,116,EXTENSION_VALUE_ERROR
-X509V3,reason,117,ILLEGAL_EMPTY_EXTENSION
-X509V3,reason,118,ILLEGAL_HEX_DIGIT
-X509V3,reason,119,INCORRECT_POLICY_SYNTAX_TAG
-X509V3,reason,120,INVALID_BOOLEAN_STRING
-X509V3,reason,121,INVALID_EXTENSION_STRING
-X509V3,reason,122,INVALID_MULTIPLE_RDNS
-X509V3,reason,123,INVALID_NAME
-X509V3,reason,124,INVALID_NULL_ARGUMENT
-X509V3,reason,125,INVALID_NULL_NAME
-X509V3,reason,126,INVALID_NULL_VALUE
-X509V3,reason,127,INVALID_NUMBER
-X509V3,reason,128,INVALID_NUMBERS
-X509V3,reason,129,INVALID_OBJECT_IDENTIFIER
-X509V3,reason,130,INVALID_OPTION
-X509V3,reason,131,INVALID_POLICY_IDENTIFIER
-X509V3,reason,132,INVALID_PROXY_POLICY_SETTING
-X509V3,reason,133,INVALID_PURPOSE
-X509V3,reason,134,INVALID_SECTION
-X509V3,reason,135,INVALID_SYNTAX
-X509V3,reason,136,ISSUER_DECODE_ERROR
-X509V3,reason,137,MISSING_VALUE
-X509V3,reason,138,NEED_ORGANIZATION_AND_NUMBERS
-X509V3,reason,139,NO_CONFIG_DATABASE
-X509V3,reason,140,NO_ISSUER_CERTIFICATE
-X509V3,reason,141,NO_ISSUER_DETAILS
-X509V3,reason,142,NO_POLICY_IDENTIFIER
-X509V3,reason,143,NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED
-X509V3,reason,144,NO_PUBLIC_KEY
-X509V3,reason,145,NO_SUBJECT_DETAILS
-X509V3,reason,146,ODD_NUMBER_OF_DIGITS
-X509V3,reason,147,OPERATION_NOT_DEFINED
-X509V3,reason,148,OTHERNAME_ERROR
-X509V3,reason,149,POLICY_LANGUAGE_ALREADY_DEFINED
-X509V3,reason,150,POLICY_PATH_LENGTH
-X509V3,reason,151,POLICY_PATH_LENGTH_ALREADY_DEFINED
-X509V3,reason,152,POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY
-X509V3,reason,153,SECTION_NOT_FOUND
-X509V3,reason,154,UNABLE_TO_GET_ISSUER_DETAILS
-X509V3,reason,155,UNABLE_TO_GET_ISSUER_KEYID
-X509V3,reason,156,UNKNOWN_BIT_STRING_ARGUMENT
-X509V3,reason,157,UNKNOWN_EXTENSION
-X509V3,reason,158,UNKNOWN_EXTENSION_NAME
-X509V3,reason,159,UNKNOWN_OPTION
-X509V3,reason,160,UNSUPPORTED_OPTION
-X509V3,reason,161,UNSUPPORTED_TYPE
-X509V3,reason,162,USER_TOO_LONG
+X509V3,100,BAD_IP_ADDRESS
+X509V3,101,BAD_OBJECT
+X509V3,102,BN_DEC2BN_ERROR
+X509V3,103,BN_TO_ASN1_INTEGER_ERROR
+X509V3,104,CANNOT_FIND_FREE_FUNCTION
+X509V3,105,DIRNAME_ERROR
+X509V3,106,DISTPOINT_ALREADY_SET
+X509V3,107,DUPLICATE_ZONE_ID
+X509V3,108,ERROR_CONVERTING_ZONE
+X509V3,109,ERROR_CREATING_EXTENSION
+X509V3,110,ERROR_IN_EXTENSION
+X509V3,111,EXPECTED_A_SECTION_NAME
+X509V3,112,EXTENSION_EXISTS
+X509V3,113,EXTENSION_NAME_ERROR
+X509V3,114,EXTENSION_NOT_FOUND
+X509V3,115,EXTENSION_SETTING_NOT_SUPPORTED
+X509V3,116,EXTENSION_VALUE_ERROR
+X509V3,117,ILLEGAL_EMPTY_EXTENSION
+X509V3,118,ILLEGAL_HEX_DIGIT
+X509V3,119,INCORRECT_POLICY_SYNTAX_TAG
+X509V3,120,INVALID_BOOLEAN_STRING
+X509V3,121,INVALID_EXTENSION_STRING
+X509V3,122,INVALID_MULTIPLE_RDNS
+X509V3,123,INVALID_NAME
+X509V3,124,INVALID_NULL_ARGUMENT
+X509V3,125,INVALID_NULL_NAME
+X509V3,126,INVALID_NULL_VALUE
+X509V3,127,INVALID_NUMBER
+X509V3,128,INVALID_NUMBERS
+X509V3,129,INVALID_OBJECT_IDENTIFIER
+X509V3,130,INVALID_OPTION
+X509V3,131,INVALID_POLICY_IDENTIFIER
+X509V3,132,INVALID_PROXY_POLICY_SETTING
+X509V3,133,INVALID_PURPOSE
+X509V3,134,INVALID_SECTION
+X509V3,135,INVALID_SYNTAX
+X509V3,136,ISSUER_DECODE_ERROR
+X509V3,137,MISSING_VALUE
+X509V3,138,NEED_ORGANIZATION_AND_NUMBERS
+X509V3,139,NO_CONFIG_DATABASE
+X509V3,140,NO_ISSUER_CERTIFICATE
+X509V3,141,NO_ISSUER_DETAILS
+X509V3,142,NO_POLICY_IDENTIFIER
+X509V3,143,NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED
+X509V3,144,NO_PUBLIC_KEY
+X509V3,145,NO_SUBJECT_DETAILS
+X509V3,146,ODD_NUMBER_OF_DIGITS
+X509V3,147,OPERATION_NOT_DEFINED
+X509V3,148,OTHERNAME_ERROR
+X509V3,149,POLICY_LANGUAGE_ALREADY_DEFINED
+X509V3,150,POLICY_PATH_LENGTH
+X509V3,151,POLICY_PATH_LENGTH_ALREADY_DEFINED
+X509V3,152,POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY
+X509V3,153,SECTION_NOT_FOUND
+X509V3,154,UNABLE_TO_GET_ISSUER_DETAILS
+X509V3,155,UNABLE_TO_GET_ISSUER_KEYID
+X509V3,156,UNKNOWN_BIT_STRING_ARGUMENT
+X509V3,157,UNKNOWN_EXTENSION
+X509V3,158,UNKNOWN_EXTENSION_NAME
+X509V3,159,UNKNOWN_OPTION
+X509V3,160,UNSUPPORTED_OPTION
+X509V3,161,UNSUPPORTED_TYPE
+X509V3,162,USER_TOO_LONG
diff --git a/src/crypto/evp/CMakeLists.txt b/src/crypto/evp/CMakeLists.txt
index 5769fa4..5d2e918 100644
--- a/src/crypto/evp/CMakeLists.txt
+++ b/src/crypto/evp/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   evp
@@ -6,15 +6,13 @@
   OBJECT
 
   algorithm.c
-  asn1.c
   digestsign.c
   evp.c
+  evp_asn1.c
   evp_ctx.c
   p_dsa_asn1.c
   p_ec.c
   p_ec_asn1.c
-  p_hmac.c
-  p_hmac_asn1.c
   p_rsa.c
   p_rsa_asn1.c
   pbkdf.c
diff --git a/src/crypto/evp/algorithm.c b/src/crypto/evp/algorithm.c
index ea28dfa..63bc77a 100644
--- a/src/crypto/evp/algorithm.c
+++ b/src/crypto/evp/algorithm.c
@@ -74,8 +74,7 @@
   digest = EVP_MD_CTX_md(ctx);
   pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
   if (!digest || !pkey) {
-    OPENSSL_PUT_ERROR(EVP, EVP_DigestSignAlgorithm,
-                      EVP_R_CONTEXT_NOT_INITIALISED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_CONTEXT_NOT_INITIALISED);
     return 0;
   }
 
@@ -97,8 +96,7 @@
    * that. */
   if (!OBJ_find_sigid_by_algs(&sign_nid, EVP_MD_type(digest),
                               pkey->ameth->pkey_id)) {
-    OPENSSL_PUT_ERROR(EVP, EVP_DigestSignAlgorithm,
-                      EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
     return 0;
   }
 
@@ -122,24 +120,21 @@
   /* Convert signature OID into digest and public key OIDs */
   if (!OBJ_find_sigid_algs(OBJ_obj2nid(algor->algorithm), &digest_nid,
                            &pkey_nid)) {
-    OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
-                      EVP_R_UNKNOWN_SIGNATURE_ALGORITHM);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM);
     return 0;
   }
 
   /* Check public key OID matches public key type */
   ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
   if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id) {
-    OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
-                      EVP_R_WRONG_PUBLIC_KEY_TYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_WRONG_PUBLIC_KEY_TYPE);
     return 0;
   }
 
   /* NID_undef signals that there are custom parameters to set. */
   if (digest_nid == NID_undef) {
     if (!pkey->ameth || !pkey->ameth->digest_verify_init_from_algorithm) {
-      OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
-                        EVP_R_UNKNOWN_SIGNATURE_ALGORITHM);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM);
       return 0;
     }
 
@@ -149,8 +144,7 @@
   /* Otherwise, initialize with the digest from the OID. */
   digest = EVP_get_digestbynid(digest_nid);
   if (digest == NULL) {
-    OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
-                      EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
     return 0;
   }
 
diff --git a/src/crypto/evp/digestsign.c b/src/crypto/evp/digestsign.c
index c163d40..ccb4de4 100644
--- a/src/crypto/evp/digestsign.c
+++ b/src/crypto/evp/digestsign.c
@@ -62,17 +62,9 @@
 #include "../digest/internal.h"
 
 
-/* md_begin_digset is a callback from the |EVP_MD_CTX| code that is called when
- * a new digest is begun. */
-static int md_begin_digest(EVP_MD_CTX *ctx) {
-  return EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
-                           EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
-}
-
 static const struct evp_md_pctx_ops md_pctx_ops = {
   EVP_PKEY_CTX_free,
   EVP_PKEY_CTX_dup,
-  md_begin_digest,
 };
 
 static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
@@ -91,26 +83,16 @@
   }
 
   if (type == NULL) {
-    OPENSSL_PUT_ERROR(EVP, do_sigver_init, EVP_R_NO_DEFAULT_DIGEST);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_DEFAULT_DIGEST);
     return 0;
   }
 
   if (is_verify) {
-    if (ctx->pctx->pmeth->verifyctx_init) {
-      if (!ctx->pctx->pmeth->verifyctx_init(ctx->pctx, ctx)) {
-        return 0;
-      }
-      ctx->pctx->operation = EVP_PKEY_OP_VERIFYCTX;
-    } else if (!EVP_PKEY_verify_init(ctx->pctx)) {
+    if (!EVP_PKEY_verify_init(ctx->pctx)) {
       return 0;
     }
   } else {
-    if (ctx->pctx->pmeth->signctx_init) {
-      if (!ctx->pctx->pmeth->signctx_init(ctx->pctx, ctx)) {
-        return 0;
-      }
-      ctx->pctx->operation = EVP_PKEY_OP_SIGNCTX;
-    } else if (!EVP_PKEY_sign_init(ctx->pctx)) {
+    if (!EVP_PKEY_sign_init(ctx->pctx)) {
       return 0;
     }
   }
@@ -146,59 +128,37 @@
 
 int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig,
                         size_t *out_sig_len) {
-  int r = 0;
-  const int has_signctx = ctx->pctx->pmeth->signctx != NULL;
-
   if (out_sig) {
     EVP_MD_CTX tmp_ctx;
+    int ret;
     uint8_t md[EVP_MAX_MD_SIZE];
     unsigned int mdlen;
 
     EVP_MD_CTX_init(&tmp_ctx);
-    if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) {
-      return 0;
-    }
-    if (has_signctx) {
-      r = tmp_ctx.pctx->pmeth->signctx(tmp_ctx.pctx, out_sig, out_sig_len, &tmp_ctx);
-    } else {
-      r = EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen);
-      if (r) {
-        r = EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen);
-      }
-    }
+    ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) &&
+          EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) &&
+          EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen);
     EVP_MD_CTX_cleanup(&tmp_ctx);
-    return r;
+
+    return ret;
   } else {
-    if (has_signctx) {
-      return ctx->pctx->pmeth->signctx(ctx->pctx, out_sig, out_sig_len, ctx);
-    } else {
-      size_t s = EVP_MD_size(ctx->digest);
-      return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s);
-    }
+    size_t s = EVP_MD_size(ctx->digest);
+    return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s);
   }
 }
 
 int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
                           size_t sig_len) {
   EVP_MD_CTX tmp_ctx;
+  int ret;
   uint8_t md[EVP_MAX_MD_SIZE];
-  int r;
   unsigned int mdlen;
 
   EVP_MD_CTX_init(&tmp_ctx);
-  if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) {
-    return 0;
-  }
-  if (ctx->pctx->pmeth->verifyctx) {
-    r = tmp_ctx.pctx->pmeth->verifyctx(tmp_ctx.pctx, sig, sig_len, &tmp_ctx);
-  } else {
-    r = EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen);
-    if (r) {
-      r = EVP_PKEY_verify(ctx->pctx, sig, sig_len, md, mdlen);
-    }
-  }
-
+  ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) &&
+        EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) &&
+        EVP_PKEY_verify(ctx->pctx, sig, sig_len, md, mdlen);
   EVP_MD_CTX_cleanup(&tmp_ctx);
 
-  return r;
+  return ret;
 }
diff --git a/src/crypto/evp/evp.c b/src/crypto/evp/evp.c
index 0ad5c27..5822379 100644
--- a/src/crypto/evp/evp.c
+++ b/src/crypto/evp/evp.c
@@ -75,7 +75,6 @@
 
 extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD ec_asn1_meth;
-extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meth;
 
 EVP_PKEY *EVP_PKEY_new(void) {
@@ -83,7 +82,7 @@
 
   ret = OPENSSL_malloc(sizeof(EVP_PKEY));
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -159,12 +158,12 @@
 
 int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
   if (to->type != from->type) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_copy_parameters, EVP_R_DIFFERENT_KEY_TYPES);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
     goto err;
   }
 
   if (EVP_PKEY_missing_parameters(from)) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_copy_parameters, EVP_R_MISSING_PARAMETERS);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
     goto err;
   }
 
@@ -207,8 +206,6 @@
     case EVP_PKEY_RSA:
     case EVP_PKEY_RSA2:
       return &rsa_asn1_meth;
-    case EVP_PKEY_HMAC:
-      return &hmac_asn1_meth;
     case EVP_PKEY_EC:
       return &ec_asn1_meth;
     case EVP_PKEY_DSA:
@@ -226,32 +223,6 @@
   return meth->pkey_id;
 }
 
-EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e, const uint8_t *mac_key,
-                               size_t mac_key_len) {
-  EVP_PKEY_CTX *mac_ctx = NULL;
-  EVP_PKEY *ret = NULL;
-
-  mac_ctx = EVP_PKEY_CTX_new_id(type, e);
-  if (!mac_ctx) {
-    return NULL;
-  }
-
-  if (!EVP_PKEY_keygen_init(mac_ctx) ||
-      !EVP_PKEY_CTX_ctrl(mac_ctx, -1, EVP_PKEY_OP_KEYGEN,
-                         EVP_PKEY_CTRL_SET_MAC_KEY, mac_key_len,
-                         (uint8_t *)mac_key) ||
-      !EVP_PKEY_keygen(mac_ctx, &ret)) {
-    ret = NULL;
-    goto merr;
-  }
-
-merr:
-  if (mac_ctx) {
-    EVP_PKEY_CTX_free(mac_ctx);
-  }
-  return ret;
-}
-
 int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key) {
   if (EVP_PKEY_assign_RSA(pkey, key)) {
     RSA_up_ref(key);
@@ -266,7 +237,7 @@
 
 RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey) {
   if (pkey->type != EVP_PKEY_RSA) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_get1_RSA, EVP_R_EXPECTING_AN_RSA_KEY);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_RSA_KEY);
     return NULL;
   }
   RSA_up_ref(pkey->pkey.rsa);
@@ -287,7 +258,7 @@
 
 DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey) {
   if (pkey->type != EVP_PKEY_DSA) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_get1_DSA, EVP_R_EXPECTING_A_DSA_KEY);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DSA_KEY);
     return NULL;
   }
   DSA_up_ref(pkey->pkey.dsa);
@@ -308,7 +279,7 @@
 
 EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey) {
   if (pkey->type != EVP_PKEY_EC) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_get1_EC_KEY, EVP_R_EXPECTING_AN_EC_KEY_KEY);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_EC_KEY_KEY);
     return NULL;
   }
   EC_KEY_up_ref(pkey->pkey.ec);
@@ -329,7 +300,7 @@
 
 DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey) {
   if (pkey->type != EVP_PKEY_DH) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_get1_DH, EVP_R_EXPECTING_A_DH_KEY);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DH_KEY);
     return NULL;
   }
   DH_up_ref(pkey->pkey.dh);
@@ -349,10 +320,10 @@
                                                    size_t len) {
   if (len == 3 && memcmp(name, "RSA", 3) == 0) {
     return &rsa_asn1_meth;
-  } else if (len == 4 && memcmp(name, "HMAC", 4) == 0) {
-    return &hmac_asn1_meth;
   } if (len == 2 && memcmp(name, "EC", 2) == 0) {
     return &ec_asn1_meth;
+  } else if (len == 3 && memcmp(name, "DSA", 3) == 0) {
+    return &dsa_asn1_meth;
   }
   return NULL;
 }
@@ -366,7 +337,7 @@
 
   ameth = EVP_PKEY_asn1_find(NULL, type);
   if (ameth == NULL) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_set_type, EVP_R_UNSUPPORTED_ALGORITHM);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
     ERR_add_error_dataf("algorithm %d (%s)", type, OBJ_nid2sn(type));
     return 0;
   }
@@ -436,10 +407,6 @@
                            0, (void *)out_md);
 }
 
-EVP_PKEY *EVP_PKEY_dup(EVP_PKEY *pkey) {
-  return EVP_PKEY_up_ref(pkey);
-}
-
 void OpenSSL_add_all_algorithms(void) {}
 
 void OpenSSL_add_all_ciphers(void) {}
diff --git a/src/crypto/evp/asn1.c b/src/crypto/evp/evp_asn1.c
similarity index 93%
rename from src/crypto/evp/asn1.c
rename to src/crypto/evp/evp_asn1.c
index 3df9f52..356c62b 100644
--- a/src/crypto/evp/asn1.c
+++ b/src/crypto/evp/evp_asn1.c
@@ -71,7 +71,7 @@
   if (out == NULL || *out == NULL) {
     ret = EVP_PKEY_new();
     if (ret == NULL) {
-      OPENSSL_PUT_ERROR(EVP, d2i_PrivateKey, ERR_R_EVP_LIB);
+      OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
       return NULL;
     }
   } else {
@@ -79,7 +79,7 @@
   }
 
   if (!EVP_PKEY_set_type(ret, type)) {
-    OPENSSL_PUT_ERROR(EVP, d2i_PrivateKey, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE);
     goto err;
   }
 
@@ -94,7 +94,7 @@
       ret = EVP_PKCS82PKEY(p8);
       PKCS8_PRIV_KEY_INFO_free(p8);
     } else {
-      OPENSSL_PUT_ERROR(EVP, d2i_PrivateKey, ERR_R_ASN1_LIB);
+      OPENSSL_PUT_ERROR(EVP, ERR_R_ASN1_LIB);
       goto err;
     }
   }
@@ -134,8 +134,7 @@
 
     sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
     if (!p8) {
-      OPENSSL_PUT_ERROR(EVP, d2i_AutoPrivateKey,
-                        EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
       return NULL;
     }
     ret = EVP_PKCS82PKEY(p8);
@@ -161,7 +160,7 @@
     case EVP_PKEY_EC:
       return i2o_ECPublicKey(key->pkey.ec, outp);
     default:
-      OPENSSL_PUT_ERROR(EVP, i2d_PublicKey, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
       return -1;
   }
 }
diff --git a/src/crypto/evp/evp_ctx.c b/src/crypto/evp/evp_ctx.c
index 9f42274..a8e71fe 100644
--- a/src/crypto/evp/evp_ctx.c
+++ b/src/crypto/evp/evp_ctx.c
@@ -67,12 +67,10 @@
 
 
 extern const EVP_PKEY_METHOD rsa_pkey_meth;
-extern const EVP_PKEY_METHOD hmac_pkey_meth;
 extern const EVP_PKEY_METHOD ec_pkey_meth;
 
 static const EVP_PKEY_METHOD *const evp_methods[] = {
   &rsa_pkey_meth,
-  &hmac_pkey_meth,
   &ec_pkey_meth,
 };
 
@@ -102,7 +100,7 @@
   pmeth = evp_pkey_meth_find(id);
 
   if (pmeth == NULL) {
-    OPENSSL_PUT_ERROR(EVP, evp_pkey_ctx_new, EVP_R_UNSUPPORTED_ALGORITHM);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
     const char *name = OBJ_nid2sn(id);
     ERR_add_error_dataf("algorithm %d (%s)", id, name);
     return NULL;
@@ -110,7 +108,7 @@
 
   ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX));
   if (!ret) {
-    OPENSSL_PUT_ERROR(EVP, evp_pkey_ctx_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
   memset(ret, 0, sizeof(EVP_PKEY_CTX));
@@ -192,7 +190,7 @@
 
 err:
   EVP_PKEY_CTX_free(rctx);
-  OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_dup, ERR_LIB_EVP);
+  OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP);
   return NULL;
 }
 
@@ -207,7 +205,7 @@
 int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd,
                       int p1, void *p2) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_COMMAND_NOT_SUPPORTED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
     return 0;
   }
   if (keytype != -1 && ctx->pmeth->pkey_id != keytype) {
@@ -215,12 +213,12 @@
   }
 
   if (ctx->operation == EVP_PKEY_OP_UNDEFINED) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_NO_OPERATION_SET);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_OPERATION_SET);
     return 0;
   }
 
   if (optype != -1 && !(ctx->operation & optype)) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_INVALID_OPERATION);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
     return 0;
   }
 
@@ -229,8 +227,7 @@
 
 int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign_init,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
 
@@ -250,12 +247,11 @@
 int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len,
                   const uint8_t *data, size_t data_len) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   if (ctx->operation != EVP_PKEY_OP_SIGN) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign, EVP_R_OPERATON_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
     return 0;
   }
   return ctx->pmeth->sign(ctx, sig, sig_len, data, data_len);
@@ -263,8 +259,7 @@
 
 int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_verify_init,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   ctx->operation = EVP_PKEY_OP_VERIFY;
@@ -282,12 +277,11 @@
 int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t sig_len,
                     const uint8_t *data, size_t data_len) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_verify,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   if (ctx->operation != EVP_PKEY_OP_VERIFY) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_verify, EVP_R_OPERATON_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
     return 0;
   }
   return ctx->pmeth->verify(ctx, sig, sig_len, data, data_len);
@@ -295,8 +289,7 @@
 
 int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt_init,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   ctx->operation = EVP_PKEY_OP_ENCRYPT;
@@ -313,12 +306,11 @@
 int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
                      const uint8_t *in, size_t inlen) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   if (ctx->operation != EVP_PKEY_OP_ENCRYPT) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt, EVP_R_OPERATON_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
     return 0;
   }
   return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen);
@@ -326,8 +318,7 @@
 
 int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt_init,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   ctx->operation = EVP_PKEY_OP_DECRYPT;
@@ -344,12 +335,11 @@
 int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
                      const uint8_t *in, size_t inlen) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   if (ctx->operation != EVP_PKEY_OP_DECRYPT) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt, EVP_R_OPERATON_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
     return 0;
   }
   return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen);
@@ -357,8 +347,7 @@
 
 int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_init,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   ctx->operation = EVP_PKEY_OP_DERIVE;
@@ -377,15 +366,13 @@
   if (!ctx || !ctx->pmeth ||
       !(ctx->pmeth->derive || ctx->pmeth->encrypt || ctx->pmeth->decrypt) ||
       !ctx->pmeth->ctrl) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   if (ctx->operation != EVP_PKEY_OP_DERIVE &&
       ctx->operation != EVP_PKEY_OP_ENCRYPT &&
       ctx->operation != EVP_PKEY_OP_DECRYPT) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer,
-                      EVP_R_OPERATON_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
     return 0;
   }
 
@@ -400,12 +387,12 @@
   }
 
   if (!ctx->pkey) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer, EVP_R_NO_KEY_SET);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
     return 0;
   }
 
   if (ctx->pkey->type != peer->type) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer, EVP_R_DIFFERENT_KEY_TYPES);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
     return 0;
   }
 
@@ -416,8 +403,7 @@
    * -2 is OK for us here, as well as 1, so we can check for 0 only. */
   if (!EVP_PKEY_missing_parameters(peer) &&
       !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer,
-                      EVP_R_DIFFERENT_PARAMETERS);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_PARAMETERS);
     return 0;
   }
 
@@ -437,12 +423,11 @@
 
 int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *out_key_len) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   if (ctx->operation != EVP_PKEY_OP_DERIVE) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive, EVP_R_OPERATON_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
     return 0;
   }
   return ctx->pmeth->derive(ctx, key, out_key_len);
@@ -450,8 +435,7 @@
 
 int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen_init,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   ctx->operation = EVP_PKEY_OP_KEYGEN;
@@ -467,12 +451,11 @@
 
 int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen,
-                      EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return 0;
   }
   if (ctx->operation != EVP_PKEY_OP_KEYGEN) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen, EVP_R_OPERATON_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
     return 0;
   }
 
@@ -483,7 +466,7 @@
   if (!*ppkey) {
     *ppkey = EVP_PKEY_new();
     if (!*ppkey) {
-      OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen, ERR_LIB_EVP);
+      OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP);
       return 0;
     }
   }
diff --git a/src/crypto/evp/evp_extra_test.cc b/src/crypto/evp/evp_extra_test.cc
index 674547d..9c955fa 100644
--- a/src/crypto/evp/evp_extra_test.cc
+++ b/src/crypto/evp/evp_extra_test.cc
@@ -322,8 +322,8 @@
 };
 
 static ScopedEVP_PKEY LoadExampleRSAKey() {
-  const uint8_t *derp = kExampleRSAKeyDER;
-  ScopedRSA rsa(d2i_RSAPrivateKey(nullptr, &derp, sizeof(kExampleRSAKeyDER)));
+  ScopedRSA rsa(RSA_private_key_from_bytes(kExampleRSAKeyDER,
+                                           sizeof(kExampleRSAKeyDER)));
   if (!rsa) {
     return nullptr;
   }
diff --git a/src/crypto/evp/evp_test.cc b/src/crypto/evp/evp_test.cc
index 239f868..c7ac908 100644
--- a/src/crypto/evp/evp_test.cc
+++ b/src/crypto/evp/evp_test.cc
@@ -56,10 +56,19 @@
 #include <stdlib.h>
 #include <string.h>
 
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable: 4702)
+#endif
+
 #include <map>
 #include <string>
 #include <vector>
 
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
 #include <openssl/bio.h>
 #include <openssl/crypto.h>
 #include <openssl/digest.h>
@@ -72,11 +81,10 @@
 #include "../test/stl_compat.h"
 
 
-// evp_test dispatches between multiple test types. HMAC tests test the legacy
-// EVP_PKEY_HMAC API. PrivateKey tests take a key name parameter and single
-// block, decode it as a PEM private key, and save it under that key name.
-// Decrypt, Sign, and Verify tests take a previously imported key name as
-// parameter and test their respective operations.
+// evp_test dispatches between multiple test types. PrivateKey tests take a key
+// name parameter and single block, decode it as a PEM private key, and save it
+// under that key name. Decrypt, Sign, and Verify tests take a previously
+// imported key name as parameter and test their respective operations.
 
 static const EVP_MD *GetDigest(FileTest *t, const std::string &name) {
   if (name == "MD5") {
@@ -120,54 +128,10 @@
   return true;
 }
 
-static bool TestHMAC(FileTest *t) {
-  std::string digest_str;
-  if (!t->GetAttribute(&digest_str, "HMAC")) {
-    return false;
-  }
-  const EVP_MD *digest = GetDigest(t, digest_str);
-  if (digest == nullptr) {
-    return false;
-  }
-
-  std::vector<uint8_t> key, input, output;
-  if (!t->GetBytes(&key, "Key") ||
-      !t->GetBytes(&input, "Input") ||
-      !t->GetBytes(&output, "Output")) {
-    return false;
-  }
-
-  ScopedEVP_PKEY pkey(EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr,
-                                           bssl::vector_data(&key),
-                                           key.size()));
-  ScopedEVP_MD_CTX mctx;
-  if (!pkey ||
-      !EVP_DigestSignInit(mctx.get(), nullptr, digest, nullptr, pkey.get()) ||
-      !EVP_DigestSignUpdate(mctx.get(), bssl::vector_data(&input),
-                            input.size())) {
-    return false;
-  }
-
-  size_t len;
-  std::vector<uint8_t> actual;
-  if (!EVP_DigestSignFinal(mctx.get(), nullptr, &len)) {
-    return false;
-  }
-  actual.resize(len);
-  if (!EVP_DigestSignFinal(mctx.get(), bssl::vector_data(&actual), &len)) {
-    return false;
-  }
-  actual.resize(len);
-  return t->ExpectBytesEqual(bssl::vector_data(&output), output.size(),
-                             bssl::vector_data(&actual), actual.size());
-}
-
 static bool TestEVP(FileTest *t, void *arg) {
   KeyMap *key_map = reinterpret_cast<KeyMap*>(arg);
   if (t->GetType() == "PrivateKey") {
     return ImportPrivateKey(t, key_map);
-  } else if (t->GetType() == "HMAC") {
-    return TestHMAC(t);
   }
 
   int (*key_op_init)(EVP_PKEY_CTX *ctx);
@@ -219,7 +183,7 @@
                          bssl::vector_data(&input), input.size())) {
       // ECDSA sometimes doesn't push an error code. Push one on the error queue
       // so it's distinguishable from other errors.
-      ERR_put_error(ERR_LIB_USER, 0, ERR_R_EVP_LIB, __FILE__, __LINE__);
+      OPENSSL_PUT_ERROR(USER, ERR_R_EVP_LIB);
       return false;
     }
     return true;
diff --git a/src/crypto/evp/evp_tests.txt b/src/crypto/evp/evp_tests.txt
index cccfa4f..97ddaa0 100644
--- a/src/crypto/evp/evp_tests.txt
+++ b/src/crypto/evp/evp_tests.txt
@@ -163,12 +163,11 @@
 Input = "0123456789ABCDEF1234"
 Output = 3045022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec800
 # This operation fails without an error code, so ERR_R_EVP_LIB is surfaced.
-Error = public key routines
+Error = BAD_SIGNATURE
 
 # BER signature
 Verify = P-256
 Digest = SHA1
 Input = "0123456789ABCDEF1234"
 Output = 3080022100b1d1cb1a577035bccdd5a86c6148c2cc7c633cd42b7234139b593076d041e15202201898cdd52b41ca502098184b409cf83a21bc945006746e3b7cea52234e043ec80000
-# This operation fails without an error code, so ERR_R_EVP_LIB is surfaced.
-Error = public key routines
+Error = BAD_SIGNATURE
diff --git a/src/crypto/evp/internal.h b/src/crypto/evp/internal.h
index 08a7bfb..60881e3 100644
--- a/src/crypto/evp/internal.h
+++ b/src/crypto/evp/internal.h
@@ -89,8 +89,7 @@
   int pkey_base_id;
   unsigned long pkey_flags;
 
-  char *pem_str;
-  char *info;
+  const char *pem_str;
 
   int (*pub_decode)(EVP_PKEY *pk, X509_PUBKEY *pub);
   int (*pub_encode)(X509_PUBKEY *pub, const EVP_PKEY *pk);
@@ -115,8 +114,8 @@
   int (*pkey_size)(const EVP_PKEY *pk);
   int (*pkey_bits)(const EVP_PKEY *pk);
 
-  int (*param_decode)(EVP_PKEY *pkey, const unsigned char **pder, int derlen);
-  int (*param_encode)(const EVP_PKEY *pkey, unsigned char **pder);
+  int (*param_decode)(EVP_PKEY *pkey, const uint8_t **pder, int derlen);
+  int (*param_encode)(const EVP_PKEY *pkey, uint8_t **pder);
   int (*param_missing)(const EVP_PKEY *pk);
   int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from);
   int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
@@ -130,9 +129,9 @@
 
   /* Legacy functions for old PEM */
 
-  int (*old_priv_decode)(EVP_PKEY *pkey, const unsigned char **pder,
+  int (*old_priv_decode)(EVP_PKEY *pkey, const uint8_t **pder,
                          int derlen);
-  int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
+  int (*old_priv_encode)(const EVP_PKEY *pkey, uint8_t **pder);
 
   /* Converting parameters to/from AlgorithmIdentifier (X509_ALGOR). */
   int (*digest_verify_init_from_algorithm)(EVP_MD_CTX *ctx,
@@ -153,15 +152,12 @@
 #define EVP_PKEY_OP_SIGN (1 << 3)
 #define EVP_PKEY_OP_VERIFY (1 << 4)
 #define EVP_PKEY_OP_VERIFYRECOVER (1 << 5)
-#define EVP_PKEY_OP_SIGNCTX (1 << 6)
-#define EVP_PKEY_OP_VERIFYCTX (1 << 7)
-#define EVP_PKEY_OP_ENCRYPT (1 << 8)
-#define EVP_PKEY_OP_DECRYPT (1 << 9)
-#define EVP_PKEY_OP_DERIVE (1 << 10)
+#define EVP_PKEY_OP_ENCRYPT (1 << 6)
+#define EVP_PKEY_OP_DECRYPT (1 << 7)
+#define EVP_PKEY_OP_DERIVE (1 << 8)
 
 #define EVP_PKEY_OP_TYPE_SIG                                           \
-  (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER | \
-   EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX)
+  (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER)
 
 #define EVP_PKEY_OP_TYPE_CRYPT (EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT)
 
@@ -181,13 +177,8 @@
 OPENSSL_EXPORT int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
                                      int cmd, int p1, void *p2);
 
-/* EVP_PKEY_CTRL_DIGESTINIT is an internal value. It's called by
- * EVP_DigestInit_ex to signal the |EVP_PKEY| that a digest operation is
- * starting.
- *
- * TODO(davidben): This is only needed to support the deprecated HMAC |EVP_PKEY|
- * types. */
-#define EVP_PKEY_CTRL_DIGESTINIT 3
+#define EVP_PKEY_CTRL_MD 1
+#define EVP_PKEY_CTRL_GET_MD 2
 
 /* EVP_PKEY_CTRL_PEER_KEY is called with different values of |p1|:
  *   0: Is called from |EVP_PKEY_derive_set_peer| and |p2| contains a peer key.
@@ -198,21 +189,12 @@
  *      (EC)DH always return one in this case.
  *   3: Is called with |p2| == NULL to set whether the peer's key was used.
  *      (EC)DH always return one in this case. This was only used for GOST. */
-#define EVP_PKEY_CTRL_PEER_KEY 4
-
-/* EVP_PKEY_CTRL_SET_MAC_KEY sets a MAC key. For example, this can be done an
- * |EVP_PKEY_CTX| prior to calling |EVP_PKEY_keygen| in order to generate an
- * HMAC |EVP_PKEY| with the given key. It returns one on success and zero on
- * error. */
-#define EVP_PKEY_CTRL_SET_MAC_KEY 5
+#define EVP_PKEY_CTRL_PEER_KEY 3
 
 /* EVP_PKEY_ALG_CTRL is the base value from which key-type specific ctrl
  * commands are numbered. */
 #define EVP_PKEY_ALG_CTRL 0x1000
 
-#define EVP_PKEY_CTRL_MD 1
-#define EVP_PKEY_CTRL_GET_MD 2
-
 #define EVP_PKEY_CTRL_RSA_PADDING (EVP_PKEY_ALG_CTRL + 1)
 #define EVP_PKEY_CTRL_GET_RSA_PADDING (EVP_PKEY_ALG_CTRL + 2)
 #define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 3)
@@ -260,34 +242,25 @@
   int (*keygen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
 
   int (*sign_init)(EVP_PKEY_CTX *ctx);
-  int (*sign)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
-              const unsigned char *tbs, size_t tbslen);
+  int (*sign)(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
+              const uint8_t *tbs, size_t tbslen);
 
   int (*verify_init)(EVP_PKEY_CTX *ctx);
-  int (*verify)(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen,
-                const unsigned char *tbs, size_t tbslen);
-
-  int (*signctx_init)(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
-  int (*signctx)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
-                 EVP_MD_CTX *mctx);
-
-  int (*verifyctx_init)(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
-  int (*verifyctx)(EVP_PKEY_CTX *ctx, const unsigned char *sig, int siglen,
-                   EVP_MD_CTX *mctx);
+  int (*verify)(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen,
+                const uint8_t *tbs, size_t tbslen);
 
   int (*encrypt_init)(EVP_PKEY_CTX *ctx);
-  int (*encrypt)(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
-                 const unsigned char *in, size_t inlen);
+  int (*encrypt)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
+                 const uint8_t *in, size_t inlen);
 
   int (*decrypt_init)(EVP_PKEY_CTX *ctx);
-  int (*decrypt)(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen,
-                 const unsigned char *in, size_t inlen);
+  int (*decrypt)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
+                 const uint8_t *in, size_t inlen);
 
   int (*derive_init)(EVP_PKEY_CTX *ctx);
-  int (*derive)(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
+  int (*derive)(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *keylen);
 
   int (*ctrl)(EVP_PKEY_CTX *ctx, int type, int p1, void *p2);
-  int (*ctrl_str)(EVP_PKEY_CTX *ctx, const char *type, const char *value);
 } /* EVP_PKEY_METHOD */;
 
 
diff --git a/src/crypto/evp/p_dsa_asn1.c b/src/crypto/evp/p_dsa_asn1.c
index 826d4e4..4790cf6 100644
--- a/src/crypto/evp/p_dsa_asn1.c
+++ b/src/crypto/evp/p_dsa_asn1.c
@@ -91,29 +91,29 @@
 
     dsa = d2i_DSAparams(NULL, &pm, pmlen);
     if (dsa == NULL) {
-      OPENSSL_PUT_ERROR(EVP, dsa_pub_decode, EVP_R_DECODE_ERROR);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
       goto err;
     }
   } else if (ptype == V_ASN1_NULL || ptype == V_ASN1_UNDEF) {
     dsa = DSA_new();
     if (dsa == NULL) {
-      OPENSSL_PUT_ERROR(EVP, dsa_pub_decode, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
       goto err;
     }
   } else {
-    OPENSSL_PUT_ERROR(EVP, dsa_pub_decode, EVP_R_PARAMETER_ENCODING_ERROR);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_PARAMETER_ENCODING_ERROR);
     goto err;
   }
 
   public_key = d2i_ASN1_INTEGER(NULL, &p, pklen);
   if (public_key == NULL) {
-    OPENSSL_PUT_ERROR(EVP, dsa_pub_decode, EVP_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     goto err;
   }
 
   dsa->pub_key = ASN1_INTEGER_to_BN(public_key, NULL);
   if (dsa->pub_key == NULL) {
-    OPENSSL_PUT_ERROR(EVP, dsa_pub_decode, EVP_R_BN_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_BN_DECODE_ERROR);
     goto err;
   }
 
@@ -140,12 +140,12 @@
   if (dsa->p && dsa->q && dsa->g) {
     pval = ASN1_STRING_new();
     if (!pval) {
-      OPENSSL_PUT_ERROR(EVP, dsa_pub_encode, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
       goto err;
     }
     pval->length = i2d_DSAparams(dsa, &pval->data);
     if (pval->length <= 0) {
-      OPENSSL_PUT_ERROR(EVP, dsa_pub_encode, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
       goto err;
     }
     ptype = V_ASN1_SEQUENCE;
@@ -155,7 +155,7 @@
 
   penclen = i2d_DSAPublicKey(dsa, &penc);
   if (penclen <= 0) {
-    OPENSSL_PUT_ERROR(EVP, dsa_pub_encode, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -252,23 +252,23 @@
   /* We have parameters. Now set private key */
   dsa->priv_key = ASN1_INTEGER_to_BN(privkey, NULL);
   if (dsa->priv_key == NULL) {
-    OPENSSL_PUT_ERROR(EVP, dsa_priv_decode, ERR_LIB_BN);
+    OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN);
     goto dsaerr;
   }
   /* Calculate public key. */
   dsa->pub_key = BN_new();
   if (dsa->pub_key == NULL) {
-    OPENSSL_PUT_ERROR(EVP, dsa_priv_decode, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     goto dsaerr;
   }
   ctx = BN_CTX_new();
   if (ctx == NULL) {
-    OPENSSL_PUT_ERROR(EVP, dsa_priv_decode, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     goto dsaerr;
   }
 
   if (!BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) {
-    OPENSSL_PUT_ERROR(EVP, dsa_priv_decode, ERR_LIB_BN);
+    OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN);
     goto dsaerr;
   }
 
@@ -280,7 +280,7 @@
   return 1;
 
 decerr:
-  OPENSSL_PUT_ERROR(EVP, dsa_priv_decode, EVP_R_DECODE_ERROR);
+  OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
 
 dsaerr:
   BN_CTX_free(ctx);
@@ -297,19 +297,19 @@
   int dplen;
 
   if (!pkey->pkey.dsa || !pkey->pkey.dsa->priv_key) {
-    OPENSSL_PUT_ERROR(EVP, dsa_priv_encode, EVP_R_MISSING_PARAMETERS);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
     goto err;
   }
 
   params = ASN1_STRING_new();
   if (!params) {
-    OPENSSL_PUT_ERROR(EVP, dsa_priv_encode, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
   params->length = i2d_DSAparams(pkey->pkey.dsa, &params->data);
   if (params->length <= 0) {
-    OPENSSL_PUT_ERROR(EVP, dsa_priv_encode, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     goto err;
   }
   params->type = V_ASN1_SEQUENCE;
@@ -318,13 +318,14 @@
   prkey = BN_to_ASN1_INTEGER(pkey->pkey.dsa->priv_key, NULL);
 
   if (!prkey) {
-    OPENSSL_PUT_ERROR(EVP, dsa_priv_encode, ERR_LIB_BN);
+    OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN);
     goto err;
   }
 
   dplen = i2d_ASN1_INTEGER(prkey, &dp);
 
   ASN1_INTEGER_free(prkey);
+  prkey = NULL;
 
   if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_dsa), 0,
                        V_ASN1_SEQUENCE, params, dp, dplen)) {
@@ -437,7 +438,7 @@
 
   m = (uint8_t *)OPENSSL_malloc(buf_len + 10);
   if (m == NULL) {
-    OPENSSL_PUT_ERROR(EVP, do_dsa_print, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -466,7 +467,7 @@
   DSA *dsa;
   dsa = d2i_DSAparams(NULL, pder, derlen);
   if (dsa == NULL) {
-    OPENSSL_PUT_ERROR(EVP, dsa_param_decode, ERR_R_DSA_LIB);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_DSA_LIB);
     return 0;
   }
   EVP_PKEY_assign_DSA(pkey, dsa);
@@ -497,7 +498,7 @@
   DSA *dsa;
   dsa = d2i_DSAPrivateKey(NULL, pder, derlen);
   if (dsa == NULL) {
-    OPENSSL_PUT_ERROR(EVP, old_dsa_priv_decode, ERR_R_DSA_LIB);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_DSA_LIB);
     return 0;
   }
   EVP_PKEY_assign_DSA(pkey, dsa);
@@ -531,7 +532,7 @@
   update_buflen(dsa_sig->s, &buf_len);
   m = OPENSSL_malloc(buf_len + 10);
   if (m == NULL) {
-    OPENSSL_PUT_ERROR(EVP, dsa_sig_print, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -554,7 +555,6 @@
   0,
 
   "DSA",
-  "OpenSSL DSA method",
 
   dsa_pub_decode,
   dsa_pub_encode,
diff --git a/src/crypto/evp/p_ec.c b/src/crypto/evp/p_ec.c
index 73c00d8..77f213d 100644
--- a/src/crypto/evp/p_ec.c
+++ b/src/crypto/evp/p_ec.c
@@ -125,25 +125,18 @@
 
 static int pkey_ec_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
                         const uint8_t *tbs, size_t tbslen) {
-  int type;
   unsigned int sltmp;
-  EC_PKEY_CTX *dctx = ctx->data;
   EC_KEY *ec = ctx->pkey->pkey.ec;
 
   if (!sig) {
     *siglen = ECDSA_size(ec);
     return 1;
   } else if (*siglen < (size_t)ECDSA_size(ec)) {
-    OPENSSL_PUT_ERROR(EVP, pkey_ec_sign, EVP_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
-  type = NID_sha1;
-  if (dctx->md) {
-    type = EVP_MD_type(dctx->md);
-  }
-
-  if (!ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec)) {
+  if (!ECDSA_sign(0, tbs, tbslen, sig, &sltmp, ec)) {
     return 0;
   }
   *siglen = (size_t)sltmp;
@@ -152,16 +145,7 @@
 
 static int pkey_ec_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen,
                           const uint8_t *tbs, size_t tbslen) {
-  int type;
-  EC_PKEY_CTX *dctx = ctx->data;
-  EC_KEY *ec = ctx->pkey->pkey.ec;
-
-  type = NID_sha1;
-  if (dctx->md) {
-    type = EVP_MD_type(dctx->md);
-  }
-
-  return ECDSA_verify(type, tbs, tbslen, sig, siglen, ec);
+  return ECDSA_verify(0, tbs, tbslen, sig, siglen, ctx->pkey->pkey.ec);
 }
 
 static int pkey_ec_derive(EVP_PKEY_CTX *ctx, uint8_t *key,
@@ -172,7 +156,7 @@
   EC_KEY *eckey;
 
   if (!ctx->pkey || !ctx->peerkey) {
-    OPENSSL_PUT_ERROR(EVP, pkey_ec_derive, EVP_R_KEYS_NOT_SET);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
     return 0;
   }
 
@@ -207,7 +191,7 @@
     case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID:
       group = EC_GROUP_new_by_curve_name(p1);
       if (group == NULL) {
-        OPENSSL_PUT_ERROR(EVP, pkey_ec_ctrl, EVP_R_INVALID_CURVE);
+        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_CURVE);
         return 0;
       }
       EC_GROUP_free(dctx->gen_group);
@@ -221,7 +205,7 @@
           EVP_MD_type((const EVP_MD *)p2) != NID_sha256 &&
           EVP_MD_type((const EVP_MD *)p2) != NID_sha384 &&
           EVP_MD_type((const EVP_MD *)p2) != NID_sha512) {
-        OPENSSL_PUT_ERROR(EVP, pkey_ec_ctrl, EVP_R_INVALID_DIGEST_TYPE);
+        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE);
         return 0;
       }
       dctx->md = p2;
@@ -232,12 +216,11 @@
       return 1;
 
     case EVP_PKEY_CTRL_PEER_KEY:
-    /* Default behaviour is OK */
-    case EVP_PKEY_CTRL_DIGESTINIT:
+      /* Default behaviour is OK */
       return 1;
 
     default:
-      OPENSSL_PUT_ERROR(EVP, pkey_ec_ctrl, EVP_R_COMMAND_NOT_SUPPORTED);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
       return 0;
   }
 }
@@ -248,7 +231,7 @@
   int ret = 0;
 
   if (dctx->gen_group == NULL) {
-    OPENSSL_PUT_ERROR(EVP, pkey_ec_paramgen, EVP_R_NO_PARAMETERS_SET);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
     return 0;
   }
   ec = EC_KEY_new();
@@ -268,7 +251,7 @@
   EC_KEY *ec = NULL;
   EC_PKEY_CTX *dctx = ctx->data;
   if (ctx->pkey == NULL && dctx->gen_group == NULL) {
-    OPENSSL_PUT_ERROR(EVP, pkey_ec_keygen, EVP_R_NO_PARAMETERS_SET);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET);
     return 0;
   }
   ec = EC_KEY_new();
@@ -290,12 +273,11 @@
 }
 
 const EVP_PKEY_METHOD ec_pkey_meth = {
-    EVP_PKEY_EC,            0 /* flags */,        pkey_ec_init,
-    pkey_ec_copy,           pkey_ec_cleanup,      0 /* paramgen_init */,
-    pkey_ec_paramgen,       0 /* keygen_init */,  pkey_ec_keygen,
-    0 /* sign_init */,      pkey_ec_sign,         0 /* verify_init */,
-    pkey_ec_verify,         0 /* signctx_init */, 0 /* signctx */,
-    0 /* verifyctx_init */, 0 /* verifyctx */,    0 /* encrypt_init */,
-    0 /* encrypt */,        0 /* decrypt_init */, 0 /* decrypt */,
-    0 /* derive_init */,    pkey_ec_derive,       pkey_ec_ctrl,
+    EVP_PKEY_EC,          0 /* flags */,        pkey_ec_init,
+    pkey_ec_copy,         pkey_ec_cleanup,      0 /* paramgen_init */,
+    pkey_ec_paramgen,     0 /* keygen_init */,  pkey_ec_keygen,
+    0 /* sign_init */,    pkey_ec_sign,         0 /* verify_init */,
+    pkey_ec_verify,       0 /* encrypt_init */, 0 /* encrypt */,
+    0 /* decrypt_init */, 0 /* decrypt */,      0 /* derive_init */,
+    pkey_ec_derive,       pkey_ec_ctrl,
 };
diff --git a/src/crypto/evp/p_ec_asn1.c b/src/crypto/evp/p_ec_asn1.c
index fbbf4e7..9867947 100644
--- a/src/crypto/evp/p_ec_asn1.c
+++ b/src/crypto/evp/p_ec_asn1.c
@@ -71,13 +71,13 @@
   int nid;
 
   if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL) {
-    OPENSSL_PUT_ERROR(EVP, eckey_param2type, EVP_R_MISSING_PARAMETERS);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
     return 0;
   }
 
   nid = EC_GROUP_get_curve_name(group);
   if (nid == NID_undef) {
-    OPENSSL_PUT_ERROR(EVP, eckey_param2type, EVP_R_NO_NID_FOR_CURVE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE);
     return 0;
   }
 
@@ -94,7 +94,7 @@
   int penclen;
 
   if (!eckey_param2type(&ptype, &pval, ec_key)) {
-    OPENSSL_PUT_ERROR(EVP, eckey_pub_encode, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
     return 0;
   }
   penclen = i2o_ECPublicKey(ec_key, NULL);
@@ -137,7 +137,7 @@
 
     eckey = d2i_ECParameters(NULL, &pm, pmlen);
     if (eckey == NULL) {
-      OPENSSL_PUT_ERROR(EVP, eckey_type2param, EVP_R_DECODE_ERROR);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
       goto err;
     }
   } else if (ptype == V_ASN1_OBJECT) {
@@ -150,7 +150,7 @@
       goto err;
     }
   } else {
-    OPENSSL_PUT_ERROR(EVP, eckey_type2param, EVP_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     goto err;
   }
 
@@ -177,13 +177,13 @@
 
   eckey = eckey_type2param(ptype, pval);
   if (!eckey) {
-    OPENSSL_PUT_ERROR(EVP, eckey_pub_decode, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
     return 0;
   }
 
   /* We have parameters now set public key */
   if (!o2i_ECPublicKey(&eckey, &p, pklen)) {
-    OPENSSL_PUT_ERROR(EVP, eckey_pub_decode, EVP_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     goto err;
   }
 
@@ -232,7 +232,7 @@
 
   /* We have parameters now set private key */
   if (!d2i_ECPrivateKey(&eckey, &p, pklen)) {
-    OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, EVP_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     goto ecerr;
   }
 
@@ -246,23 +246,23 @@
     group = EC_KEY_get0_group(eckey);
     pub_key = EC_POINT_new(group);
     if (pub_key == NULL) {
-      OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
       goto ecliberr;
     }
     if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) {
       EC_POINT_free(pub_key);
-      OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
       goto ecliberr;
     }
     priv_key = EC_KEY_get0_private_key(eckey);
     if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)) {
       EC_POINT_free(pub_key);
-      OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
       goto ecliberr;
     }
     if (EC_KEY_set_public_key(eckey, pub_key) == 0) {
       EC_POINT_free(pub_key);
-      OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+      OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
       goto ecliberr;
     }
     EC_POINT_free(pub_key);
@@ -272,7 +272,7 @@
   return 1;
 
 ecliberr:
-  OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+  OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
 ecerr:
   if (eckey) {
     EC_KEY_free(eckey);
@@ -290,7 +290,7 @@
   ec_key = pkey->pkey.ec;
 
   if (!eckey_param2type(&ptype, &pval, ec_key)) {
-    OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, EVP_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     return 0;
   }
 
@@ -304,20 +304,20 @@
   eplen = i2d_ECPrivateKey(ec_key, NULL);
   if (!eplen) {
     EC_KEY_set_enc_flags(ec_key, old_flags);
-    OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
     return 0;
   }
   ep = (uint8_t *)OPENSSL_malloc(eplen);
   if (!ep) {
     EC_KEY_set_enc_flags(ec_key, old_flags);
-    OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     return 0;
   }
   p = ep;
   if (!i2d_ECPrivateKey(ec_key, &p)) {
     EC_KEY_set_enc_flags(ec_key, old_flags);
     OPENSSL_free(ep);
-    OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
     return 0;
   }
   /* restore old encoding flags */
@@ -325,6 +325,7 @@
 
   if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_X9_62_id_ecPublicKey),
                        0, ptype, pval, ep, eplen)) {
+    OPENSSL_free(ep);
     return 0;
   }
 
@@ -478,7 +479,7 @@
 
 err:
   if (!ret) {
-    OPENSSL_PUT_ERROR(EVP, do_EC_KEY_print, reason);
+    OPENSSL_PUT_ERROR(EVP, reason);
   }
   OPENSSL_free(pub_key_bytes);
   BN_free(order);
@@ -491,7 +492,7 @@
                               int derlen) {
   EC_KEY *eckey;
   if (!(eckey = d2i_ECParameters(NULL, pder, derlen))) {
-    OPENSSL_PUT_ERROR(EVP, eckey_param_decode, ERR_R_EC_LIB);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
     return 0;
   }
   EVP_PKEY_assign_EC_KEY(pkey, eckey);
@@ -526,7 +527,7 @@
                               int derlen) {
   EC_KEY *ec;
   if (!(ec = d2i_ECPrivateKey(NULL, pder, derlen))) {
-    OPENSSL_PUT_ERROR(EVP, old_ec_priv_decode, EVP_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     return 0;
   }
   EVP_PKEY_assign_EC_KEY(pkey, ec);
@@ -542,7 +543,6 @@
   EVP_PKEY_EC,
   0,
   "EC",
-  "OpenSSL EC algorithm",
 
   eckey_pub_decode,
   eckey_pub_encode,
diff --git a/src/crypto/evp/p_hmac.c b/src/crypto/evp/p_hmac.c
deleted file mode 100644
index 7d3254a..0000000
--- a/src/crypto/evp/p_hmac.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 2007.
- */
-/* ====================================================================
- * Copyright (c) 2007 The OpenSSL Project.  All rights reserved.
- *
- * 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 above 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 acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED 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 OpenSSL PROJECT OR
- * ITS 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.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com). */
-
-#include <openssl/evp.h>
-
-#include <string.h>
-
-#include <openssl/asn1.h>
-#include <openssl/err.h>
-#include <openssl/hmac.h>
-#include <openssl/mem.h>
-#include <openssl/obj.h>
-
-#include "internal.h"
-#include "../digest/internal.h"
-
-
-typedef struct {
-  const EVP_MD *md;       /* MD for HMAC use */
-  ASN1_OCTET_STRING ktmp; /* Temp storage for key */
-  HMAC_CTX ctx;
-} HMAC_PKEY_CTX;
-
-static int pkey_hmac_init(EVP_PKEY_CTX *ctx) {
-  HMAC_PKEY_CTX *hctx;
-  hctx = OPENSSL_malloc(sizeof(HMAC_PKEY_CTX));
-  if (!hctx) {
-    return 0;
-  }
-  memset(hctx, 0, sizeof(HMAC_PKEY_CTX));
-  hctx->ktmp.type = V_ASN1_OCTET_STRING;
-  HMAC_CTX_init(&hctx->ctx);
-
-  ctx->data = hctx;
-
-  return 1;
-}
-
-static int pkey_hmac_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
-  HMAC_PKEY_CTX *sctx, *dctx;
-  if (!pkey_hmac_init(dst)) {
-    return 0;
-  }
-  sctx = src->data;
-  dctx = dst->data;
-  dctx->md = sctx->md;
-  HMAC_CTX_init(&dctx->ctx);
-  if (!HMAC_CTX_copy_ex(&dctx->ctx, &sctx->ctx)) {
-    return 0;
-  }
-  if (sctx->ktmp.data) {
-    if (!ASN1_OCTET_STRING_set(&dctx->ktmp, sctx->ktmp.data,
-                               sctx->ktmp.length)) {
-      return 0;
-    }
-  }
-  return 1;
-}
-
-static void pkey_hmac_cleanup(EVP_PKEY_CTX *ctx) {
-  HMAC_PKEY_CTX *hctx = ctx->data;
-
-  if (hctx == NULL) {
-    return;
-  }
-
-  HMAC_CTX_cleanup(&hctx->ctx);
-  if (hctx->ktmp.data) {
-    if (hctx->ktmp.length) {
-      OPENSSL_cleanse(hctx->ktmp.data, hctx->ktmp.length);
-    }
-    OPENSSL_free(hctx->ktmp.data);
-    hctx->ktmp.data = NULL;
-  }
-  OPENSSL_free(hctx);
-}
-
-static int pkey_hmac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
-  ASN1_OCTET_STRING *hkey = NULL;
-  HMAC_PKEY_CTX *hctx = ctx->data;
-
-  if (!hctx->ktmp.data) {
-    return 0;
-  }
-  hkey = ASN1_OCTET_STRING_dup(&hctx->ktmp);
-  if (!hkey) {
-    return 0;
-  }
-  EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, hkey);
-
-  return 1;
-}
-
-static void int_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
-  HMAC_PKEY_CTX *hctx = ctx->pctx->data;
-  HMAC_Update(&hctx->ctx, data, count);
-}
-
-static int hmac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) {
-  /* |mctx| gets repurposed as a hook to call |HMAC_Update|. Suppress the
-   * automatic setting of |mctx->update| and the rest of its initialization. */
-  EVP_MD_CTX_set_flags(mctx, EVP_MD_CTX_FLAG_NO_INIT);
-  mctx->update = int_update;
-  return 1;
-}
-
-static int hmac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
-                        EVP_MD_CTX *mctx) {
-  unsigned int hlen;
-  HMAC_PKEY_CTX *hctx = ctx->data;
-  size_t md_size = EVP_MD_CTX_size(mctx);
-
-  if (!sig) {
-    *siglen = md_size;
-    return 1;
-  } else if (*siglen < md_size) {
-    OPENSSL_PUT_ERROR(EVP, hmac_signctx, EVP_R_BUFFER_TOO_SMALL);
-    return 0;
-  }
-
-  if (!HMAC_Final(&hctx->ctx, sig, &hlen)) {
-    return 0;
-  }
-  *siglen = (size_t)hlen;
-  return 1;
-}
-
-static int pkey_hmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
-  HMAC_PKEY_CTX *hctx = ctx->data;
-  ASN1_OCTET_STRING *key;
-
-  switch (type) {
-    case EVP_PKEY_CTRL_SET_MAC_KEY:
-      if ((!p2 && p1 > 0) || (p1 < -1)) {
-        return 0;
-      }
-      if (!ASN1_OCTET_STRING_set(&hctx->ktmp, p2, p1)) {
-        return 0;
-      }
-      break;
-
-    case EVP_PKEY_CTRL_MD:
-      hctx->md = p2;
-      break;
-
-    case EVP_PKEY_CTRL_DIGESTINIT:
-      key = (ASN1_OCTET_STRING *)ctx->pkey->pkey.ptr;
-      if (!HMAC_Init_ex(&hctx->ctx, key->data, key->length, hctx->md,
-                        ctx->engine)) {
-        return 0;
-      }
-      break;
-
-    default:
-      OPENSSL_PUT_ERROR(EVP, pkey_hmac_ctrl, EVP_R_COMMAND_NOT_SUPPORTED);
-      return 0;
-  }
-  return 1;
-}
-
-const EVP_PKEY_METHOD hmac_pkey_meth = {
-    EVP_PKEY_HMAC,          0 /* flags */,        pkey_hmac_init,
-    pkey_hmac_copy,         pkey_hmac_cleanup,    0 /* paramgen_init */,
-    0 /* paramgen */,       0 /* keygen_init */,  pkey_hmac_keygen,
-    0 /* sign_init */,      0 /* sign */,         0 /* verify_init */,
-    0 /* verify */,         hmac_signctx_init,    hmac_signctx,
-    0 /* verifyctx_init */, 0 /* verifyctx */,    0 /* encrypt_init */,
-    0 /* encrypt */,        0 /* decrypt_init */, 0 /* decrypt */,
-    0 /* derive_init */,    0 /* derive */,       pkey_hmac_ctrl,
-    0,
-};
diff --git a/src/crypto/evp/p_hmac_asn1.c b/src/crypto/evp/p_hmac_asn1.c
deleted file mode 100644
index 8aa6676..0000000
--- a/src/crypto/evp/p_hmac_asn1.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 2007.
- */
-/* ====================================================================
- * Copyright (c) 2007 The OpenSSL Project.  All rights reserved.
- *
- * 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 above 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 acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED 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 OpenSSL PROJECT OR
- * ITS 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.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com). */
-
-#include <openssl/evp.h>
-
-#include <openssl/asn1.h>
-#include <openssl/digest.h>
-#include <openssl/mem.h>
-#include <openssl/obj.h>
-
-#include "internal.h"
-
-
-static int hmac_size(const EVP_PKEY *pkey) { return EVP_MAX_MD_SIZE; }
-
-static void hmac_key_free(EVP_PKEY *pkey) {
-  ASN1_OCTET_STRING *os = (ASN1_OCTET_STRING *)pkey->pkey.ptr;
-  if (os) {
-    if (os->data) {
-      OPENSSL_cleanse(os->data, os->length);
-    }
-    ASN1_OCTET_STRING_free(os);
-  }
-}
-
-const EVP_PKEY_ASN1_METHOD hmac_asn1_meth = {
-    EVP_PKEY_HMAC,       EVP_PKEY_HMAC,         0 /* flags */,
-    "HMAC",              "OpenSSL HMAC method", 0 /* pub_decode */,
-    0 /* pub_encode */,  0 /* pub_cmp */,       0 /* pub_print */,
-    0 /*priv_decode */,  0 /* priv_encode */,   0 /* priv_print */,
-    0 /* pkey_opaque */, 0 /* pkey_supports_digest */,
-    hmac_size,           0 /* pkey_bits */,     0 /* param_decode */,
-    0 /* param_encode*/, 0 /* param_missing*/,  0 /* param_copy*/,
-    0 /* param_cmp*/,    0 /* param_print*/,    0 /* sig_print*/,
-    hmac_key_free,       0 /* old_priv_decode */,
-    0 /* old_priv_encode */
-};
diff --git a/src/crypto/evp/p_rsa.c b/src/crypto/evp/p_rsa.c
index 5abc075..cfecbfd 100644
--- a/src/crypto/evp/p_rsa.c
+++ b/src/crypto/evp/p_rsa.c
@@ -174,7 +174,7 @@
   }
 
   if (*siglen < key_len) {
-    OPENSSL_PUT_ERROR(EVP, pkey_rsa_sign, EVP_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
@@ -182,12 +182,12 @@
     unsigned int out_len;
 
     if (tbslen != EVP_MD_size(rctx->md)) {
-      OPENSSL_PUT_ERROR(EVP, pkey_rsa_sign, EVP_R_INVALID_DIGEST_LENGTH);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_LENGTH);
       return 0;
     }
 
     if (EVP_MD_type(rctx->md) == NID_mdc2) {
-      OPENSSL_PUT_ERROR(EVP, pkey_rsa_sign, EVP_R_NO_MDC2_SUPPORT);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_NO_MDC2_SUPPORT);
       return 0;
     }
 
@@ -268,7 +268,7 @@
   }
 
   if (*outlen < key_len) {
-    OPENSSL_PUT_ERROR(EVP, pkey_rsa_encrypt, EVP_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
@@ -300,7 +300,7 @@
   }
 
   if (*outlen < key_len) {
-    OPENSSL_PUT_ERROR(EVP, pkey_rsa_decrypt, EVP_R_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
     return 0;
   }
 
@@ -333,7 +333,7 @@
   }
 
   if (padding == RSA_NO_PADDING) {
-    OPENSSL_PUT_ERROR(EVP, check_padding_md, EVP_R_INVALID_PADDING_MODE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
     return 0;
   }
 
@@ -361,8 +361,7 @@
            0 == (ctx->operation & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY))) ||
           (p1 == RSA_PKCS1_OAEP_PADDING &&
            0 == (ctx->operation & EVP_PKEY_OP_TYPE_CRYPT))) {
-        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl,
-                          EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
+        OPENSSL_PUT_ERROR(EVP, EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE);
         return 0;
       }
       if ((p1 == RSA_PKCS1_PSS_PADDING || p1 == RSA_PKCS1_OAEP_PADDING) &&
@@ -379,7 +378,7 @@
     case EVP_PKEY_CTRL_RSA_PSS_SALTLEN:
     case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN:
       if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING) {
-        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_PSS_SALTLEN);
+        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_SALTLEN);
         return 0;
       }
       if (type == EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN) {
@@ -394,7 +393,7 @@
 
     case EVP_PKEY_CTRL_RSA_KEYGEN_BITS:
       if (p1 < 256) {
-        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_KEYBITS);
+        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_KEYBITS);
         return 0;
       }
       rctx->nbits = p1;
@@ -411,7 +410,7 @@
     case EVP_PKEY_CTRL_RSA_OAEP_MD:
     case EVP_PKEY_CTRL_GET_RSA_OAEP_MD:
       if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
-        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_PADDING_MODE);
+        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
         return 0;
       }
       if (type == EVP_PKEY_CTRL_GET_RSA_OAEP_MD) {
@@ -436,7 +435,7 @@
     case EVP_PKEY_CTRL_GET_RSA_MGF1_MD:
       if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING &&
           rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
-        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_MGF1_MD);
+        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_MGF1_MD);
         return 0;
       }
       if (type == EVP_PKEY_CTRL_GET_RSA_MGF1_MD) {
@@ -452,7 +451,7 @@
 
     case EVP_PKEY_CTRL_RSA_OAEP_LABEL:
       if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
-        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_PADDING_MODE);
+        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
         return 0;
       }
       OPENSSL_free(rctx->oaep_label);
@@ -469,17 +468,14 @@
 
     case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL:
       if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
-        OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_PADDING_MODE);
+        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
         return 0;
       }
       CBS_init((CBS *)p2, rctx->oaep_label, rctx->oaep_labellen);
       return 1;
 
-    case EVP_PKEY_CTRL_DIGESTINIT:
-      return 1;
-
     default:
-      OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_COMMAND_NOT_SUPPORTED);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
       return 0;
   }
 }
@@ -509,14 +505,13 @@
 }
 
 const EVP_PKEY_METHOD rsa_pkey_meth = {
-    EVP_PKEY_RSA,           0 /* flags */,        pkey_rsa_init,
-    pkey_rsa_copy,          pkey_rsa_cleanup,     0 /* paramgen_init */,
-    0 /* paramgen */,       0 /* keygen_init */,  pkey_rsa_keygen,
-    0 /* sign_init */,      pkey_rsa_sign,        0 /* verify_init */,
-    pkey_rsa_verify,        0 /* signctx_init */, 0 /* signctx */,
-    0 /* verifyctx_init */, 0 /* verifyctx */,    0 /* encrypt_init */,
-    pkey_rsa_encrypt,       0 /* decrypt_init */, pkey_rsa_decrypt,
-    0 /* derive_init */,    0 /* derive */,       pkey_rsa_ctrl,
+    EVP_PKEY_RSA,         0 /* flags */,        pkey_rsa_init,
+    pkey_rsa_copy,        pkey_rsa_cleanup,     0 /* paramgen_init */,
+    0 /* paramgen */,     0 /* keygen_init */,  pkey_rsa_keygen,
+    0 /* sign_init */,    pkey_rsa_sign,        0 /* verify_init */,
+    pkey_rsa_verify,      0 /* encrypt_init */, pkey_rsa_encrypt,
+    0 /* decrypt_init */, pkey_rsa_decrypt,     0 /* derive_init */,
+    0 /* derive */,       pkey_rsa_ctrl,
 };
 
 int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding) {
@@ -593,7 +588,7 @@
     return -1;
   }
   if (CBS_len(&label) > INT_MAX) {
-    OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_get0_rsa_oaep_label, ERR_R_OVERFLOW);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW);
     return -1;
   }
   *out_label = CBS_data(&label);
diff --git a/src/crypto/evp/p_rsa_asn1.c b/src/crypto/evp/p_rsa_asn1.c
index 1e2d3f6..f60625b 100644
--- a/src/crypto/evp/p_rsa_asn1.c
+++ b/src/crypto/evp/p_rsa_asn1.c
@@ -57,6 +57,7 @@
 
 #include <openssl/asn1.h>
 #include <openssl/asn1t.h>
+#include <openssl/bytestring.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
@@ -69,16 +70,14 @@
 
 
 static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) {
-  uint8_t *encoded = NULL;
-  int len;
-  len = i2d_RSAPublicKey(pkey->pkey.rsa, &encoded);
-
-  if (len <= 0) {
+  uint8_t *encoded;
+  size_t encoded_len;
+  if (!RSA_public_key_to_bytes(&encoded, &encoded_len, pkey->pkey.rsa)) {
     return 0;
   }
 
   if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA), V_ASN1_NULL, NULL,
-                              encoded, len)) {
+                              encoded, encoded_len)) {
     OPENSSL_free(encoded);
     return 0;
   }
@@ -89,16 +88,25 @@
 static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) {
   const uint8_t *p;
   int pklen;
-  RSA *rsa;
-
   if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, pubkey)) {
     return 0;
   }
-  rsa = d2i_RSAPublicKey(NULL, &p, pklen);
-  if (rsa == NULL) {
-    OPENSSL_PUT_ERROR(EVP, rsa_pub_decode, ERR_R_RSA_LIB);
+
+  /* Estonian IDs issued between September 2014 to September 2015 are
+   * broken. See https://crbug.com/532048 and https://crbug.com/534766.
+   *
+   * TODO(davidben): Switch this to the strict version in March 2016 or when
+   * Chromium can force client certificates down a different codepath, whichever
+   * comes first. */
+  CBS cbs;
+  CBS_init(&cbs, p, pklen);
+  RSA *rsa = RSA_parse_public_key_buggy(&cbs);
+  if (rsa == NULL || CBS_len(&cbs) != 0) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    RSA_free(rsa);
     return 0;
   }
+
   EVP_PKEY_assign_RSA(pkey, rsa);
   return 1;
 }
@@ -109,20 +117,17 @@
 }
 
 static int rsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) {
-  uint8_t *rk = NULL;
-  int rklen;
-
-  rklen = i2d_RSAPrivateKey(pkey->pkey.rsa, &rk);
-
-  if (rklen <= 0) {
-    OPENSSL_PUT_ERROR(EVP, rsa_priv_encode, ERR_R_MALLOC_FAILURE);
+  uint8_t *encoded;
+  size_t encoded_len;
+  if (!RSA_private_key_to_bytes(&encoded, &encoded_len, pkey->pkey.rsa)) {
     return 0;
   }
 
   /* TODO(fork): const correctness in next line. */
   if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_rsaEncryption), 0,
-                       V_ASN1_NULL, NULL, rk, rklen)) {
-    OPENSSL_PUT_ERROR(EVP, rsa_priv_encode, ERR_R_MALLOC_FAILURE);
+                       V_ASN1_NULL, NULL, encoded, encoded_len)) {
+    OPENSSL_free(encoded);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -132,16 +137,14 @@
 static int rsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) {
   const uint8_t *p;
   int pklen;
-  RSA *rsa;
-
   if (!PKCS8_pkey_get0(NULL, &p, &pklen, NULL, p8)) {
-    OPENSSL_PUT_ERROR(EVP, rsa_priv_decode, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
-  rsa = d2i_RSAPrivateKey(NULL, &p, pklen);
+  RSA *rsa = RSA_private_key_from_bytes(p, pklen);
   if (rsa == NULL) {
-    OPENSSL_PUT_ERROR(EVP, rsa_priv_decode, ERR_R_RSA_LIB);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB);
     return 0;
   }
 
@@ -198,11 +201,24 @@
     update_buflen(rsa->dmp1, &buf_len);
     update_buflen(rsa->dmq1, &buf_len);
     update_buflen(rsa->iqmp, &buf_len);
+
+    if (rsa->additional_primes != NULL) {
+      size_t i;
+
+      for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes);
+           i++) {
+        const RSA_additional_prime *ap =
+            sk_RSA_additional_prime_value(rsa->additional_primes, i);
+        update_buflen(ap->prime, &buf_len);
+        update_buflen(ap->exp, &buf_len);
+        update_buflen(ap->coeff, &buf_len);
+      }
+    }
   }
 
   m = (uint8_t *)OPENSSL_malloc(buf_len + 10);
   if (m == NULL) {
-    OPENSSL_PUT_ERROR(EVP, do_rsa_print, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -241,6 +257,28 @@
         !ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) {
       goto err;
     }
+
+    if (rsa->additional_primes != NULL &&
+        sk_RSA_additional_prime_num(rsa->additional_primes) > 0) {
+      size_t i;
+
+      if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) {
+        goto err;
+      }
+      for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes);
+           i++) {
+        const RSA_additional_prime *ap =
+            sk_RSA_additional_prime_value(rsa->additional_primes, i);
+
+        if (BIO_printf(out, "otherPrimeInfo (prime %u):\n",
+                       (unsigned)(i + 3)) <= 0 ||
+            !ASN1_bn_print(out, "prime:", ap->prime, m, off) ||
+            !ASN1_bn_print(out, "exponent:", ap->exp, m, off) ||
+            !ASN1_bn_print(out, "coeff:", ap->coeff, m, off)) {
+          goto err;
+        }
+      }
+    }
   }
   ret = 1;
 
@@ -407,18 +445,18 @@
   return 1;
 }
 
-static int old_rsa_priv_decode(EVP_PKEY *pkey, const unsigned char **pder,
+static int old_rsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder,
                                int derlen) {
   RSA *rsa = d2i_RSAPrivateKey(NULL, pder, derlen);
   if (rsa == NULL) {
-    OPENSSL_PUT_ERROR(EVP, old_rsa_priv_decode, ERR_R_RSA_LIB);
+    OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB);
     return 0;
   }
   EVP_PKEY_assign_RSA(pkey, rsa);
   return 1;
 }
 
-static int old_rsa_priv_encode(const EVP_PKEY *pkey, unsigned char **pder) {
+static int old_rsa_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) {
   return i2d_RSAPrivateKey(pkey->pkey.rsa, pder);
 }
 
@@ -474,7 +512,7 @@
   }
   md = EVP_get_digestbyobj(alg->algorithm);
   if (md == NULL) {
-    OPENSSL_PUT_ERROR(EVP, rsa_algor_to_md, EVP_R_UNKNOWN_DIGEST);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_DIGEST);
   }
   return md;
 }
@@ -487,16 +525,16 @@
   }
   /* Check mask and lookup mask hash algorithm */
   if (OBJ_obj2nid(alg->algorithm) != NID_mgf1) {
-    OPENSSL_PUT_ERROR(EVP, rsa_mgf1_to_md, EVP_R_UNSUPPORTED_MASK_ALGORITHM);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_ALGORITHM);
     return NULL;
   }
   if (!maskHash) {
-    OPENSSL_PUT_ERROR(EVP, rsa_mgf1_to_md, EVP_R_UNSUPPORTED_MASK_PARAMETER);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_PARAMETER);
     return NULL;
   }
   md = EVP_get_digestbyobj(maskHash->algorithm);
   if (md == NULL) {
-    OPENSSL_PUT_ERROR(EVP, rsa_mgf1_to_md, EVP_R_UNKNOWN_MASK_DIGEST);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MASK_DIGEST);
     return NULL;
   }
   return md;
@@ -576,13 +614,13 @@
 
   /* Sanity check: make sure it is PSS */
   if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
-    OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
     return 0;
   }
   /* Decode PSS parameters */
   pss = rsa_pss_decode(sigalg, &maskHash);
   if (pss == NULL) {
-    OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_INVALID_PSS_PARAMETERS);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_PARAMETERS);
     goto err;
   }
 
@@ -602,7 +640,7 @@
     /* Could perform more salt length sanity checks but the main
      * RSA routines will trap other invalid values anyway. */
     if (saltlen < 0) {
-      OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_INVALID_SALT_LENGTH);
+      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SALT_LENGTH);
       goto err;
     }
   }
@@ -610,7 +648,7 @@
   /* low-level routines support only trailer field 0xbc (value 1)
    * and PKCS#1 says we should reject any other value anyway. */
   if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1) {
-    OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_INVALID_TRAILER);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_TRAILER);
     goto err;
   }
 
@@ -638,8 +676,7 @@
                                                  EVP_PKEY *pkey) {
   /* Sanity check: make sure it is PSS */
   if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
-    OPENSSL_PUT_ERROR(EVP, rsa_digest_verify_init_from_algorithm,
-                      EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
     return 0;
   }
   return rsa_pss_to_ctx(ctx, sigalg, pkey);
@@ -671,7 +708,6 @@
   ASN1_PKEY_SIGPARAM_NULL,
 
   "RSA",
-  "OpenSSL RSA method",
 
   rsa_pub_decode,
   rsa_pub_encode,
diff --git a/src/crypto/ex_data.c b/src/crypto/ex_data.c
index 10fefc8..f562f17 100644
--- a/src/crypto/ex_data.c
+++ b/src/crypto/ex_data.c
@@ -138,7 +138,7 @@
 
   funcs = OPENSSL_malloc(sizeof(CRYPTO_EX_DATA_FUNCS));
   if (funcs == NULL) {
-    OPENSSL_PUT_ERROR(CRYPTO, CRYPTO_get_ex_new_index, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -156,12 +156,13 @@
 
   if (ex_data_class->meth == NULL ||
       !sk_CRYPTO_EX_DATA_FUNCS_push(ex_data_class->meth, funcs)) {
-    OPENSSL_PUT_ERROR(CRYPTO, CRYPTO_get_ex_new_index, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE);
     OPENSSL_free(funcs);
     goto err;
   }
 
-  *out_index = sk_CRYPTO_EX_DATA_FUNCS_num(ex_data_class->meth) - 1;
+  *out_index = sk_CRYPTO_EX_DATA_FUNCS_num(ex_data_class->meth) - 1 +
+               ex_data_class->num_reserved;
   ret = 1;
 
 err:
@@ -175,7 +176,7 @@
   if (ad->sk == NULL) {
     ad->sk = sk_void_new_null();
     if (ad->sk == NULL) {
-      OPENSSL_PUT_ERROR(CRYPTO, CRYPTO_set_ex_data, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE);
       return 0;
     }
   }
@@ -185,7 +186,7 @@
   /* Add NULL values until the stack is long enough. */
   for (i = n; i <= index; i++) {
     if (!sk_void_push(ad->sk, NULL)) {
-      OPENSSL_PUT_ERROR(CRYPTO, CRYPTO_set_ex_data, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE);
       return 0;
     }
   }
@@ -222,7 +223,7 @@
   CRYPTO_STATIC_MUTEX_unlock(&ex_data_class->lock);
 
   if (n > 0 && *out == NULL) {
-    OPENSSL_PUT_ERROR(CRYPTO, get_func_pointers, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -244,8 +245,8 @@
     CRYPTO_EX_DATA_FUNCS *func_pointer =
         sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i);
     if (func_pointer->new_func) {
-      func_pointer->new_func(obj, NULL, ad, i, func_pointer->argl,
-                             func_pointer->argp);
+      func_pointer->new_func(obj, NULL, ad, i + ex_data_class->num_reserved,
+                             func_pointer->argl, func_pointer->argp);
     }
   }
 
@@ -272,12 +273,12 @@
   for (i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) {
     CRYPTO_EX_DATA_FUNCS *func_pointer =
         sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i);
-    void *ptr = CRYPTO_get_ex_data(from, i);
+    void *ptr = CRYPTO_get_ex_data(from, i + ex_data_class->num_reserved);
     if (func_pointer->dup_func) {
-      func_pointer->dup_func(to, from, &ptr, i, func_pointer->argl,
-                             func_pointer->argp);
+      func_pointer->dup_func(to, from, &ptr, i + ex_data_class->num_reserved,
+                             func_pointer->argl, func_pointer->argp);
     }
-    CRYPTO_set_ex_data(to, i, ptr);
+    CRYPTO_set_ex_data(to, i + ex_data_class->num_reserved, ptr);
   }
 
   sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers);
@@ -298,9 +299,9 @@
     CRYPTO_EX_DATA_FUNCS *func_pointer =
         sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i);
     if (func_pointer->free_func) {
-      void *ptr = CRYPTO_get_ex_data(ad, i);
-      func_pointer->free_func(obj, ptr, ad, i, func_pointer->argl,
-                              func_pointer->argp);
+      void *ptr = CRYPTO_get_ex_data(ad, i + ex_data_class->num_reserved);
+      func_pointer->free_func(obj, ptr, ad, i + ex_data_class->num_reserved,
+                              func_pointer->argl, func_pointer->argp);
     }
   }
 
diff --git a/src/crypto/hkdf/CMakeLists.txt b/src/crypto/hkdf/CMakeLists.txt
index 66d680a..53bf558 100644
--- a/src/crypto/hkdf/CMakeLists.txt
+++ b/src/crypto/hkdf/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   hkdf
diff --git a/src/crypto/hkdf/hkdf.c b/src/crypto/hkdf/hkdf.c
index bb7f5a4..f9cdcb0 100644
--- a/src/crypto/hkdf/hkdf.c
+++ b/src/crypto/hkdf/hkdf.c
@@ -40,7 +40,7 @@
   /* Expand key material to desired length. */
   n = (out_len + digest_len - 1) / digest_len;
   if (out_len + digest_len < out_len || n > 255) {
-    OPENSSL_PUT_ERROR(HKDF, HKDF, HKDF_R_OUTPUT_TOO_LARGE);
+    OPENSSL_PUT_ERROR(HKDF, HKDF_R_OUTPUT_TOO_LARGE);
     return 0;
   }
 
@@ -83,7 +83,7 @@
 out:
   HMAC_CTX_cleanup(&hmac);
   if (ret != 1) {
-    OPENSSL_PUT_ERROR(HKDF, HKDF, ERR_R_HMAC_LIB);
+    OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB);
   }
   return ret;
 }
diff --git a/src/crypto/hmac/CMakeLists.txt b/src/crypto/hmac/CMakeLists.txt
index 11d267f..392ce01 100644
--- a/src/crypto/hmac/CMakeLists.txt
+++ b/src/crypto/hmac/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   hmac
diff --git a/src/crypto/hmac/hmac.c b/src/crypto/hmac/hmac.c
index 556e7f9..d37a249 100644
--- a/src/crypto/hmac/hmac.c
+++ b/src/crypto/hmac/hmac.c
@@ -97,7 +97,7 @@
   EVP_MD_CTX_cleanup(&ctx->i_ctx);
   EVP_MD_CTX_cleanup(&ctx->o_ctx);
   EVP_MD_CTX_cleanup(&ctx->md_ctx);
-  OPENSSL_cleanse(ctx, sizeof(ctx));
+  OPENSSL_cleanse(ctx, sizeof(HMAC_CTX));
 }
 
 int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
diff --git a/src/crypto/hmac/hmac_tests.txt b/src/crypto/hmac/hmac_tests.txt
index 012f593..53f3f8f 100644
--- a/src/crypto/hmac/hmac_tests.txt
+++ b/src/crypto/hmac/hmac_tests.txt
@@ -1,6 +1,3 @@
-# This test file is shared between evp_test and hmac_test, to test the legacy
-# EVP_PKEY_HMAC API.
-
 HMAC = MD5
 # Note: The empty key results in passing NULL to HMAC_Init_ex, so this tests
 # that HMAC_CTX and HMAC treat NULL as the empty key initially.
diff --git a/src/crypto/internal.h b/src/crypto/internal.h
index 59eddd0..713659d 100644
--- a/src/crypto/internal.h
+++ b/src/crypto/internal.h
@@ -452,6 +452,7 @@
 typedef enum {
   OPENSSL_THREAD_LOCAL_ERR = 0,
   OPENSSL_THREAD_LOCAL_RAND,
+  OPENSSL_THREAD_LOCAL_URANDOM_BUF,
   OPENSSL_THREAD_LOCAL_TEST,
   NUM_OPENSSL_THREAD_LOCALS,
 } thread_local_data_t;
@@ -493,9 +494,14 @@
 typedef struct {
   struct CRYPTO_STATIC_MUTEX lock;
   STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth;
+  /* num_reserved is one if the ex_data index zero is reserved for legacy
+   * |TYPE_get_app_data| functions. */
+  uint8_t num_reserved;
 } CRYPTO_EX_DATA_CLASS;
 
-#define CRYPTO_EX_DATA_CLASS_INIT {CRYPTO_STATIC_MUTEX_INIT, NULL}
+#define CRYPTO_EX_DATA_CLASS_INIT {CRYPTO_STATIC_MUTEX_INIT, NULL, 0}
+#define CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA \
+    {CRYPTO_STATIC_MUTEX_INIT, NULL, 1}
 
 /* CRYPTO_get_ex_new_index allocates a new index for |ex_data_class| and writes
  * it to |*out_index|. Each class of object should provide a wrapper function
diff --git a/src/crypto/lhash/CMakeLists.txt b/src/crypto/lhash/CMakeLists.txt
index c71b8a1..ce785eb 100644
--- a/src/crypto/lhash/CMakeLists.txt
+++ b/src/crypto/lhash/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   lhash
diff --git a/src/crypto/lhash/lhash.c b/src/crypto/lhash/lhash.c
index c282fa8..257900e 100644
--- a/src/crypto/lhash/lhash.c
+++ b/src/crypto/lhash/lhash.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved.
+/* 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).
diff --git a/src/crypto/md4/CMakeLists.txt b/src/crypto/md4/CMakeLists.txt
index db7a187..59140a7 100644
--- a/src/crypto/md4/CMakeLists.txt
+++ b/src/crypto/md4/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   md4
diff --git a/src/crypto/md5/CMakeLists.txt b/src/crypto/md5/CMakeLists.txt
index 6c5e80f..a37c47e 100644
--- a/src/crypto/md5/CMakeLists.txt
+++ b/src/crypto/md5/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 if (${ARCH} STREQUAL "x86_64")
   set(
diff --git a/src/crypto/md5/md5.c b/src/crypto/md5/md5.c
index 5575efb..6ad8d12 100644
--- a/src/crypto/md5/md5.c
+++ b/src/crypto/md5/md5.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved.
+/* 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).
diff --git a/src/crypto/mem.c b/src/crypto/mem.c
index ce41440..edd14a8 100644
--- a/src/crypto/mem.c
+++ b/src/crypto/mem.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved.
+/* 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).
diff --git a/src/crypto/modes/CMakeLists.txt b/src/crypto/modes/CMakeLists.txt
index ffb29b6..6da5207 100644
--- a/src/crypto/modes/CMakeLists.txt
+++ b/src/crypto/modes/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 if (${ARCH} STREQUAL "x86_64")
   set(
diff --git a/src/crypto/modes/asm/ghash-armv4.pl b/src/crypto/modes/asm/ghash-armv4.pl
index 25a4e27..dc5b99e 100644
--- a/src/crypto/modes/asm/ghash-armv4.pl
+++ b/src/crypto/modes/asm/ghash-armv4.pl
@@ -45,7 +45,7 @@
 # processes one byte in 8.45 cycles, A9 - in 10.2, A15 - in 7.63,
 # Snapdragon S4 - in 9.33.
 #
-# Câmara, D.; Gouvêa, C. P. L.; López, J. & Dahab, R.: Fast Software
+# Câmara, D.; Gouvêa, C. P. L.; López, J. & Dahab, R.: Fast Software
 # Polynomial Multiplication on ARM Processors using the NEON Engine.
 # 
 # http://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf
@@ -134,7 +134,7 @@
 
 $code=<<___;
 #if defined(__arm__)
-#include "arm_arch.h"
+#include <openssl/arm_arch.h>
 
 .syntax unified
 
@@ -457,12 +457,12 @@
 	veor		$IN,$Xl			@ inp^=Xi
 .Lgmult_neon:
 ___
-	&clmul64x64	($Xl,$Hlo,"$IN#lo");	# H.lo·Xi.lo
+	&clmul64x64	($Xl,$Hlo,"$IN#lo");	# H.lo·Xi.lo
 $code.=<<___;
 	veor		$IN#lo,$IN#lo,$IN#hi	@ Karatsuba pre-processing
 ___
-	&clmul64x64	($Xm,$Hhl,"$IN#lo");	# (H.lo+H.hi)·(Xi.lo+Xi.hi)
-	&clmul64x64	($Xh,$Hhi,"$IN#hi");	# H.hi·Xi.hi
+	&clmul64x64	($Xm,$Hhl,"$IN#lo");	# (H.lo+H.hi)·(Xi.lo+Xi.hi)
+	&clmul64x64	($Xh,$Hhi,"$IN#hi");	# H.hi·Xi.hi
 $code.=<<___;
 	veor		$Xm,$Xm,$Xl		@ Karatsuba post-processing
 	veor		$Xm,$Xm,$Xh
diff --git a/src/crypto/modes/asm/ghash-x86.pl b/src/crypto/modes/asm/ghash-x86.pl
index 23a5527..0269169 100644
--- a/src/crypto/modes/asm/ghash-x86.pl
+++ b/src/crypto/modes/asm/ghash-x86.pl
@@ -358,7 +358,7 @@
 # effective address calculation and finally merge of value to Z.hi.
 # Reference to rem_4bit is scheduled so late that I had to >>4
 # rem_4bit elements. This resulted in 20-45% procent improvement
-# on contemporary µ-archs.
+# on contemporary µ-archs.
 {
     my $cnt;
     my $rem_4bit = "eax";
diff --git a/src/crypto/modes/asm/ghash-x86_64.pl b/src/crypto/modes/asm/ghash-x86_64.pl
index 6e656ca..5a7ce39 100644
--- a/src/crypto/modes/asm/ghash-x86_64.pl
+++ b/src/crypto/modes/asm/ghash-x86_64.pl
@@ -576,15 +576,15 @@
 	# experimental alternative. special thing about is that there
 	# no dependency between the two multiplications... 
 	mov		\$`0xE1<<1`,%eax
-	mov		\$0xA040608020C0E000,%r10	# ((7..0)·0xE0)&0xff
+	mov		\$0xA040608020C0E000,%r10	# ((7..0)·0xE0)&0xff
 	mov		\$0x07,%r11d
 	movq		%rax,$T1
 	movq		%r10,$T2
 	movq		%r11,$T3		# borrow $T3
 	pand		$Xi,$T3
-	pshufb		$T3,$T2			# ($Xi&7)·0xE0
+	pshufb		$T3,$T2			# ($Xi&7)·0xE0
 	movq		%rax,$T3
-	pclmulqdq	\$0x00,$Xi,$T1		# ·(0xE1<<1)
+	pclmulqdq	\$0x00,$Xi,$T1		# ·(0xE1<<1)
 	pxor		$Xi,$T2
 	pslldq		\$15,$T2
 	paddd		$T2,$T2			# <<(64+56+1)
@@ -657,7 +657,7 @@
 	je		.Lskip4x
 
 	sub		\$0x30,$len
-	mov		\$0xA040608020C0E000,%rax	# ((7..0)·0xE0)&0xff
+	mov		\$0xA040608020C0E000,%rax	# ((7..0)·0xE0)&0xff
 	movdqu		0x30($Htbl),$Hkey3
 	movdqu		0x40($Htbl),$Hkey4
 
diff --git a/src/crypto/modes/asm/ghashv8-armx.pl b/src/crypto/modes/asm/ghashv8-armx.pl
index 686951f..3a7b8d8 100644
--- a/src/crypto/modes/asm/ghashv8-armx.pl
+++ b/src/crypto/modes/asm/ghashv8-armx.pl
@@ -54,7 +54,7 @@
 my ($t0,$t1,$t2,$xC2,$H,$Hhl,$H2)=map("q$_",(8..14));
 
 $code=<<___;
-#include "arm_arch.h"
+#include <openssl/arm_arch.h>
 
 .text
 ___
@@ -148,10 +148,10 @@
 #endif
 	vext.8		$IN,$t1,$t1,#8
 
-	vpmull.p64	$Xl,$H,$IN		@ H.lo·Xi.lo
+	vpmull.p64	$Xl,$H,$IN		@ H.lo·Xi.lo
 	veor		$t1,$t1,$IN		@ Karatsuba pre-processing
-	vpmull2.p64	$Xh,$H,$IN		@ H.hi·Xi.hi
-	vpmull.p64	$Xm,$Hhl,$t1		@ (H.lo+H.hi)·(Xi.lo+Xi.hi)
+	vpmull2.p64	$Xh,$H,$IN		@ H.hi·Xi.hi
+	vpmull.p64	$Xm,$Hhl,$t1		@ (H.lo+H.hi)·(Xi.lo+Xi.hi)
 
 	vext.8		$t1,$Xl,$Xh,#8		@ Karatsuba post-processing
 	veor		$t2,$Xl,$Xh
@@ -239,7 +239,7 @@
 #endif
 	vext.8		$In,$t1,$t1,#8
 	veor		$IN,$IN,$Xl		@ I[i]^=Xi
-	vpmull.p64	$Xln,$H,$In		@ H·Ii+1
+	vpmull.p64	$Xln,$H,$In		@ H·Ii+1
 	veor		$t1,$t1,$In		@ Karatsuba pre-processing
 	vpmull2.p64	$Xhn,$H,$In
 	b		.Loop_mod2x_v8
@@ -248,14 +248,14 @@
 .Loop_mod2x_v8:
 	vext.8		$t2,$IN,$IN,#8
 	subs		$len,$len,#32		@ is there more data?
-	vpmull.p64	$Xl,$H2,$IN		@ H^2.lo·Xi.lo
+	vpmull.p64	$Xl,$H2,$IN		@ H^2.lo·Xi.lo
 	cclr		$inc,lo			@ is it time to zero $inc?
 
 	 vpmull.p64	$Xmn,$Hhl,$t1
 	veor		$t2,$t2,$IN		@ Karatsuba pre-processing
-	vpmull2.p64	$Xh,$H2,$IN		@ H^2.hi·Xi.hi
+	vpmull2.p64	$Xh,$H2,$IN		@ H^2.hi·Xi.hi
 	veor		$Xl,$Xl,$Xln		@ accumulate
-	vpmull2.p64	$Xm,$Hhl,$t2		@ (H^2.lo+H^2.hi)·(Xi.lo+Xi.hi)
+	vpmull2.p64	$Xm,$Hhl,$t2		@ (H^2.lo+H^2.hi)·(Xi.lo+Xi.hi)
 	 vld1.64	{$t0},[$inp],$inc	@ load [rotated] I[i+2]
 
 	veor		$Xh,$Xh,$Xhn
@@ -280,7 +280,7 @@
 	 vext.8		$In,$t1,$t1,#8
 	 vext.8		$IN,$t0,$t0,#8
 	veor		$Xl,$Xm,$t2
-	 vpmull.p64	$Xln,$H,$In		@ H·Ii+1
+	 vpmull.p64	$Xln,$H,$In		@ H·Ii+1
 	veor		$IN,$IN,$Xh		@ accumulate $IN early
 
 	vext.8		$t2,$Xl,$Xl,#8		@ 2nd phase of reduction
@@ -304,10 +304,10 @@
 	veor		$IN,$IN,$Xl		@ inp^=Xi
 	veor		$t1,$t0,$t2		@ $t1 is rotated inp^Xi
 
-	vpmull.p64	$Xl,$H,$IN		@ H.lo·Xi.lo
+	vpmull.p64	$Xl,$H,$IN		@ H.lo·Xi.lo
 	veor		$t1,$t1,$IN		@ Karatsuba pre-processing
-	vpmull2.p64	$Xh,$H,$IN		@ H.hi·Xi.hi
-	vpmull.p64	$Xm,$Hhl,$t1		@ (H.lo+H.hi)·(Xi.lo+Xi.hi)
+	vpmull2.p64	$Xh,$H,$IN		@ H.hi·Xi.hi
+	vpmull.p64	$Xm,$Hhl,$t1		@ (H.lo+H.hi)·(Xi.lo+Xi.hi)
 
 	vext.8		$t1,$Xl,$Xh,#8		@ Karatsuba post-processing
 	veor		$t2,$Xl,$Xh
diff --git a/src/crypto/modes/gcm.c b/src/crypto/modes/gcm.c
index b1c10b3..593dce8 100644
--- a/src/crypto/modes/gcm.c
+++ b/src/crypto/modes/gcm.c
@@ -349,12 +349,12 @@
                         size_t len);
 #endif
 #elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
-#include "../arm_arch.h"
+#include <openssl/arm_arch.h>
 #if __ARM_ARCH__ >= 7
 #define GHASH_ASM_ARM
 #define GCM_FUNCREF_4BIT
 
-static int pmull_capable() {
+static int pmull_capable(void) {
   return (OPENSSL_armcap_P & ARMV8_PMULL) != 0;
 }
 
@@ -365,7 +365,7 @@
 
 #if defined(OPENSSL_ARM)
 /* 32-bit ARM also has support for doing GCM with NEON instructions. */
-static int neon_capable() {
+static int neon_capable(void) {
   return CRYPTO_is_NEON_capable();
 }
 
@@ -375,7 +375,7 @@
                     size_t len);
 #else
 /* AArch64 only has the ARMv8 versions of functions. */
-static int neon_capable() {
+static int neon_capable(void) {
   return 0;
 }
 void gcm_init_neon(u128 Htable[16], const uint64_t Xi[2]) {
diff --git a/src/crypto/modes/gcm_test.c b/src/crypto/modes/gcm_test.c
index a8819ea..89ed792 100644
--- a/src/crypto/modes/gcm_test.c
+++ b/src/crypto/modes/gcm_test.c
@@ -55,6 +55,7 @@
 #include <openssl/modes.h>
 
 #include "internal.h"
+#include "../test/test_util.h"
 
 
 struct test_case {
@@ -298,17 +299,6 @@
   return 0;
 }
 
-void hexdump(const char *msg, const void *in, size_t len) {
-  const uint8_t *data = in;
-  size_t i;
-
-  fprintf(stderr, "%s: ", msg);
-  for (i = 0; i < len; i++) {
-    fprintf(stderr, "%02x", data[i]);
-  }
-  fprintf(stderr, "\n");
-}
-
 static int run_test_case(unsigned test_num, const struct test_case *test) {
   size_t key_len, plaintext_len, additional_data_len, nonce_len, ciphertext_len,
       tag_len;
@@ -367,8 +357,8 @@
   if (!CRYPTO_gcm128_finish(&ctx, tag, tag_len) ||
       (ciphertext && memcmp(out, ciphertext, plaintext_len) != 0)) {
     fprintf(stderr, "%u: encrypt failed.\n", test_num);
-    hexdump("got ", out, plaintext_len);
-    hexdump("want", ciphertext, plaintext_len);
+    hexdump(stderr, "got :", out, plaintext_len);
+    hexdump(stderr, "want:", ciphertext, plaintext_len);
     goto out;
   }
 
diff --git a/src/crypto/modes/internal.h b/src/crypto/modes/internal.h
index d12405e..caeac40 100644
--- a/src/crypto/modes/internal.h
+++ b/src/crypto/modes/internal.h
@@ -173,11 +173,6 @@
   void *key;
 };
 
-struct xts128_context {
-  void *key1, *key2;
-  block128_f block1, block2;
-};
-
 struct ccm128_context {
   union {
     uint64_t u[2];
diff --git a/src/crypto/obj/CMakeLists.txt b/src/crypto/obj/CMakeLists.txt
index a27e504..b8a4ef3 100644
--- a/src/crypto/obj/CMakeLists.txt
+++ b/src/crypto/obj/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   obj
diff --git a/src/crypto/obj/obj.c b/src/crypto/obj/obj.c
index bf16d17..94f739c 100644
--- a/src/crypto/obj/obj.c
+++ b/src/crypto/obj/obj.c
@@ -108,7 +108,7 @@
 
   r = ASN1_OBJECT_new();
   if (r == NULL) {
-    OPENSSL_PUT_ERROR(OBJ, OBJ_dup, ERR_R_ASN1_LIB);
+    OPENSSL_PUT_ERROR(OBJ, ERR_R_ASN1_LIB);
     return NULL;
   }
   r->ln = r->sn = NULL;
@@ -149,7 +149,7 @@
   return r;
 
 err:
-  OPENSSL_PUT_ERROR(OBJ, OBJ_dup, ERR_R_MALLOC_FAILURE);
+  OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE);
   OPENSSL_free(ln);
   OPENSSL_free(sn);
   OPENSSL_free(data);
@@ -337,7 +337,7 @@
   CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
 
 err:
-  OPENSSL_PUT_ERROR(OBJ, OBJ_nid2obj, OBJ_R_UNKNOWN_NID);
+  OPENSSL_PUT_ERROR(OBJ, OBJ_R_UNKNOWN_NID);
   return NULL;
 }
 
@@ -388,7 +388,7 @@
 
   buf = OPENSSL_malloc(total_len);
   if (buf == NULL) {
-    OPENSSL_PUT_ERROR(OBJ, OBJ_txt2obj, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -636,7 +636,7 @@
 
   buf = OPENSSL_malloc(len);
   if (buf == NULL) {
-    OPENSSL_PUT_ERROR(OBJ, OBJ_create, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
diff --git a/src/crypto/pem/CMakeLists.txt b/src/crypto/pem/CMakeLists.txt
index 720ba2f..30dd7c9 100644
--- a/src/crypto/pem/CMakeLists.txt
+++ b/src/crypto/pem/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   pem
diff --git a/src/crypto/pem/pem_info.c b/src/crypto/pem/pem_info.c
index 3f02619..b4ae805 100644
--- a/src/crypto/pem/pem_info.c
+++ b/src/crypto/pem/pem_info.c
@@ -80,7 +80,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_read, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,fp,BIO_NOCLOSE);
@@ -107,7 +107,7 @@
 		{
 		if ((ret=sk_X509_INFO_new_null()) == NULL)
 			{
-			OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_read_bio, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE);
 			goto err;
 			}
 		}
@@ -248,13 +248,13 @@
 					{
 					if (!d2i_PrivateKey(ptype, pp, &p, len))
 						{
-						OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_read_bio, ERR_R_ASN1_LIB);
+						OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
 						goto err;
 						}
 					}
 				else if (d2i(pp,&p,len) == NULL)
 					{
-					OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_read_bio, ERR_R_ASN1_LIB);
+					OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
 					goto err;
 					}
 				}
@@ -326,7 +326,7 @@
 		objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc));
 		if (objstr == NULL)
 			{
-			OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_write_bio, PEM_R_UNSUPPORTED_CIPHER);
+			OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER);
 			goto err;
 			}
 		}
@@ -342,7 +342,7 @@
 			{
 			if (enc == NULL)
 				{
-				OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_write_bio, PEM_R_CIPHER_IS_NULL);
+				OPENSSL_PUT_ERROR(PEM, PEM_R_CIPHER_IS_NULL);
 				goto err;
 				}
 
@@ -360,7 +360,7 @@
 				EVP_CIPHER_nid(xi->enc_cipher.cipher));
 			if (objstr == NULL)
 				{
-				OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_write_bio, PEM_R_UNSUPPORTED_CIPHER);
+				OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER);
 				goto err;
 				}
 
diff --git a/src/crypto/pem/pem_lib.c b/src/crypto/pem/pem_lib.c
index 5201467..5915696 100644
--- a/src/crypto/pem/pem_lib.c
+++ b/src/crypto/pem/pem_lib.c
@@ -128,7 +128,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_ASN1_read, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,fp,BIO_NOCLOSE);
@@ -275,7 +275,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,fp,BIO_NOCLOSE);
@@ -302,14 +302,14 @@
 		objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc));
 		if (objstr == NULL)
 			{
-			OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write_bio, PEM_R_UNSUPPORTED_CIPHER);
+			OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER);
 			goto err;
 			}
 		}
 
 	if ((dsize=i2d(x,NULL)) < 0)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write_bio, ERR_R_ASN1_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
 		dsize=0;
 		goto err;
 		}
@@ -318,7 +318,7 @@
 	data=(unsigned char *)OPENSSL_malloc((unsigned int)dsize+20);
 	if (data == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write_bio, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 	p=data;
@@ -336,7 +336,7 @@
  			klen=(*callback)(buf,PEM_BUFSIZE,1,u);
 			if (klen <= 0)
 				{
-				OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write_bio, PEM_R_READ_KEY);
+				OPENSSL_PUT_ERROR(PEM, PEM_R_READ_KEY);
 				goto err;
 				}
 			kstr=(unsigned char *)buf;
@@ -408,7 +408,7 @@
 	klen=callback(buf,PEM_BUFSIZE,0,u);
 	if (klen <= 0)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_do_header, PEM_R_BAD_PASSWORD_READ);
+		OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ);
 		return(0);
 		}
 
@@ -428,7 +428,7 @@
 	OPENSSL_cleanse((char *)key,sizeof(key));
 	if (!o)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_do_header, PEM_R_BAD_DECRYPT);
+		OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_DECRYPT);
 		return(0);
 		}
 	j+=i;
@@ -437,11 +437,18 @@
 	}
 
 static const EVP_CIPHER* cipher_by_name(const char *name) {
-  if (strcmp(name, "DES-CBC") == 0) {
+  /* This is similar to the (deprecated) function |EVP_get_cipherbyname|. */
+  if (0 == strcmp(name, SN_rc4)) {
+    return EVP_rc4();
+  } else if (0 == strcmp(name, SN_des_cbc)) {
     return EVP_des_cbc();
-  } else if (strcmp(name, "AES-128-CBC") == 0) {
+  } else if (0 == strcmp(name, SN_des_ede3_cbc)) {
+    return EVP_des_ede3_cbc();
+  } else if (0 == strcmp(name, SN_aes_128_cbc)) {
     return EVP_aes_128_cbc();
-  } else if (strcmp(name,  "AES-256-CBC") == 0) {
+  } else if (0 == strcmp(name, SN_aes_192_cbc)) {
+    return EVP_aes_192_cbc();
+  } else if (0 == strcmp(name, SN_aes_256_cbc)) {
     return EVP_aes_256_cbc();
   } else {
     return NULL;
@@ -458,19 +465,19 @@
 	if ((header == NULL) || (*header == '\0') || (*header == '\n'))
 		return(1);
 	if (strncmp(header,"Proc-Type: ",11) != 0)
-		{ OPENSSL_PUT_ERROR(PEM, PEM_get_EVP_CIPHER_INFO, PEM_R_NOT_PROC_TYPE); return(0); }
+		{ OPENSSL_PUT_ERROR(PEM, PEM_R_NOT_PROC_TYPE); return(0); }
 	header+=11;
 	if (*header != '4') return(0); header++;
 	if (*header != ',') return(0); header++;
 	if (strncmp(header,"ENCRYPTED",9) != 0)
-		{ OPENSSL_PUT_ERROR(PEM, PEM_get_EVP_CIPHER_INFO, PEM_R_NOT_ENCRYPTED); return(0); }
+		{ OPENSSL_PUT_ERROR(PEM, PEM_R_NOT_ENCRYPTED); return(0); }
 	for (; (*header != '\n') && (*header != '\0'); header++)
 		;
 	if (*header == '\0')
-		{ OPENSSL_PUT_ERROR(PEM, PEM_get_EVP_CIPHER_INFO, PEM_R_SHORT_HEADER); return(0); }
+		{ OPENSSL_PUT_ERROR(PEM, PEM_R_SHORT_HEADER); return(0); }
 	header++;
 	if (strncmp(header,"DEK-Info: ",10) != 0)
-		{ OPENSSL_PUT_ERROR(PEM, PEM_get_EVP_CIPHER_INFO, PEM_R_NOT_DEK_INFO); return(0); }
+		{ OPENSSL_PUT_ERROR(PEM, PEM_R_NOT_DEK_INFO); return(0); }
 	header+=10;
 
 	p=header;
@@ -489,7 +496,7 @@
 
 	if (enc == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_get_EVP_CIPHER_INFO, PEM_R_UNSUPPORTED_ENCRYPTION);
+		OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_ENCRYPTION);
 		return(0);
 		}
 	if (!load_iv(header_pp,&(cipher->iv[0]),EVP_CIPHER_iv_length(enc)))
@@ -516,7 +523,7 @@
 			v= *from-'a'+10;
 		else
 			{
-			OPENSSL_PUT_ERROR(PEM, load_iv, PEM_R_BAD_IV_CHARS);
+			OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_IV_CHARS);
 			return(0);
 			}
 		from++;
@@ -536,7 +543,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_write, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,fp,BIO_NOCLOSE);
@@ -603,7 +610,7 @@
 		OPENSSL_cleanse(buf, PEM_BUFSIZE*8);
 		OPENSSL_free(buf);
 	}
-	OPENSSL_PUT_ERROR(PEM, PEM_write_bio, reason);
+	OPENSSL_PUT_ERROR(PEM, reason);
 	return(0);
 	}
 
@@ -616,7 +623,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_read, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,fp,BIO_NOCLOSE);
@@ -644,7 +651,7 @@
 		BUF_MEM_free(nameB);
 		BUF_MEM_free(headerB);
 		BUF_MEM_free(dataB);
-		OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE);
 		return(0);
 		}
 
@@ -655,7 +662,7 @@
 
 		if (i <= 0)
 			{
-			OPENSSL_PUT_ERROR(PEM, PEM_read_bio, PEM_R_NO_START_LINE);
+			OPENSSL_PUT_ERROR(PEM, PEM_R_NO_START_LINE);
 			goto err;
 			}
 
@@ -670,7 +677,7 @@
 				continue;
 			if (!BUF_MEM_grow(nameB,i+9))
 				{
-				OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE);
 				goto err;
 				}
 			memcpy(nameB->data,&(buf[11]),i-6);
@@ -680,7 +687,7 @@
 		}
 	hl=0;
 	if (!BUF_MEM_grow(headerB,256))
-		{ OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE); goto err; }
+		{ OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; }
 	headerB->data[0]='\0';
 	for (;;)
 		{
@@ -692,7 +699,7 @@
 
 		if (buf[0] == '\n') break;
 		if (!BUF_MEM_grow(headerB,hl+i+9))
-			{ OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE); goto err; }
+			{ OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; }
 		if (strncmp(buf,"-----END ",9) == 0)
 			{
 			nohead=1;
@@ -705,7 +712,7 @@
 
 	bl=0;
 	if (!BUF_MEM_grow(dataB,1024))
-		{ OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE); goto err; }
+		{ OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; }
 	dataB->data[0]='\0';
 	if (!nohead)
 		{
@@ -723,7 +730,7 @@
 			if (i > 65) break;
 			if (!BUF_MEM_grow_clean(dataB,i+bl+9))
 				{
-				OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE);
 				goto err;
 				}
 			memcpy(&(dataB->data[bl]),buf,i);
@@ -754,7 +761,7 @@
 		(strncmp(nameB->data,&(buf[9]),i) != 0) ||
 		(strncmp(&(buf[9+i]),"-----\n",6) != 0))
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_read_bio, PEM_R_BAD_END_LINE);
+		OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_END_LINE);
 		goto err;
 		}
 
@@ -764,13 +771,13 @@
 		(unsigned char *)dataB->data,bl);
 	if (i < 0)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_read_bio, PEM_R_BAD_BASE64_DECODE);
+		OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_BASE64_DECODE);
 		goto err;
 		}
 	i=EVP_DecodeFinal(&ctx,(unsigned char *)&(dataB->data[bl]),&k);
 	if (i < 0)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_read_bio, PEM_R_BAD_BASE64_DECODE);
+		OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_BASE64_DECODE);
 		goto err;
 		}
 	bl+=k;
diff --git a/src/crypto/pem/pem_oth.c b/src/crypto/pem/pem_oth.c
index 20d12b6..3e8f6bd 100644
--- a/src/crypto/pem/pem_oth.c
+++ b/src/crypto/pem/pem_oth.c
@@ -83,7 +83,7 @@
 	p = data;
 	ret=d2i(x,&p,len);
 	if (ret == NULL)
-		OPENSSL_PUT_ERROR(PEM, PEM_ASN1_read_bio, ERR_R_ASN1_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
 	OPENSSL_free(data);
 	return ret;
 	}
diff --git a/src/crypto/pem/pem_pk8.c b/src/crypto/pem/pem_pk8.c
index 035038e..0824477 100644
--- a/src/crypto/pem/pem_pk8.c
+++ b/src/crypto/pem/pem_pk8.c
@@ -118,7 +118,7 @@
 	char buf[PEM_BUFSIZE];
 	int ret;
 	if(!(p8inf = EVP_PKEY2PKCS8(x))) {
-		OPENSSL_PUT_ERROR(PEM, do_pk8pkey, PEM_R_ERROR_CONVERTING_PRIVATE_KEY);
+		OPENSSL_PUT_ERROR(PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY);
 		return 0;
 	}
 	if(enc || (nid != -1)) {
@@ -127,7 +127,7 @@
 			if (!cb) cb = PEM_def_callback;
 			klen = cb(buf, PEM_BUFSIZE, 1, u);
 			if(klen <= 0) {
-				OPENSSL_PUT_ERROR(PEM, do_pk8pkey, PEM_R_READ_KEY);
+				OPENSSL_PUT_ERROR(PEM, PEM_R_READ_KEY);
 				PKCS8_PRIV_KEY_INFO_free(p8inf);
 				return 0;
 			}
@@ -163,7 +163,7 @@
 	if (!cb) cb = PEM_def_callback;
 	klen=cb(psbuf,PEM_BUFSIZE,0,u);
 	if (klen <= 0) {
-		OPENSSL_PUT_ERROR(PEM, d2i_PKCS8PrivateKey_bio, PEM_R_BAD_PASSWORD_READ);
+		OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ);
 		X509_SIG_free(p8);
 		return NULL;	
 	}
@@ -216,7 +216,7 @@
 	BIO *bp;
 	int ret;
 	if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) {
-		OPENSSL_PUT_ERROR(PEM, do_pk8pkey_fp, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return(0);
 	}
 	ret = do_pk8pkey(bp, x, isder, nid, enc, kstr, klen, cb, u);
@@ -229,7 +229,7 @@
 	BIO *bp;
 	EVP_PKEY *ret;
 	if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) {
-		OPENSSL_PUT_ERROR(PEM, d2i_PKCS8PrivateKey_fp, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return NULL;
 	}
 	ret = d2i_PKCS8PrivateKey_bio(bp, x, cb, u);
diff --git a/src/crypto/pem/pem_pkey.c b/src/crypto/pem/pem_pkey.c
index fe58558..c462727 100644
--- a/src/crypto/pem/pem_pkey.c
+++ b/src/crypto/pem/pem_pkey.c
@@ -109,7 +109,7 @@
 		if (!cb) cb = PEM_def_callback;
 		klen=cb(psbuf,PEM_BUFSIZE,0,u);
 		if (klen <= 0) {
-			OPENSSL_PUT_ERROR(PEM, PEM_read_bio_PrivateKey, PEM_R_BAD_PASSWORD_READ);
+			OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ);
 			X509_SIG_free(p8);
 			goto err;
 		}
@@ -132,7 +132,7 @@
 		}
 p8err:
 	if (ret == NULL)
-		OPENSSL_PUT_ERROR(PEM, PEM_read_bio_PrivateKey, ERR_R_ASN1_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
 
 err:
 	OPENSSL_free(nm);
@@ -210,7 +210,7 @@
 		}
 err:
 	if (ret == NULL)
-		OPENSSL_PUT_ERROR(PEM, PEM_read_bio_Parameters, ERR_R_ASN1_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
 	OPENSSL_free(nm);
 	OPENSSL_free(data);
 	return(ret);
@@ -236,7 +236,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_read_PrivateKey, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,fp,BIO_NOCLOSE);
@@ -254,7 +254,7 @@
 
         if ((b=BIO_new_fp(fp, BIO_NOCLOSE)) == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_write_PrivateKey, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return 0;
 		}
         ret=PEM_write_bio_PrivateKey(b, x, enc, kstr, klen, cb, u);
@@ -287,7 +287,7 @@
 		ret = d2i_DHparams(x, &p, len);
 
 	if (ret == NULL)
-		OPENSSL_PUT_ERROR(PEM, PEM_read_bio_DHparams, ERR_R_ASN1_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB);
 	OPENSSL_free(nm);
 	OPENSSL_free(data);
 	return ret;
@@ -301,7 +301,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(PEM, PEM_read_DHparams, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,fp,BIO_NOCLOSE);
diff --git a/src/crypto/perlasm/arm-xlate.pl b/src/crypto/perlasm/arm-xlate.pl
index 81ceb31..706fa70 100755
--- a/src/crypto/perlasm/arm-xlate.pl
+++ b/src/crypto/perlasm/arm-xlate.pl
@@ -116,6 +116,9 @@
     return $line;
 }
 
+print "#if defined(__arm__)\n" if ($flavour eq "linux32");
+print "#if defined(__aarch64__)\n" if ($flavour eq "linux64");
+
 while($line=<>) {
 
     if ($line =~ m/^\s*(#|@|\/\/)/)	{ print $line; next; }
@@ -162,4 +165,6 @@
     print "\n";
 }
 
+print "#endif" if ($flavour eq "linux32" || $flavour eq "linux64");
+
 close STDOUT;
diff --git a/src/crypto/pkcs8/CMakeLists.txt b/src/crypto/pkcs8/CMakeLists.txt
index 4426f1e..ce5bce1 100644
--- a/src/crypto/pkcs8/CMakeLists.txt
+++ b/src/crypto/pkcs8/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   pkcs8
@@ -19,4 +19,11 @@
   $<TARGET_OBJECTS:test_support>
 )
 
+add_executable(
+  pkcs8_test
+
+  pkcs8_test.cc
+)
+
+target_link_libraries(pkcs8_test crypto)
 target_link_libraries(pkcs12_test crypto)
diff --git a/src/crypto/pkcs8/internal.h b/src/crypto/pkcs8/internal.h
index 44ca4f7..7995e78 100644
--- a/src/crypto/pkcs8/internal.h
+++ b/src/crypto/pkcs8/internal.h
@@ -66,6 +66,15 @@
 #define PKCS5_DEFAULT_ITERATIONS 2048
 #define PKCS5_SALT_LEN 8
 
+/* PKCS5_v2_PBE_keyivgen intializes the supplied |ctx| for PBKDF v2, which must
+ * be specified by |param|. The password is specified by |pass_raw| and
+ * |pass_raw_len|. |cipher| and |md| are ignored.
+ *
+ * It returns one on success and zero on error. */
+int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw,
+                          size_t pass_raw_len, ASN1_TYPE *param,
+                          const EVP_CIPHER *cipher, const EVP_MD *md, int enc);
+
 
 #if defined(__cplusplus)
 }  /* extern C */
diff --git a/src/crypto/pkcs8/p5_pbe.c b/src/crypto/pkcs8/p5_pbe.c
index f30ae79..653cabf 100644
--- a/src/crypto/pkcs8/p5_pbe.c
+++ b/src/crypto/pkcs8/p5_pbe.c
@@ -86,21 +86,21 @@
 	pbe = PBEPARAM_new();
 	if (!pbe)
 		{
-		OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe_set0_algor, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 	if(iter <= 0)
 		iter = PKCS5_DEFAULT_ITERATIONS;
 	if (!ASN1_INTEGER_set(pbe->iter, iter))
 		{
-		OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe_set0_algor, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 	if (!saltlen)
 		saltlen = PKCS5_SALT_LEN;
 	if (!ASN1_STRING_set(pbe->salt, NULL, saltlen))
 		{
-		OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe_set0_algor, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 	sstr = ASN1_STRING_data(pbe->salt);
@@ -111,7 +111,7 @@
 
 	if(!ASN1_item_pack(pbe, ASN1_ITEM_rptr(PBEPARAM), &pbe_str))
 		{
-		OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe_set0_algor, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 
@@ -138,7 +138,7 @@
 	ret = X509_ALGOR_new();
 	if (!ret)
 		{
-		OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe_set, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
 		return NULL;
 		}
 
diff --git a/src/crypto/pkcs8/p5_pbev2.c b/src/crypto/pkcs8/p5_pbev2.c
index 9eb9848..f58aae7 100644
--- a/src/crypto/pkcs8/p5_pbev2.c
+++ b/src/crypto/pkcs8/p5_pbev2.c
@@ -53,6 +53,8 @@
  * (eay@cryptsoft.com).  This product includes software written by Tim
  * Hudson (tjh@cryptsoft.com). */
 
+#include <assert.h>
+#include <limits.h>
 #include <string.h>
 
 #include <openssl/asn1t.h>
@@ -124,7 +126,7 @@
 
 	alg_nid = EVP_CIPHER_nid(cipher);
 	if(alg_nid == NID_undef) {
-		OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe2_set_iv, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER);
+		OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER);
 		goto err;
 	}
 	obj = OBJ_nid2obj(alg_nid);
@@ -152,7 +154,7 @@
 	if (!EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, iv, 0))
 		goto err;
 	if(param_to_asn1(&ctx, scheme->parameter) < 0) {
-		OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe2_set_iv, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS);
+		OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS);
 		EVP_CIPHER_CTX_cleanup(&ctx);
 		goto err;
 	}
@@ -202,7 +204,7 @@
 	return ret;
 
 	merr:
-	OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe2_set_iv, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
 
 	err:
 	PBE2PARAM_free(pbe2);
@@ -295,9 +297,143 @@
 	return keyfunc;
 
 	merr:
-	OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbkdf2_set, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
 	PBKDF2PARAM_free(kdf);
 	X509_ALGOR_free(keyfunc);
 	return NULL;
 	}
 
+static int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx,
+                                    const uint8_t *pass_raw,
+                                    size_t pass_raw_len, const ASN1_TYPE *param,
+                                    const ASN1_TYPE *iv, int enc) {
+  int rv = 0;
+  PBKDF2PARAM *pbkdf2param = NULL;
+
+  if (EVP_CIPHER_CTX_cipher(ctx) == NULL) {
+    OPENSSL_PUT_ERROR(PKCS8, CIPHER_R_NO_CIPHER_SET);
+    goto err;
+  }
+
+  /* Decode parameters. */
+  if (param == NULL || param->type != V_ASN1_SEQUENCE) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+    goto err;
+  }
+
+  const uint8_t *pbuf = param->value.sequence->data;
+  int plen = param->value.sequence->length;
+  pbkdf2param = d2i_PBKDF2PARAM(NULL, &pbuf, plen);
+  if (pbkdf2param == NULL || pbuf != param->value.sequence->data + plen) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+    goto err;
+  }
+
+  /* Now check the parameters. */
+  uint8_t key[EVP_MAX_KEY_LENGTH];
+  const size_t key_len = EVP_CIPHER_CTX_key_length(ctx);
+  assert(key_len <= sizeof(key));
+
+  if (pbkdf2param->keylength != NULL &&
+      ASN1_INTEGER_get(pbkdf2param->keylength) != (int) key_len) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEYLENGTH);
+    goto err;
+  }
+
+  if (pbkdf2param->prf != NULL &&
+      OBJ_obj2nid(pbkdf2param->prf->algorithm) != NID_hmacWithSHA1) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRF);
+    goto err;
+  }
+
+  if (pbkdf2param->salt->type != V_ASN1_OCTET_STRING) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_SALT_TYPE);
+    goto err;
+  }
+
+  if (pbkdf2param->iter->type != V_ASN1_INTEGER) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT);
+    goto err;
+  }
+  long iterations = ASN1_INTEGER_get(pbkdf2param->iter);
+  if (iterations < 0 || iterations > UINT_MAX) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT);
+    goto err;
+  }
+
+  if (iv->type != V_ASN1_OCTET_STRING || iv->value.octet_string == NULL) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS);
+    goto err;
+  }
+
+  const size_t iv_len = EVP_CIPHER_CTX_iv_length(ctx);
+  if (iv->value.octet_string->length != iv_len) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS);
+    goto err;
+  }
+
+  if (!PKCS5_PBKDF2_HMAC_SHA1((const char *) pass_raw, pass_raw_len,
+                              pbkdf2param->salt->value.octet_string->data,
+                              pbkdf2param->salt->value.octet_string->length,
+                              iterations, key_len, key)) {
+    goto err;
+  }
+
+  rv = EVP_CipherInit_ex(ctx, NULL /* cipher */, NULL /* engine */, key,
+                         iv->value.octet_string->data, enc);
+
+ err:
+  PBKDF2PARAM_free(pbkdf2param);
+  return rv;
+}
+
+int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw,
+                          size_t pass_raw_len, ASN1_TYPE *param,
+                          const EVP_CIPHER *unused, const EVP_MD *unused2,
+                          int enc) {
+  PBE2PARAM *pbe2param = NULL;
+  int rv = 0;
+
+  if (param == NULL ||
+      param->type != V_ASN1_SEQUENCE ||
+      param->value.sequence == NULL) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+    goto err;
+  }
+
+  const uint8_t *pbuf = param->value.sequence->data;
+  int plen = param->value.sequence->length;
+  pbe2param = d2i_PBE2PARAM(NULL, &pbuf, plen);
+  if (pbe2param == NULL || pbuf != param->value.sequence->data + plen) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+    goto err;
+  }
+
+  /* Check that the key derivation function is PBKDF2. */
+  if (OBJ_obj2nid(pbe2param->keyfunc->algorithm) != NID_id_pbkdf2) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION);
+    goto err;
+  }
+
+  /* See if we recognise the encryption algorithm. */
+  const EVP_CIPHER *cipher =
+      EVP_get_cipherbynid(OBJ_obj2nid(pbe2param->encryption->algorithm));
+  if (cipher == NULL) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_CIPHER);
+    goto err;
+  }
+
+  /* Fixup cipher based on AlgorithmIdentifier. */
+  if (!EVP_CipherInit_ex(ctx, cipher, NULL /* engine */, NULL /* key */,
+                         NULL /* iv */, enc)) {
+    goto err;
+  }
+
+  rv = PKCS5_v2_PBKDF2_keyivgen(ctx, pass_raw, pass_raw_len,
+                                pbe2param->keyfunc->parameter,
+                                pbe2param->encryption->parameter, enc);
+
+ err:
+  PBE2PARAM_free(pbe2param);
+  return rv;
+}
diff --git a/src/crypto/pkcs8/pkcs8.c b/src/crypto/pkcs8/pkcs8.c
index 843c74d..8067c91 100644
--- a/src/crypto/pkcs8/pkcs8.c
+++ b/src/crypto/pkcs8/pkcs8.c
@@ -69,6 +69,7 @@
 #include <openssl/mem.h>
 #include <openssl/x509.h>
 
+#include "internal.h"
 #include "../bytestring/internal.h"
 #include "../evp/internal.h"
 
@@ -200,7 +201,7 @@
   }
 
 err:
-  OPENSSL_PUT_ERROR(PKCS8, pkcs12_key_gen_raw, ERR_R_MALLOC_FAILURE);
+  OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
 
 end:
   OPENSSL_free(Ai);
@@ -227,14 +228,14 @@
   /* Extract useful info from parameter */
   if (param == NULL || param->type != V_ASN1_SEQUENCE ||
       param->value.sequence == NULL) {
-    OPENSSL_PUT_ERROR(PKCS8, pkcs12_pbe_keyivgen, PKCS8_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
     return 0;
   }
 
   pbuf = param->value.sequence->data;
   pbe = d2i_PBEPARAM(NULL, &pbuf, param->value.sequence->length);
   if (pbe == NULL) {
-    OPENSSL_PUT_ERROR(PKCS8, pkcs12_pbe_keyivgen, PKCS8_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
     return 0;
   }
 
@@ -247,13 +248,13 @@
   salt_len = pbe->salt->length;
   if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_KEY_ID,
                           iterations, EVP_CIPHER_key_length(cipher), key, md)) {
-    OPENSSL_PUT_ERROR(PKCS8, pkcs12_pbe_keyivgen, PKCS8_R_KEY_GEN_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR);
     PBEPARAM_free(pbe);
     return 0;
   }
   if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_IV_ID,
                           iterations, EVP_CIPHER_iv_length(cipher), iv, md)) {
-    OPENSSL_PUT_ERROR(PKCS8, pkcs12_pbe_keyivgen, PKCS8_R_KEY_GEN_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR);
     PBEPARAM_free(pbe);
     return 0;
   }
@@ -274,42 +275,93 @@
   const EVP_CIPHER* (*cipher_func)(void);
   const EVP_MD* (*md_func)(void);
   keygen_func keygen;
+  int flags;
 };
 
+#define PBE_UCS2_CONVERT_PASSWORD 0x1
+
 static const struct pbe_suite kBuiltinPBE[] = {
     {
-     NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1, pkcs12_pbe_keyivgen,
+     NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1,
+     pkcs12_pbe_keyivgen, PBE_UCS2_CONVERT_PASSWORD
     },
     {
      NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1, pkcs12_pbe_keyivgen,
+     PBE_UCS2_CONVERT_PASSWORD
     },
     {
      NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1,
-     pkcs12_pbe_keyivgen,
+     pkcs12_pbe_keyivgen, PBE_UCS2_CONVERT_PASSWORD
+    },
+    {
+      NID_pbes2, NULL, NULL,  PKCS5_v2_PBE_keyivgen, 0
     },
 };
 
+static const struct pbe_suite *get_pbe_suite(int pbe_nid) {
+  unsigned i;
+  for (i = 0; i < sizeof(kBuiltinPBE) / sizeof(kBuiltinPBE[0]); i++) {
+    if (kBuiltinPBE[i].pbe_nid == pbe_nid) {
+      return &kBuiltinPBE[i];
+    }
+  }
+
+  return NULL;
+}
+
+/* pass_to_pass_raw performs a password conversion (possibly a no-op)
+ * appropriate to the supplied |pbe_nid|. The input |pass| is treated as a
+ * NUL-terminated string if |pass_len| is -1, otherwise it is treated as a
+ * buffer of the specified length. If the supplied PBE NID sets the
+ * |PBE_UCS2_CONVERT_PASSWORD| flag, the supplied |pass| will be converted to
+ * UCS-2.
+ *
+ * It sets |*out_pass_raw| to a new buffer that must be freed by the caller. It
+ * returns one on success and zero on error. */
+static int pass_to_pass_raw(int pbe_nid, const char *pass, int pass_len,
+                            uint8_t **out_pass_raw, size_t *out_pass_raw_len) {
+  if (pass == NULL) {
+    *out_pass_raw = NULL;
+    *out_pass_raw_len = 0;
+    return 1;
+  }
+
+  if (pass_len == -1) {
+    pass_len = strlen(pass);
+  } else if (pass_len < 0 || pass_len > 2000000000) {
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
+    return 0;
+  }
+
+  const struct pbe_suite *suite = get_pbe_suite(pbe_nid);
+  if (suite != NULL && (suite->flags & PBE_UCS2_CONVERT_PASSWORD)) {
+    if (!ascii_to_ucs2(pass, pass_len, out_pass_raw, out_pass_raw_len)) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+      return 0;
+    }
+  } else {
+    *out_pass_raw = BUF_memdup(pass, pass_len);
+    if (*out_pass_raw == NULL) {
+      OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+      return 0;
+    }
+    *out_pass_raw_len = (size_t)pass_len;
+  }
+
+  return 1;
+}
+
 static int pbe_cipher_init(ASN1_OBJECT *pbe_obj,
                            const uint8_t *pass_raw, size_t pass_raw_len,
                            ASN1_TYPE *param,
                            EVP_CIPHER_CTX *ctx, int is_encrypt) {
   const EVP_CIPHER *cipher;
   const EVP_MD *md;
-  unsigned i;
 
-  const struct pbe_suite *suite = NULL;
-  const int pbe_nid = OBJ_obj2nid(pbe_obj);
-
-  for (i = 0; i < sizeof(kBuiltinPBE) / sizeof(struct pbe_suite); i++) {
-    if (kBuiltinPBE[i].pbe_nid == pbe_nid) {
-      suite = &kBuiltinPBE[i];
-      break;
-    }
-  }
-
+  const struct pbe_suite *suite = get_pbe_suite(OBJ_obj2nid(pbe_obj));
   if (suite == NULL) {
     char obj_str[80];
-    OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_ALGORITHM);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM);
     if (!pbe_obj) {
       strncpy(obj_str, "NULL", sizeof(obj_str));
     } else {
@@ -324,7 +376,7 @@
   } else {
     cipher = suite->cipher_func();
     if (!cipher) {
-      OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_CIPHER);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER);
       return 0;
     }
   }
@@ -334,14 +386,14 @@
   } else {
     md = suite->md_func();
     if (!md) {
-      OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_DIGEST);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_DIGEST);
       return 0;
     }
   }
 
   if (!suite->keygen(ctx, pass_raw, pass_raw_len, param, cipher, md,
                      is_encrypt)) {
-    OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_KEYGEN_FAILURE);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEYGEN_FAILURE);
     return 0;
   }
 
@@ -362,32 +414,32 @@
 
   if (!pbe_cipher_init(algor->algorithm, pass_raw, pass_raw_len,
                        algor->parameter, &ctx, is_encrypt)) {
-    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, PKCS8_R_UNKNOWN_CIPHER_ALGORITHM);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER_ALGORITHM);
     return 0;
   }
   block_size = EVP_CIPHER_CTX_block_size(&ctx);
 
   if (in_len + block_size < in_len) {
-    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, PKCS8_R_TOO_LONG);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG);
     goto err;
   }
 
   buf = OPENSSL_malloc(in_len + block_size);
   if (buf == NULL) {
-    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
   if (!EVP_CipherUpdate(&ctx, buf, &n, in, in_len)) {
     OPENSSL_free(buf);
-    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, ERR_R_EVP_LIB);
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB);
     goto err;
   }
   *out_len = n;
 
   if (!EVP_CipherFinal_ex(&ctx, buf + n, &n)) {
     OPENSSL_free(buf);
-    OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, ERR_R_EVP_LIB);
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB);
     goto err;
   }
   *out_len += n;
@@ -410,14 +462,14 @@
 
   if (!pbe_crypt(algor, pass_raw, pass_raw_len, oct->data, oct->length,
                  &out, &out_len, 0 /* decrypt */)) {
-    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_decrypt_d2i, PKCS8_R_CRYPT_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CRYPT_ERROR);
     return NULL;
   }
   p = out;
   ret = ASN1_item_d2i(NULL, &p, out_len, it);
   OPENSSL_cleanse(out, out_len);
   if (!ret) {
-    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_decrypt_d2i, PKCS8_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
   }
   OPENSSL_free(out);
   return ret;
@@ -427,19 +479,12 @@
                                    int pass_len) {
   uint8_t *pass_raw = NULL;
   size_t pass_raw_len = 0;
-  PKCS8_PRIV_KEY_INFO *ret;
-
-  if (pass) {
-    if (pass_len == -1) {
-      pass_len = strlen(pass);
-    }
-    if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) {
-      OPENSSL_PUT_ERROR(PKCS8, PKCS8_decrypt, PKCS8_R_DECODE_ERROR);
-      return NULL;
-    }
+  if (!pass_to_pass_raw(OBJ_obj2nid(pkcs8->algor->algorithm), pass, pass_len,
+                        &pass_raw, &pass_raw_len)) {
+    return NULL;
   }
 
-  ret = PKCS8_decrypt_pbe(pkcs8, pass_raw, pass_raw_len);
+  PKCS8_PRIV_KEY_INFO *ret = PKCS8_decrypt_pbe(pkcs8, pass_raw, pass_raw_len);
 
   if (pass_raw) {
     OPENSSL_cleanse(pass_raw, pass_raw_len);
@@ -466,17 +511,17 @@
 
   oct = M_ASN1_OCTET_STRING_new();
   if (oct == NULL) {
-    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_i2d_encrypt, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
   in_len = ASN1_item_i2d(obj, &in, it);
   if (!in) {
-    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_i2d_encrypt, PKCS8_R_ENCODE_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCODE_ERROR);
     return NULL;
   }
   if (!pbe_crypt(algor, pass_raw, pass_raw_len, in, in_len, &oct->data, &crypt_len,
                  1 /* encrypt */)) {
-    OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_i2d_encrypt, PKCS8_R_ENCRYPT_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR);
     OPENSSL_free(in);
     return NULL;
   }
@@ -491,20 +536,12 @@
                         int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
   uint8_t *pass_raw = NULL;
   size_t pass_raw_len = 0;
-  X509_SIG *ret;
-
-  if (pass) {
-    if (pass_len == -1) {
-      pass_len = strlen(pass);
-    }
-    if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) {
-      OPENSSL_PUT_ERROR(PKCS8, PKCS8_encrypt, PKCS8_R_DECODE_ERROR);
-      return NULL;
-    }
+  if (!pass_to_pass_raw(pbe_nid, pass, pass_len, &pass_raw, &pass_raw_len)) {
+    return NULL;
   }
 
-  ret = PKCS8_encrypt_pbe(pbe_nid, pass_raw, pass_raw_len,
-                          salt, salt_len, iterations, p8inf);
+  X509_SIG *ret = PKCS8_encrypt_pbe(pbe_nid, cipher, pass_raw, pass_raw_len,
+                                    salt, salt_len, iterations, p8inf);
 
   if (pass_raw) {
     OPENSSL_cleanse(pass_raw, pass_raw_len);
@@ -513,7 +550,7 @@
   return ret;
 }
 
-X509_SIG *PKCS8_encrypt_pbe(int pbe_nid,
+X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, const EVP_CIPHER *cipher,
                             const uint8_t *pass_raw, size_t pass_raw_len,
                             uint8_t *salt, size_t salt_len,
                             int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
@@ -522,13 +559,17 @@
 
   pkcs8 = X509_SIG_new();
   if (pkcs8 == NULL) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS8_encrypt_pbe, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
-  pbe = PKCS5_pbe_set(pbe_nid, iterations, salt, salt_len);
+  if (pbe_nid == -1) {
+    pbe = PKCS5_pbe2_set(cipher, iterations, salt, salt_len);
+  } else {
+    pbe = PKCS5_pbe_set(pbe_nid, iterations, salt, salt_len);
+  }
   if (!pbe) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS8_encrypt_pbe, ERR_R_ASN1_LIB);
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_ASN1_LIB);
     goto err;
   }
 
@@ -538,7 +579,7 @@
   pkcs8->digest = pkcs12_item_i2d_encrypt(
       pbe, ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw, pass_raw_len, p8inf);
   if (!pkcs8->digest) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS8_encrypt_pbe, PKCS8_R_ENCRYPT_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR);
     goto err;
   }
 
@@ -560,13 +601,12 @@
 
   pkey = EVP_PKEY_new();
   if (pkey == NULL) {
-    OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
   if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid))) {
-    OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY,
-                      PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
     i2t_ASN1_OBJECT(obj_tmp, 80, algoid);
     ERR_add_error_data(2, "TYPE=", obj_tmp);
     goto error;
@@ -574,11 +614,11 @@
 
   if (pkey->ameth->priv_decode) {
     if (!pkey->ameth->priv_decode(pkey, p8)) {
-      OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY, PKCS8_R_PRIVATE_KEY_DECODE_ERROR);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PRIVATE_KEY_DECODE_ERROR);
       goto error;
     }
   } else {
-    OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY, PKCS8_R_METHOD_NOT_SUPPORTED);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED);
     goto error;
   }
 
@@ -594,7 +634,7 @@
 
   p8 = PKCS8_PRIV_KEY_INFO_new();
   if (p8 == NULL) {
-    OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
   p8->broken = PKCS8_OK;
@@ -602,17 +642,15 @@
   if (pkey->ameth) {
     if (pkey->ameth->priv_encode) {
       if (!pkey->ameth->priv_encode(p8, pkey)) {
-        OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8,
-                          PKCS8_R_PRIVATE_KEY_ENCODE_ERROR);
+        OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PRIVATE_KEY_ENCODE_ERROR);
         goto error;
       }
     } else {
-      OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED);
       goto error;
     }
   } else {
-    OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8,
-                      PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
     goto error;
   }
   return p8;
@@ -646,8 +684,7 @@
    * 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);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PKCS12_TOO_DEEPLY_NESTED);
     return 0;
   }
 
@@ -656,6 +693,7 @@
    * 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)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
     return 0;
   }
 
@@ -666,16 +704,14 @@
   }
 
   if (!CBS_get_asn1(&in, &in, CBS_ASN1_SEQUENCE)) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_infos,
-                      PKCS8_R_BAD_PKCS12_DATA);
+    OPENSSL_PUT_ERROR(PKCS8, 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);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
       goto err;
     }
 
@@ -705,8 +741,7 @@
   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_handle_content_info,
-                      PKCS8_R_BAD_PKCS12_DATA);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
     goto err;
   }
 
@@ -734,14 +769,12 @@
         !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);
+      OPENSSL_PUT_ERROR(PKCS8, 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);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
       goto err;
     }
 
@@ -752,8 +785,7 @@
     }
     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);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
       goto err;
     }
 
@@ -773,8 +805,7 @@
 
     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);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
       goto err;
     }
 
@@ -787,8 +818,7 @@
     X509_SIG *encrypted = NULL;
 
     if (*ctx->out_key) {
-      OPENSSL_PUT_ERROR(PKCS8, PKCS12_handle_content_info,
-                        PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12);
       goto err;
     }
 
@@ -796,13 +826,11 @@
      * 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);
+      OPENSSL_PUT_ERROR(PKCS8, 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);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
       X509_SIG_free(encrypted);
       goto err;
     }
@@ -828,8 +856,7 @@
         !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);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
       goto err;
     }
 
@@ -837,13 +864,11 @@
       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);
+        OPENSSL_PUT_ERROR(PKCS8, 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);
+        OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
         X509_free(x509);
         goto err;
       }
@@ -875,6 +900,7 @@
 
   /* The input may be in BER format. */
   if (!CBS_asn1_ber_to_der(ber_in, &der_bytes, &der_len)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
     return 0;
   }
   if (der_bytes != NULL) {
@@ -891,28 +917,27 @@
   if (!CBS_get_asn1(&in, &pfx, CBS_ASN1_SEQUENCE) ||
       CBS_len(&in) != 0 ||
       !CBS_get_asn1_uint64(&pfx, &version)) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS12_get_key_and_certs, PKCS8_R_BAD_PKCS12_DATA);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
     goto err;
   }
 
   if (version < 3) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS12_get_key_and_certs,
-                      PKCS8_R_BAD_PKCS12_VERSION);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_VERSION);
     goto err;
   }
 
   if (!CBS_get_asn1(&pfx, &authsafe, CBS_ASN1_SEQUENCE)) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS12_get_key_and_certs, PKCS8_R_BAD_PKCS12_DATA);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
     goto err;
   }
 
   if (CBS_len(&pfx) == 0) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS12_get_key_and_certs, PKCS8_R_MISSING_MAC);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MISSING_MAC);
     goto err;
   }
 
   if (!CBS_get_asn1(&pfx, &mac_data, CBS_ASN1_SEQUENCE)) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS12_get_key_and_certs, PKCS8_R_BAD_PKCS12_DATA);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
     goto err;
   }
 
@@ -921,7 +946,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_get_key_and_certs, PKCS8_R_BAD_PKCS12_DATA);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
     goto err;
   }
 
@@ -929,13 +954,12 @@
    * 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_get_key_and_certs,
-                      PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED);
+    OPENSSL_PUT_ERROR(PKCS8, 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_get_key_and_certs, PKCS8_R_BAD_PKCS12_DATA);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
     goto err;
   }
 
@@ -943,7 +967,7 @@
   ctx.out_certs = out_certs;
   if (!ascii_to_ucs2(password, strlen(password), &ctx.password,
                      &ctx.password_len)) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS12_get_key_and_certs, PKCS8_R_DECODE_ERROR);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
     goto err;
   }
 
@@ -962,7 +986,7 @@
         !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_get_key_and_certs, PKCS8_R_BAD_PKCS12_DATA);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
       goto err;
     }
 
@@ -971,8 +995,7 @@
     if (CBS_len(&mac_data) > 0) {
       if (!CBS_get_asn1_uint64(&mac_data, &iterations) ||
           iterations > INT_MAX) {
-        OPENSSL_PUT_ERROR(PKCS8, PKCS12_get_key_and_certs,
-                          PKCS8_R_BAD_PKCS12_DATA);
+        OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
         goto err;
       }
     }
@@ -980,7 +1003,7 @@
     hash_nid = OBJ_cbs2nid(&hash_oid);
     if (hash_nid == NID_undef ||
         (md = EVP_get_digestbynid(hash_nid)) == NULL) {
-      OPENSSL_PUT_ERROR(PKCS8, PKCS12_get_key_and_certs, PKCS8_R_UNKNOWN_HASH);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_HASH);
       goto err;
     }
 
@@ -996,8 +1019,7 @@
     }
 
     if (!CBS_mem_equal(&expected_mac, hmac, hmac_len)) {
-      OPENSSL_PUT_ERROR(PKCS8, PKCS12_get_key_and_certs,
-                        PKCS8_R_INCORRECT_PASSWORD);
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_INCORRECT_PASSWORD);
       goto err;
     }
   }
@@ -1126,6 +1148,7 @@
   if (!ca_certs) {
     ca_certs = sk_X509_new_null();
     if (ca_certs == NULL) {
+      OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
       return 0;
     }
     ca_certs_alloced = 1;
diff --git a/src/crypto/pkcs8/pkcs8_test.cc b/src/crypto/pkcs8/pkcs8_test.cc
new file mode 100644
index 0000000..7a88ddf
--- /dev/null
+++ b/src/crypto/pkcs8/pkcs8_test.cc
@@ -0,0 +1,91 @@
+/* Copyright (c) 2015, 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 <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/pkcs8.h>
+#include <openssl/x509.h>
+
+#include "../test/scoped_types.h"
+
+
+/* kDER is a PKCS#8 encrypted private key. It was generated with:
+ *
+ * openssl genrsa 512 > test.key
+ * openssl pkcs8 -topk8 -in test.key -out test.key.encrypted -v2 des3 -outform der
+ * hexdump -Cv test.key.encrypted
+ *
+ * The password is "testing".
+ */
+static const uint8_t kDER[] = {
+  0x30, 0x82, 0x01, 0x9e, 0x30, 0x40, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05,
+  0x0d, 0x30, 0x33, 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c,
+  0x30, 0x0e, 0x04, 0x08, 0x06, 0xa5, 0x4b, 0x0c, 0x0c, 0x50, 0x8c, 0x19, 0x02, 0x02, 0x08, 0x00,
+  0x30, 0x14, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07, 0x04, 0x08, 0x3a, 0xd0,
+  0x70, 0x4b, 0x26, 0x50, 0x13, 0x7b, 0x04, 0x82, 0x01, 0x58, 0xa6, 0xee, 0x02, 0xf2, 0xf2, 0x7c,
+  0x19, 0x91, 0xe3, 0xce, 0x32, 0x85, 0xc5, 0x01, 0xd9, 0xe3, 0x5e, 0x14, 0xb6, 0xb8, 0x78, 0xad,
+  0xda, 0x01, 0xec, 0x9e, 0x42, 0xe8, 0xbf, 0x0b, 0x46, 0x03, 0xbc, 0x92, 0x6f, 0xe4, 0x0f, 0x0f,
+  0x48, 0x30, 0x10, 0x10, 0x9b, 0xfb, 0x4b, 0xb9, 0x45, 0xf8, 0xcf, 0xab, 0xa1, 0x18, 0xdd, 0x19,
+  0xa4, 0xa4, 0xe1, 0xf0, 0xa1, 0x8d, 0xc2, 0x23, 0xe7, 0x0d, 0x7a, 0x64, 0x21, 0x6b, 0xfa, 0x48,
+  0xb9, 0x41, 0xc1, 0x0c, 0x4b, 0xce, 0x6f, 0x1a, 0x91, 0x9b, 0x9f, 0xdd, 0xcf, 0xa9, 0x8d, 0x33,
+  0x2c, 0x45, 0x81, 0x5c, 0x5e, 0x67, 0xc6, 0x68, 0x43, 0x62, 0xff, 0x5e, 0x9b, 0x1a, 0x15, 0x3a,
+  0x9d, 0x71, 0x3f, 0xbe, 0x32, 0x2f, 0xe5, 0x90, 0x65, 0x65, 0x9c, 0x22, 0xf6, 0x29, 0x2e, 0xcf,
+  0x26, 0x16, 0x7b, 0x66, 0x48, 0x55, 0xad, 0x9a, 0x8d, 0x89, 0xf4, 0x48, 0x4f, 0x1f, 0x9d, 0xb8,
+  0xfa, 0xe1, 0xf1, 0x3b, 0x39, 0x5c, 0x72, 0xc6, 0xb8, 0x3e, 0x98, 0xe8, 0x77, 0xe8, 0xb6, 0x71,
+  0x84, 0xa8, 0x6e, 0xca, 0xaf, 0x62, 0x96, 0x49, 0x8a, 0x21, 0x6f, 0x9e, 0x78, 0x07, 0x97, 0x38,
+  0x40, 0x66, 0x42, 0x5a, 0x1b, 0xe0, 0x9b, 0xe9, 0x91, 0x82, 0xe4, 0xea, 0x8f, 0x2a, 0xb2, 0x80,
+  0xce, 0xe8, 0x57, 0xd3, 0xac, 0x11, 0x9d, 0xb2, 0x39, 0x0f, 0xe1, 0xce, 0x18, 0x96, 0x38, 0xa1,
+  0x19, 0x80, 0x88, 0x81, 0x3d, 0xda, 0xaa, 0x8e, 0x15, 0x27, 0x19, 0x73, 0x0c, 0xf3, 0xaf, 0x45,
+  0xe9, 0x1b, 0xad, 0x6c, 0x3d, 0xbf, 0x95, 0xf7, 0xa0, 0x87, 0x0e, 0xde, 0xf1, 0xd8, 0xee, 0xaa,
+  0x92, 0x76, 0x8d, 0x32, 0x45, 0xa1, 0xe7, 0xf5, 0x05, 0xd6, 0x2c, 0x67, 0x63, 0x10, 0xfa, 0xde,
+  0x80, 0xc7, 0x5b, 0x96, 0x0f, 0x24, 0x50, 0x78, 0x30, 0xe5, 0x89, 0xf3, 0x73, 0xfa, 0x40, 0x11,
+  0xd5, 0x26, 0xb8, 0x36, 0x96, 0x98, 0xe6, 0xbd, 0x73, 0x62, 0x56, 0xb9, 0xea, 0x28, 0x16, 0x93,
+  0x5b, 0x33, 0xae, 0x83, 0xf9, 0x1f, 0xee, 0xef, 0xc8, 0xbf, 0xc7, 0xb1, 0x47, 0x43, 0xa1, 0xc6,
+  0x1a, 0x64, 0x47, 0x02, 0x40, 0x3e, 0xbc, 0x0f, 0x80, 0x71, 0x5c, 0x44, 0x60, 0xbc, 0x78, 0x2e,
+  0xd2, 0x77, 0xf8, 0x6e, 0x12, 0x51, 0x89, 0xdb, 0x90, 0x64, 0xcd, 0x76, 0x10, 0x29, 0x73, 0xc2,
+  0x2f, 0x94, 0x7b, 0x98, 0xcd, 0xbb, 0x61, 0x16, 0x1d, 0x52, 0x11, 0x73, 0x48, 0xe6, 0x39, 0xfc,
+  0xd6, 0x2d,
+};
+
+static bool test(const uint8_t *der, size_t der_len) {
+  const uint8_t *data = der;
+  ScopedX509_SIG sig(d2i_X509_SIG(NULL, &data, der_len));
+  if (sig.get() == NULL || data != der + der_len) {
+    fprintf(stderr, "d2i_X509_SIG failed or did not consume all bytes.\n");
+    return false;
+  }
+
+  static const char kPassword[] = "testing";
+  ScopedPKCS8_PRIV_KEY_INFO keypair(PKCS8_decrypt(sig.get(), kPassword, -1));
+  if (!keypair) {
+    fprintf(stderr, "PKCS8_decrypt failed.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  return true;
+}
+
+int main(int argc, char **argv) {
+  if (!test(kDER, sizeof(kDER))) {
+    return 1;
+  }
+
+  printf("PASS\n");
+  return 0;
+}
diff --git a/src/crypto/poly1305/CMakeLists.txt b/src/crypto/poly1305/CMakeLists.txt
index bb0c1e4..674d9f6 100644
--- a/src/crypto/poly1305/CMakeLists.txt
+++ b/src/crypto/poly1305/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 if (${ARCH} STREQUAL "arm")
   set(
@@ -19,3 +19,12 @@
 
   ${POLY1305_ARCH_SOURCES}
 )
+
+add_executable(
+  poly1305_test
+
+  poly1305_test.cc
+  $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(poly1305_test crypto)
diff --git a/src/crypto/poly1305/poly1305_test.cc b/src/crypto/poly1305/poly1305_test.cc
new file mode 100644
index 0000000..0526075
--- /dev/null
+++ b/src/crypto/poly1305/poly1305_test.cc
@@ -0,0 +1,81 @@
+/* Copyright (c) 2015, 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 <vector>
+
+#include <openssl/crypto.h>
+#include <openssl/poly1305.h>
+
+#include "../test/file_test.h"
+#include "../test/stl_compat.h"
+
+
+// |CRYPTO_poly1305_finish| requires a 16-byte-aligned output.
+#if defined(OPENSSL_WINDOWS)
+// MSVC doesn't support C++11 |alignas|.
+#define ALIGNED __declspec(align(16))
+#else
+#define ALIGNED alignas(16)
+#endif
+
+static bool TestPoly1305(FileTest *t, void *arg) {
+  std::vector<uint8_t> key, in, mac;
+  if (!t->GetBytes(&key, "Key") ||
+      !t->GetBytes(&in, "Input") ||
+      !t->GetBytes(&mac, "MAC")) {
+    return false;
+  }
+  if (key.size() != 32 || mac.size() != 16) {
+    t->PrintLine("Invalid test");
+    return false;
+  }
+
+  // Test single-shot operation.
+  poly1305_state state;
+  CRYPTO_poly1305_init(&state, bssl::vector_data(&key));
+  CRYPTO_poly1305_update(&state, bssl::vector_data(&in), in.size());
+  ALIGNED uint8_t out[16];
+  CRYPTO_poly1305_finish(&state, out);
+  if (!t->ExpectBytesEqual(out, 16, bssl::vector_data(&mac), mac.size())) {
+    t->PrintLine("Single-shot Poly1305 failed.");
+    return false;
+  }
+
+  // Test streaming byte-by-byte.
+  CRYPTO_poly1305_init(&state, bssl::vector_data(&key));
+  for (size_t i = 0; i < in.size(); i++) {
+    CRYPTO_poly1305_update(&state, &in[i], 1);
+  }
+  CRYPTO_poly1305_finish(&state, out);
+  if (!t->ExpectBytesEqual(out, 16, bssl::vector_data(&mac), mac.size())) {
+    t->PrintLine("Streaming Poly1305 failed.");
+    return false;
+  }
+
+  return true;
+}
+
+int main(int argc, char **argv) {
+  CRYPTO_library_init();
+
+  if (argc != 2) {
+    fprintf(stderr, "%s <test file>\n", argv[0]);
+    return 1;
+  }
+
+  return FileTestMain(TestPoly1305, nullptr, argv[1]);
+}
diff --git a/src/crypto/poly1305/poly1305_test.txt b/src/crypto/poly1305/poly1305_test.txt
new file mode 100644
index 0000000..6c5d403
--- /dev/null
+++ b/src/crypto/poly1305/poly1305_test.txt
@@ -0,0 +1,52 @@
+# RFC 7359, section 2.5.2.
+
+Key = 85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b
+Input = "Cryptographic Forum Research Group"
+MAC = a8061dc1305136c6c22b8baf0c0127a9
+
+
+# RFC 7359, section A.3.
+
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+Input = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+MAC = 00000000000000000000000000000000
+
+Key = 0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e
+Input = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f
+MAC = 36e5f6b5c5e06070f0efca96227a863e
+
+Key = 36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000
+Input = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f
+MAC = f3477e7cd95417af89a6b8794c310cf0
+
+Key = 1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0
+Input = 2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e642067696d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e6420746865206d6f6d65207261746873206f757467726162652e
+MAC = 4541669a7eaaee61e708dc7cbcc5eb62
+
+Key = 0200000000000000000000000000000000000000000000000000000000000000
+Input = ffffffffffffffffffffffffffffffff
+MAC = 03000000000000000000000000000000
+
+Key = 02000000000000000000000000000000ffffffffffffffffffffffffffffffff
+Input = 02000000000000000000000000000000
+MAC = 03000000000000000000000000000000
+
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+Input = fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff11000000000000000000000000000000
+MAC = 05000000000000000000000000000000
+
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+Input = fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe01010101010101010101010101010101
+MAC = 00000000000000000000000000000000
+
+Key = 0200000000000000000000000000000000000000000000000000000000000000
+Input = fdffffffffffffffffffffffffffffff
+MAC = faffffffffffffffffffffffffffffff
+
+Key = 0100000000000000040000000000000000000000000000000000000000000000
+Input = e33594d7505e43b900000000000000003394d7505e4379cd01000000000000000000000000000000000000000000000001000000000000000000000000000000
+MAC = 14000000000000005500000000000000
+
+Key = 0100000000000000040000000000000000000000000000000000000000000000
+Input = e33594d7505e43b900000000000000003394d7505e4379cd010000000000000000000000000000000000000000000000
+MAC = 13000000000000000000000000000000
diff --git a/src/crypto/rand/CMakeLists.txt b/src/crypto/rand/CMakeLists.txt
index 374d8f1..35d5290 100644
--- a/src/crypto/rand/CMakeLists.txt
+++ b/src/crypto/rand/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 if (${ARCH} STREQUAL "x86_64")
   set(
diff --git a/src/crypto/rand/hwrand.c b/src/crypto/rand/hwrand.c
index 5f81f09..f0bbccd 100644
--- a/src/crypto/rand/hwrand.c
+++ b/src/crypto/rand/hwrand.c
@@ -15,23 +15,28 @@
 #include <openssl/rand.h>
 
 #include <assert.h>
-#include <stdlib.h>
 #include <string.h>
 
 #include <openssl/cpu.h>
 
+#include "internal.h"
+
 
 #if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM)
 
-int CRYPTO_have_hwrand(void) {
-  return (OPENSSL_ia32cap_P[1] & (1u << 30)) != 0;
-}
-
 /* These functions are defined in asm/rdrand-x86_64.pl */
 extern int CRYPTO_rdrand(uint8_t out[8]);
 extern int CRYPTO_rdrand_multiple8_buf(uint8_t *buf, size_t len);
 
+static int have_rdrand(void) {
+  return (OPENSSL_ia32cap_P[1] & (1u << 30)) != 0;
+}
+
 int CRYPTO_hwrand(uint8_t *buf, size_t len) {
+  if (!have_rdrand()) {
+    return 0;
+  }
+
   const size_t len_multiple8 = len & ~7;
   if (!CRYPTO_rdrand_multiple8_buf(buf, len_multiple8)) {
     return 0;
@@ -53,12 +58,8 @@
 
 #else
 
-int CRYPTO_have_hwrand(void) {
+int CRYPTO_hwrand(uint8_t *buf, size_t len) {
   return 0;
 }
 
-void CRYPTO_hwrand(uint8_t *buf, size_t len) {
-  abort();
-}
-
 #endif
diff --git a/src/crypto/rand/internal.h b/src/crypto/rand/internal.h
index 5e6ea11..f35abbb 100644
--- a/src/crypto/rand/internal.h
+++ b/src/crypto/rand/internal.h
@@ -24,13 +24,9 @@
  * system. */
 void CRYPTO_sysrand(uint8_t *buf, size_t len);
 
-/* CRYPTO_have_hwrand returns one iff |CRYPTO_hwrand| can be called to generate
- * hardware entropy. */
-int CRYPTO_have_hwrand(void);
-
-/* CRYPTO_hwrand fills |len| bytes at |buf| with entropy from the hardware.
- * This function can only be called if |CRYPTO_have_hwrand| returns one.
- * It returns one on success or zero on hardware failure. */
+/* CRYPTO_hwrand fills |len| bytes at |buf| with entropy from the hardware. It
+ * returns one on success or zero on hardware failure or if hardware support is
+ * unavailable. */
 int CRYPTO_hwrand(uint8_t *buf, size_t len);
 
 
diff --git a/src/crypto/rand/rand.c b/src/crypto/rand/rand.c
index a96ac48..e76a120 100644
--- a/src/crypto/rand/rand.c
+++ b/src/crypto/rand/rand.c
@@ -17,6 +17,7 @@
 #include <limits.h>
 #include <string.h>
 
+#include <openssl/chacha.h>
 #include <openssl/mem.h>
 
 #include "internal.h"
@@ -69,17 +70,12 @@
   OPENSSL_free(state);
 }
 
-extern void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
-                             const uint8_t key[32], const uint8_t nonce[8],
-                             size_t counter);
-
 int RAND_bytes(uint8_t *buf, size_t len) {
   if (len == 0) {
     return 1;
   }
 
-  if (!CRYPTO_have_hwrand() ||
-      !CRYPTO_hwrand(buf, len)) {
+  if (!CRYPTO_hwrand(buf, len)) {
     /* Without a hardware RNG to save us from address-space duplication, the OS
      * entropy is used directly. */
     CRYPTO_sysrand(buf, len);
@@ -162,6 +158,10 @@
 
 void RAND_add(const void *buf, int num, double entropy) {}
 
+int RAND_egd(const char *path) {
+  return 255;
+}
+
 int RAND_poll(void) {
   return 1;
 }
@@ -169,3 +169,18 @@
 int RAND_status(void) {
   return 1;
 }
+
+static const struct rand_meth_st kSSLeayMethod = {
+  RAND_seed,
+  RAND_bytes,
+  RAND_cleanup,
+  RAND_add,
+  RAND_pseudo_bytes,
+  RAND_status,
+};
+
+RAND_METHOD *RAND_SSLeay(void) {
+  return (RAND_METHOD*) &kSSLeayMethod;
+}
+
+void RAND_set_rand_method(const RAND_METHOD *method) {}
diff --git a/src/crypto/rand/urandom.c b/src/crypto/rand/urandom.c
index 788a979..1cc5260 100644
--- a/src/crypto/rand/urandom.c
+++ b/src/crypto/rand/urandom.c
@@ -30,92 +30,126 @@
 
 
 /* This file implements a PRNG by reading from /dev/urandom, optionally with a
- * fork-safe buffer.
- *
- * If buffering is enabled then it maintains a global, linked list of buffers.
- * Threads which need random bytes grab a buffer from the list under a lock and
- * copy out the bytes that they need. In the rare case that the buffer is
- * empty, it's refilled from /dev/urandom outside of the lock.
- *
- * Large requests are always serviced from /dev/urandom directly.
- *
- * Each buffer contains the PID of the process that created it and it's tested
- * against the current PID each time. Thus processes that fork will discard all
- * the buffers filled by the parent process. There are two problems with this:
- *
- * 1) glibc maintains a cache of the current PID+PPID and, if this cache isn't
- *    correctly invalidated, the getpid() will continue to believe that
- *    it's the old process. Glibc depends on the glibc wrappers for fork,
- *    vfork and clone being used in order to invalidate the getpid() cache.
- *
- * 2) If a process forks, dies and then its child forks, it's possible that
- *    the third process will end up with the same PID as the original process.
- *    If the second process never used any random values then this will mean
- *    that the third process has stale, cached values and won't notice.
- */
+ * buffer, which is unsafe across |fork|. */
 
-/* BUF_SIZE is intended to be a 4K allocation with malloc overhead. struct
- * rand_buffer also fits in this space and the remainder is entropy. */
-#define BUF_SIZE (4096 - 16)
+#define BUF_SIZE 4096
 
-/* rand_buffer contains unused, random bytes. These structures form a linked
- * list via the |next| pointer, which is NULL in the final element. */
+/* rand_buffer contains unused, random bytes, some of which may have been
+ * consumed already. */
 struct rand_buffer {
-  size_t used; /* used contains the number of bytes of |rand| that have
-                  been consumed. */
-  struct rand_buffer *next;
-  pid_t pid; /* pid contains the pid at the time that the buffer was
-                created so that data is not duplicated after a fork. */
-  pid_t ppid; /* ppid contains the parent pid in order to try and reduce
-                 the possibility of duplicated PID confusing the
-                 detection of a fork. */
-  uint8_t rand[];
+  size_t used;
+  uint8_t rand[BUF_SIZE];
 };
 
-/* rand_bytes_per_buf is the number of actual entropy bytes in a buffer. */
-static const size_t rand_bytes_per_buf = BUF_SIZE - sizeof(struct rand_buffer);
+/* requested_lock is used to protect the |*_requested| variables. */
+static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT;
 
-static struct CRYPTO_STATIC_MUTEX global_lock = CRYPTO_STATIC_MUTEX_INIT;
+/* urandom_fd_requested is set by |RAND_set_urandom_fd|.  It's protected by
+ * |requested_lock|. */
+static int urandom_fd_requested = -2;
 
-/* list_head is the start of a global, linked-list of rand_buffer objects. It's
- * protected by |global_lock|. */
-static struct rand_buffer *list_head;
-
-/* urandom_fd is a file descriptor to /dev/urandom. It's protected by
- * |global_lock|. */
+/* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */
 static int urandom_fd = -2;
 
+/* urandom_buffering_requested is set by |RAND_enable_fork_unsafe_buffering|.
+ * It's protected by |requested_lock|. */
+static int urandom_buffering_requested = 0;
+
 /* urandom_buffering controls whether buffering is enabled (1) or not (0). This
- * is protected by |global_lock|. */
+ * is protected by |once|. */
 static int urandom_buffering = 0;
 
-/* urandom_get_fd_locked returns a file descriptor to /dev/urandom. The caller
- * of this function must hold |global_lock|. */
-static int urandom_get_fd_locked(void) {
-  if (urandom_fd != -2) {
-    return urandom_fd;
+static CRYPTO_once_t once = CRYPTO_ONCE_INIT;
+
+/* init_once initializes the state of this module to values previously
+ * requested. This is the only function that modifies |urandom_fd| and
+ * |urandom_buffering|, whose values may be read safely after calling the
+ * once. */
+static void init_once(void) {
+  CRYPTO_STATIC_MUTEX_lock_read(&requested_lock);
+  urandom_buffering = urandom_buffering_requested;
+  int fd = urandom_fd_requested;
+  CRYPTO_STATIC_MUTEX_unlock(&requested_lock);
+
+  if (fd == -2) {
+    do {
+      fd = open("/dev/urandom", O_RDONLY);
+    } while (fd == -1 && errno == EINTR);
   }
 
-  urandom_fd = open("/dev/urandom", O_RDONLY);
-  return urandom_fd;
+  if (fd < 0) {
+    abort();
+  }
+
+  int flags = fcntl(fd, F_GETFD);
+  if (flags == -1) {
+    abort();
+  }
+  flags |= FD_CLOEXEC;
+  if (fcntl(fd, F_SETFD, flags) == -1) {
+    abort();
+  }
+  urandom_fd = fd;
 }
 
-/* RAND_cleanup frees all buffers, closes any cached file descriptor
- * and resets the global state. */
-void RAND_cleanup(void) {
-  struct rand_buffer *cur;
+void RAND_cleanup(void) {}
 
-  CRYPTO_STATIC_MUTEX_lock_write(&global_lock);
-  while ((cur = list_head)) {
-    list_head = cur->next;
-    OPENSSL_free(cur);
+void RAND_set_urandom_fd(int fd) {
+  fd = dup(fd);
+  if (fd < 0) {
+    abort();
   }
-  if (urandom_fd >= 0) {
-    close(urandom_fd);
+
+  CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
+  urandom_fd_requested = fd;
+  CRYPTO_STATIC_MUTEX_unlock(&requested_lock);
+
+  CRYPTO_once(&once, init_once);
+  if (urandom_fd != fd) {
+    abort();  // Already initialized.
   }
-  urandom_fd = -2;
-  list_head = NULL;
-  CRYPTO_STATIC_MUTEX_unlock(&global_lock);
+}
+
+void RAND_enable_fork_unsafe_buffering(int fd) {
+  if (fd >= 0) {
+    fd = dup(fd);
+    if (fd < 0) {
+      abort();
+    }
+  } else {
+    fd = -2;
+  }
+
+  CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
+  urandom_buffering_requested = 1;
+  urandom_fd_requested = fd;
+  CRYPTO_STATIC_MUTEX_unlock(&requested_lock);
+
+  CRYPTO_once(&once, init_once);
+  if (urandom_buffering != 1 || (fd >= 0 && urandom_fd != fd)) {
+    abort();  // Already initialized.
+  }
+}
+
+static struct rand_buffer *get_thread_local_buffer(void) {
+  struct rand_buffer *buf =
+      CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF);
+  if (buf != NULL) {
+    return buf;
+  }
+
+  buf = OPENSSL_malloc(sizeof(struct rand_buffer));
+  if (buf == NULL) {
+    return NULL;
+  }
+  buf->used = BUF_SIZE;  /* To trigger a |read_full| on first use. */
+  if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF, buf,
+                               OPENSSL_free)) {
+    OPENSSL_free(buf);
+    return NULL;
+  }
+
+  return buf;
 }
 
 /* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In
@@ -138,110 +172,48 @@
   return 1;
 }
 
-/* CRYPTO_sysrand puts |num| random bytes into |out|. */
-void CRYPTO_sysrand(uint8_t *out, size_t requested) {
-  int fd;
-  struct rand_buffer *buf;
-  size_t todo;
-  pid_t pid, ppid;
+/* read_from_buffer reads |requested| random bytes from the buffer into |out|,
+ * refilling it if necessary to satisfy the request. */
+static void read_from_buffer(struct rand_buffer *buf,
+                             uint8_t *out, size_t requested) {
+  size_t remaining = BUF_SIZE - buf->used;
 
+  while (requested > remaining) {
+    memcpy(out, &buf->rand[buf->used], remaining);
+    buf->used += remaining;
+    out += remaining;
+    requested -= remaining;
+
+    if (!read_full(urandom_fd, buf->rand, BUF_SIZE)) {
+      abort();
+      return;
+    }
+    buf->used = 0;
+    remaining = BUF_SIZE;
+  }
+
+  memcpy(out, &buf->rand[buf->used], requested);
+  buf->used += requested;
+}
+
+/* CRYPTO_sysrand puts |requested| random bytes into |out|. */
+void CRYPTO_sysrand(uint8_t *out, size_t requested) {
   if (requested == 0) {
     return;
   }
 
-  CRYPTO_STATIC_MUTEX_lock_write(&global_lock);
-  fd = urandom_get_fd_locked();
+  CRYPTO_once(&once, init_once);
+  if (urandom_buffering && requested < BUF_SIZE) {
+    struct rand_buffer *buf = get_thread_local_buffer();
+    if (buf != NULL) {
+      read_from_buffer(buf, out, requested);
+      return;
+    }
+  }
 
-  if (fd < 0) {
-    CRYPTO_STATIC_MUTEX_unlock(&global_lock);
+  if (!read_full(urandom_fd, out, requested)) {
     abort();
-    return;
   }
-
-  /* If buffering is not enabled, or if the request is large, then the
-   * result comes directly from urandom. */
-  if (!urandom_buffering || requested > BUF_SIZE / 2) {
-    CRYPTO_STATIC_MUTEX_unlock(&global_lock);
-    if (!read_full(fd, out, requested)) {
-      abort();
-    }
-    return;
-  }
-
-  pid = getpid();
-  ppid = getppid();
-
-  for (;;) {
-    buf = list_head;
-    if (buf && buf->pid == pid && buf->ppid == ppid &&
-        rand_bytes_per_buf - buf->used >= requested) {
-      memcpy(out, &buf->rand[buf->used], requested);
-      buf->used += requested;
-      CRYPTO_STATIC_MUTEX_unlock(&global_lock);
-      return;
-    }
-
-    /* If we don't immediately have enough entropy with the correct
-     * PID, remove the buffer from the list in order to gain
-     * exclusive access and unlock. */
-    if (buf) {
-      list_head = buf->next;
-    }
-    CRYPTO_STATIC_MUTEX_unlock(&global_lock);
-
-    if (!buf) {
-      buf = (struct rand_buffer *)OPENSSL_malloc(BUF_SIZE);
-      if (!buf) {
-        abort();
-        return;
-      }
-      /* The buffer doesn't contain any random bytes yet
-       * so we mark it as fully used so that it will be
-       * filled below. */
-      buf->used = rand_bytes_per_buf;
-      buf->next = NULL;
-      buf->pid = pid;
-      buf->ppid = ppid;
-    }
-
-    if (buf->pid == pid && buf->ppid == ppid) {
-      break;
-    }
-
-    /* We have forked and so cannot use these bytes as they
-     * may have been used in another process. */
-    OPENSSL_free(buf);
-    CRYPTO_STATIC_MUTEX_lock_write(&global_lock);
-  }
-
-  while (requested > 0) {
-    todo = rand_bytes_per_buf - buf->used;
-    if (todo > requested) {
-      todo = requested;
-    }
-    memcpy(out, &buf->rand[buf->used], todo);
-    requested -= todo;
-    out += todo;
-    buf->used += todo;
-
-    if (buf->used < rand_bytes_per_buf) {
-      break;
-    }
-
-    if (!read_full(fd, buf->rand, rand_bytes_per_buf)) {
-      OPENSSL_free(buf);
-      abort();
-      return;
-    }
-
-    buf->used = 0;
-  }
-
-  CRYPTO_STATIC_MUTEX_lock_write(&global_lock);
-  assert(list_head != buf);
-  buf->next = list_head;
-  list_head = buf;
-  CRYPTO_STATIC_MUTEX_unlock(&global_lock);
 }
 
 #endif  /* !OPENSSL_WINDOWS */
diff --git a/src/crypto/rc4/CMakeLists.txt b/src/crypto/rc4/CMakeLists.txt
index fe2d0c6..a208e96 100644
--- a/src/crypto/rc4/CMakeLists.txt
+++ b/src/crypto/rc4/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 if (${ARCH} STREQUAL "x86_64")
   set(
diff --git a/src/crypto/rc4/asm/rc4-x86_64.pl b/src/crypto/rc4/asm/rc4-x86_64.pl
index db46242..cef6268 100644
--- a/src/crypto/rc4/asm/rc4-x86_64.pl
+++ b/src/crypto/rc4/asm/rc4-x86_64.pl
@@ -56,7 +56,7 @@
 # achieves respectful 432MBps on 2.8GHz processor now. For reference.
 # If executed on Xeon, current RC4_CHAR code-path is 2.7x faster than
 # RC4_INT code-path. While if executed on Opteron, it's only 25%
-# slower than the RC4_INT one [meaning that if CPU µ-arch detection
+# slower than the RC4_INT one [meaning that if CPU µ-arch detection
 # is not implemented, then this final RC4_CHAR code-path should be
 # preferred, as it provides better *all-round* performance].
 
diff --git a/src/crypto/rsa/CMakeLists.txt b/src/crypto/rsa/CMakeLists.txt
index 0ea12c8..bd8ad3b 100644
--- a/src/crypto/rsa/CMakeLists.txt
+++ b/src/crypto/rsa/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   rsa
@@ -15,7 +15,7 @@
 add_executable(
   rsa_test
 
-  rsa_test.c
+  rsa_test.cc
 
   $<TARGET_OBJECTS:test_support>
 )
diff --git a/src/crypto/rsa/blinding.c b/src/crypto/rsa/blinding.c
index 245142b..c93cee1 100644
--- a/src/crypto/rsa/blinding.c
+++ b/src/crypto/rsa/blinding.c
@@ -137,7 +137,7 @@
 
   ret = (BN_BLINDING*) OPENSSL_malloc(sizeof(BN_BLINDING));
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(RSA, BN_BLINDING_new, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
   memset(ret, 0, sizeof(BN_BLINDING));
@@ -190,7 +190,7 @@
   int ret = 0;
 
   if (b->A == NULL || b->Ai == NULL) {
-    OPENSSL_PUT_ERROR(RSA, BN_BLINDING_update, RSA_R_BN_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED);
     goto err;
   }
 
@@ -230,7 +230,7 @@
   int ret = 1;
 
   if (b->A == NULL || b->Ai == NULL) {
-    OPENSSL_PUT_ERROR(RSA, BN_BLINDING_convert_ex, RSA_R_BN_NOT_INITIALIZED);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED);
     return 0;
   }
 
@@ -266,7 +266,7 @@
     ret = BN_mod_mul(n, n, r, b->mod, ctx);
   } else {
     if (b->Ai == NULL) {
-      OPENSSL_PUT_ERROR(RSA, BN_BLINDING_invert_ex, RSA_R_BN_NOT_INITIALIZED);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED);
       return 0;
     }
     ret = BN_mod_mul(n, n, b->Ai, b->mod, ctx);
@@ -325,13 +325,13 @@
     if (!BN_rand_range(ret->A, ret->mod)) {
       goto err;
     }
-    if (BN_mod_inverse(ret->Ai, ret->A, ret->mod, ctx) == NULL) {
+
+    int no_inverse;
+    if (BN_mod_inverse_ex(ret->Ai, &no_inverse, ret->A, ret->mod, ctx) == NULL) {
       /* this should almost never happen for good RSA keys */
-      uint32_t error = ERR_peek_last_error();
-      if (ERR_GET_REASON(error) == BN_R_NO_INVERSE) {
+      if (no_inverse) {
         if (retry_counter-- == 0) {
-          OPENSSL_PUT_ERROR(RSA, BN_BLINDING_create_param,
-                            RSA_R_TOO_MANY_ITERATIONS);
+          OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS);
           goto err;
         }
         ERR_clear_error();
@@ -416,14 +416,14 @@
   BN_CTX_start(ctx);
   e = BN_CTX_get(ctx);
   if (e == NULL) {
-    OPENSSL_PUT_ERROR(RSA, rsa_setup_blinding, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
   if (rsa->e == NULL) {
     e = rsa_get_public_exp(rsa->d, rsa->p, rsa->q, ctx);
     if (e == NULL) {
-      OPENSSL_PUT_ERROR(RSA, rsa_setup_blinding, RSA_R_NO_PUBLIC_EXPONENT);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_NO_PUBLIC_EXPONENT);
       goto err;
     }
   } else {
@@ -444,7 +444,7 @@
   ret = BN_BLINDING_create_param(NULL, e, n, ctx, rsa->meth->bn_mod_exp,
                                  mont_ctx);
   if (ret == NULL) {
-    OPENSSL_PUT_ERROR(RSA, rsa_setup_blinding, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB);
     goto err;
   }
 
diff --git a/src/crypto/rsa/internal.h b/src/crypto/rsa/internal.h
index d15f2a5..c0044c3 100644
--- a/src/crypto/rsa/internal.h
+++ b/src/crypto/rsa/internal.h
@@ -59,8 +59,6 @@
 
 #include <openssl/base.h>
 
-#include <openssl/asn1.h>
-
 
 #if defined(__cplusplus)
 extern "C" {
@@ -109,8 +107,6 @@
                                       const EVP_MD *md, const EVP_MD *mgf1md);
 int RSA_padding_add_none(uint8_t *to, unsigned to_len, const uint8_t *from,
                          unsigned from_len);
-int RSA_padding_check_none(uint8_t *to, unsigned to_len, const uint8_t *from,
-                           unsigned from_len);
 
 /* RSA_private_transform calls either the method-specific |private_transform|
  * function (if given) or the generic one. See the comment for
@@ -118,20 +114,26 @@
 int RSA_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
                           size_t len);
 
-typedef struct rsa_pss_params_st {
-  X509_ALGOR *hashAlgorithm;
-  X509_ALGOR *maskGenAlgorithm;
-  ASN1_INTEGER *saltLength;
-  ASN1_INTEGER *trailerField;
-} RSA_PSS_PARAMS;
 
-DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS)
+/* RSA_additional_prime contains information about the third, forth etc prime
+ * in a multi-prime RSA key. */
+typedef struct RSA_additional_prime_st {
+  BIGNUM *prime;
+  /* exp is d^{prime-1} mod prime */
+  BIGNUM *exp;
+  /* coeff is such that r×coeff ≡ 1 mod prime. */
+  BIGNUM *coeff;
 
-typedef struct rsa_oaep_params_st {
-  X509_ALGOR *hashFunc;
-  X509_ALGOR *maskGenFunc;
-  X509_ALGOR *pSourceFunc;
-} RSA_OAEP_PARAMS;
+  /* Values below here are not in the ASN.1 serialisation. */
+
+  /* r is the product of all primes (including p and q) prior to this one. */
+  BIGNUM *r;
+  /* method_mod is managed by the |RSA_METHOD|. */
+  BN_MONT_CTX *method_mod;
+} RSA_additional_prime;
+
+void RSA_additional_prime_free(RSA_additional_prime *ap);
+
 
 #if defined(__cplusplus)
 } /* extern C */
diff --git a/src/crypto/rsa/padding.c b/src/crypto/rsa/padding.c
index 0a725f1..5a42e24 100644
--- a/src/crypto/rsa/padding.c
+++ b/src/crypto/rsa/padding.c
@@ -74,14 +74,12 @@
   uint8_t *p;
 
   if (tlen < RSA_PKCS1_PADDING_SIZE) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_type_1,
-                      RSA_R_KEY_SIZE_TOO_SMALL);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
     return 0;
   }
 
   if (flen > tlen - RSA_PKCS1_PADDING_SIZE) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_type_1,
-                      RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
     return 0;
   }
 
@@ -105,15 +103,13 @@
   const uint8_t *p;
 
   if (flen < 2) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
-                      RSA_R_DATA_TOO_SMALL);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_SMALL);
     return -1;
   }
 
   p = from;
   if ((*(p++) != 0) || (*(p++) != 1)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
-                      RSA_R_BLOCK_TYPE_IS_NOT_01);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BLOCK_TYPE_IS_NOT_01);
     return -1;
   }
 
@@ -126,8 +122,7 @@
         p++;
         break;
       } else {
-        OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
-                          RSA_R_BAD_FIXED_HEADER_DECRYPT);
+        OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_FIXED_HEADER_DECRYPT);
         return -1;
       }
     }
@@ -135,21 +130,18 @@
   }
 
   if (i == j) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
-                      RSA_R_NULL_BEFORE_BLOCK_MISSING);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_NULL_BEFORE_BLOCK_MISSING);
     return -1;
   }
 
   if (i < 8) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
-                      RSA_R_BAD_PAD_BYTE_COUNT);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_PAD_BYTE_COUNT);
     return -1;
   }
   i++; /* Skip over the '\0' */
   j -= i;
   if (j > tlen) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
-                      RSA_R_DATA_TOO_LARGE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE);
     return -1;
   }
   memcpy(to, p, j);
@@ -163,14 +155,12 @@
   uint8_t *p;
 
   if (tlen < RSA_PKCS1_PADDING_SIZE) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_type_2,
-                      RSA_R_KEY_SIZE_TOO_SMALL);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
     return 0;
   }
 
   if (flen > tlen - RSA_PKCS1_PADDING_SIZE) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_type_2,
-                      RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
     return 0;
   }
 
@@ -271,8 +261,7 @@
   size_t msg_index, msg_len;
 
   if (flen == 0) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
-                      RSA_R_EMPTY_PUBLIC_KEY);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY);
     return -1;
   }
 
@@ -281,8 +270,7 @@
    * |RSA_PKCS1_PADDING| make it impossible to completely avoid Bleichenbacher's
    * attack. */
   if (!RSA_message_index_PKCS1_type_2(from, flen, &msg_index)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
-                      RSA_R_PKCS_DECODING_ERROR);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR);
     return -1;
   }
 
@@ -290,8 +278,7 @@
   if (msg_len > tlen) {
     /* This shouldn't happen because this function is always called with |tlen|
      * the key size and |flen| is bounded by the key size. */
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
-                      RSA_R_PKCS_DECODING_ERROR);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR);
     return -1;
   }
   memcpy(to, &from[msg_index], msg_len);
@@ -300,14 +287,12 @@
 
 int RSA_padding_add_none(uint8_t *to, unsigned tlen, const uint8_t *from, unsigned flen) {
   if (flen > tlen) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_none,
-                      RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
     return 0;
   }
 
   if (flen < tlen) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_none,
-                      RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE);
     return 0;
   }
 
@@ -315,17 +300,6 @@
   return 1;
 }
 
-int RSA_padding_check_none(uint8_t *to, unsigned tlen, const uint8_t *from,
-                           unsigned flen) {
-  if (flen > tlen) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_none, RSA_R_DATA_TOO_LARGE);
-    return -1;
-  }
-
-  memcpy(to, from, flen);
-  return flen;
-}
-
 int PKCS1_MGF1(uint8_t *mask, unsigned len, const uint8_t *seed,
                unsigned seedlen, const EVP_MD *dgst) {
   unsigned outlen = 0;
@@ -388,21 +362,18 @@
   mdlen = EVP_MD_size(md);
 
   if (tlen < 2 * mdlen + 2) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
-                      RSA_R_KEY_SIZE_TOO_SMALL);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
     return 0;
   }
 
   emlen = tlen - 1;
   if (flen > emlen - 2 * mdlen - 1) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
-                      RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
     return 0;
   }
 
   if (emlen < 2 * mdlen + 1) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
-                      RSA_R_KEY_SIZE_TOO_SMALL);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
     return 0;
   }
 
@@ -422,8 +393,7 @@
 
   dbmask = OPENSSL_malloc(emlen - mdlen);
   if (dbmask == NULL) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
-                      ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -477,8 +447,7 @@
   dblen = flen - mdlen - 1;
   db = OPENSSL_malloc(dblen);
   if (db == NULL) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_OAEP_mgf1,
-                      ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -526,8 +495,7 @@
   one_index++;
   mlen = dblen - one_index;
   if (tlen < mlen) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_OAEP_mgf1,
-                      RSA_R_DATA_TOO_LARGE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE);
     mlen = -1;
   } else {
     memcpy(to, db + one_index, mlen);
@@ -539,8 +507,7 @@
 decoding_err:
   /* to avoid chosen ciphertext attacks, the error message should not reveal
    * which kind of decoding error happened */
-  OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_OAEP_mgf1,
-                    RSA_R_OAEP_DECODING_ERROR);
+  OPENSSL_PUT_ERROR(RSA, RSA_R_OAEP_DECODING_ERROR);
  err:
   OPENSSL_free(db);
   return -1;
@@ -576,15 +543,14 @@
   } else if (sLen == -2) {
     sLen = -2;
   } else if (sLen < -2) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_SLEN_CHECK_FAILED);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED);
     goto err;
   }
 
   MSBits = (BN_num_bits(rsa->n) - 1) & 0x7;
   emLen = RSA_size(rsa);
   if (EM[0] & (0xFF << MSBits)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1,
-                      RSA_R_FIRST_OCTET_INVALID);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_FIRST_OCTET_INVALID);
     goto err;
   }
   if (MSBits == 0) {
@@ -593,18 +559,18 @@
   }
   if (emLen < ((int)hLen + sLen + 2)) {
     /* sLen can be small negative */
-    OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_DATA_TOO_LARGE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE);
     goto err;
   }
   if (EM[emLen - 1] != 0xbc) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_LAST_OCTET_INVALID);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_LAST_OCTET_INVALID);
     goto err;
   }
   maskedDBLen = emLen - hLen - 1;
   H = EM + maskedDBLen;
   DB = OPENSSL_malloc(maskedDBLen);
   if (!DB) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
   if (PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0) {
@@ -620,12 +586,11 @@
     ;
   }
   if (DB[i++] != 0x1) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1,
-                      RSA_R_SLEN_RECOVERY_FAILED);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_RECOVERY_FAILED);
     goto err;
   }
   if (sLen >= 0 && (maskedDBLen - i) != sLen) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_SLEN_CHECK_FAILED);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED);
     goto err;
   }
   if (!EVP_DigestInit_ex(&ctx, Hash, NULL) ||
@@ -642,7 +607,7 @@
     goto err;
   }
   if (memcmp(H_, H, hLen)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_BAD_SIGNATURE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE);
     ret = 0;
   } else {
     ret = 1;
@@ -681,14 +646,12 @@
   } else if (sLen == -2) {
     sLen = -2;
   } else if (sLen < -2) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
-                      RSA_R_SLEN_CHECK_FAILED);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED);
     goto err;
   }
 
   if (BN_is_zero(rsa->n)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
-                      RSA_R_EMPTY_PUBLIC_KEY);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY);
     goto err;
   }
 
@@ -701,21 +664,18 @@
   }
   if (sLen == -2) {
     if (emLen < hLen + 2) {
-      OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
-                        RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
       goto err;
     }
     sLen = emLen - hLen - 2;
   } else if (emLen < hLen + sLen + 2) {
-    OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
-                      RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
     goto err;
   }
   if (sLen > 0) {
     salt = OPENSSL_malloc(sLen);
     if (!salt) {
-      OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
-                        ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
       goto err;
     }
     if (!RAND_bytes(salt, sLen)) {
diff --git a/src/crypto/rsa/rsa.c b/src/crypto/rsa/rsa.c
index 17059b0..2f23165 100644
--- a/src/crypto/rsa/rsa.c
+++ b/src/crypto/rsa/rsa.c
@@ -79,7 +79,7 @@
 RSA *RSA_new_method(const ENGINE *engine) {
   RSA *rsa = (RSA *)OPENSSL_malloc(sizeof(RSA));
   if (rsa == NULL) {
-    OPENSSL_PUT_ERROR(RSA, RSA_new_method, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     return NULL;
   }
 
@@ -114,6 +114,18 @@
   return rsa;
 }
 
+void RSA_additional_prime_free(RSA_additional_prime *ap) {
+  if (ap == NULL) {
+    return;
+  }
+
+  BN_clear_free(ap->prime);
+  BN_clear_free(ap->exp);
+  BN_clear_free(ap->coeff);
+  BN_clear_free(ap->r);
+  OPENSSL_free(ap);
+}
+
 void RSA_free(RSA *rsa) {
   unsigned u;
 
@@ -145,6 +157,10 @@
   }
   OPENSSL_free(rsa->blindings);
   OPENSSL_free(rsa->blindings_inuse);
+  if (rsa->additional_primes != NULL) {
+    sk_RSA_additional_prime_pop_free(rsa->additional_primes,
+                                     RSA_additional_prime_free);
+  }
   CRYPTO_MUTEX_cleanup(&rsa->lock);
   OPENSSL_free(rsa);
 }
@@ -162,6 +178,16 @@
   return RSA_default_method.keygen(rsa, bits, e_value, cb);
 }
 
+int RSA_generate_multi_prime_key(RSA *rsa, int bits, int num_primes,
+                                 BIGNUM *e_value, BN_GENCB *cb) {
+  if (rsa->meth->multi_prime_keygen) {
+    return rsa->meth->multi_prime_keygen(rsa, bits, num_primes, e_value, cb);
+  }
+
+  return RSA_default_method.multi_prime_keygen(rsa, bits, num_primes, e_value,
+                                               cb);
+}
+
 int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
                 const uint8_t *in, size_t in_len, int padding) {
   if (rsa->meth->encrypt) {
@@ -342,20 +368,15 @@
     },
 };
 
-/* TODO(fork): mostly new code, needs careful review. */
-
-/* pkcs1_prefixed_msg builds a PKCS#1, prefixed version of |msg| for the given
- * hash function and sets |out_msg| to point to it. On successful return,
- * |*out_msg| may be allocated memory and, if so, |*is_alloced| will be 1. */
-static int pkcs1_prefixed_msg(uint8_t **out_msg, size_t *out_msg_len,
-                              int *is_alloced, int hash_nid, const uint8_t *msg,
-                              size_t msg_len) {
+int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len,
+                         int *is_alloced, int hash_nid, const uint8_t *msg,
+                         size_t msg_len) {
   unsigned i;
 
   if (hash_nid == NID_md5_sha1) {
     /* Special case: SSL signature, just check the length. */
     if (msg_len != SSL_SIG_LENGTH) {
-      OPENSSL_PUT_ERROR(RSA, pkcs1_prefixed_msg, RSA_R_INVALID_MESSAGE_LENGTH);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
       return 0;
     }
 
@@ -378,13 +399,13 @@
 
     signed_msg_len = prefix_len + msg_len;
     if (signed_msg_len < prefix_len) {
-      OPENSSL_PUT_ERROR(RSA, pkcs1_prefixed_msg, RSA_R_TOO_LONG);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_LONG);
       return 0;
     }
 
     signed_msg = OPENSSL_malloc(signed_msg_len);
     if (!signed_msg) {
-      OPENSSL_PUT_ERROR(RSA, pkcs1_prefixed_msg, ERR_R_MALLOC_FAILURE);
+      OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
       return 0;
     }
 
@@ -398,7 +419,7 @@
     return 1;
   }
 
-  OPENSSL_PUT_ERROR(RSA, pkcs1_prefixed_msg, RSA_R_UNKNOWN_ALGORITHM_TYPE);
+  OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE);
   return 0;
 }
 
@@ -415,14 +436,14 @@
     return rsa->meth->sign(hash_nid, in, in_len, out, out_len, rsa);
   }
 
-  if (!pkcs1_prefixed_msg(&signed_msg, &signed_msg_len, &signed_msg_is_alloced,
-                          hash_nid, in, in_len)) {
+  if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len,
+                            &signed_msg_is_alloced, hash_nid, in, in_len)) {
     return 0;
   }
 
   if (rsa_size < RSA_PKCS1_PADDING_SIZE ||
       signed_msg_len > rsa_size - RSA_PKCS1_PADDING_SIZE) {
-    OPENSSL_PUT_ERROR(RSA, RSA_sign, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
     goto finish;
   }
 
@@ -453,18 +474,18 @@
   }
 
   if (sig_len != rsa_size) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify, RSA_R_WRONG_SIGNATURE_LENGTH);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_WRONG_SIGNATURE_LENGTH);
     return 0;
   }
 
   if (hash_nid == NID_md5_sha1 && msg_len != SSL_SIG_LENGTH) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify, RSA_R_INVALID_MESSAGE_LENGTH);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
     return 0;
   }
 
   buf = OPENSSL_malloc(rsa_size);
   if (!buf) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -473,13 +494,13 @@
     goto out;
   }
 
-  if (!pkcs1_prefixed_msg(&signed_msg, &signed_msg_len, &signed_msg_is_alloced,
-                          hash_nid, msg, msg_len)) {
+  if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len,
+                            &signed_msg_is_alloced, hash_nid, msg, msg_len)) {
     goto out;
   }
 
   if (len != signed_msg_len || CRYPTO_memcmp(buf, signed_msg, len) != 0) {
-    OPENSSL_PUT_ERROR(RSA, RSA_verify, RSA_R_BAD_SIGNATURE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE);
     goto out;
   }
 
@@ -509,12 +530,12 @@
   }
 
   if ((key->p != NULL) != (key->q != NULL)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_ONLY_ONE_OF_P_Q_GIVEN);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_ONLY_ONE_OF_P_Q_GIVEN);
     return 0;
   }
 
   if (!key->n || !key->e) {
-    OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_VALUE_MISSING);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
     return 0;
   }
 
@@ -526,7 +547,7 @@
 
   ctx = BN_CTX_new();
   if (ctx == NULL) {
-    OPENSSL_PUT_ERROR(RSA, RSA_check_key, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -540,52 +561,74 @@
   BN_init(&dmq1);
   BN_init(&iqmp);
 
-  if (/* n = pq */
-      !BN_mul(&n, key->p, key->q, ctx) ||
-      /* lcm = lcm(p-1, q-1) */
+  if (!BN_mul(&n, key->p, key->q, ctx) ||
+      /* lcm = lcm(prime-1, for all primes) */
       !BN_sub(&pm1, key->p, BN_value_one()) ||
       !BN_sub(&qm1, key->q, BN_value_one()) ||
       !BN_mul(&lcm, &pm1, &qm1, ctx) ||
+      !BN_gcd(&gcd, &pm1, &qm1, ctx)) {
+    OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
+    goto out;
+  }
+
+  size_t num_additional_primes = 0;
+  if (key->additional_primes != NULL) {
+    num_additional_primes = sk_RSA_additional_prime_num(key->additional_primes);
+  }
+
+  size_t i;
+  for (i = 0; i < num_additional_primes; i++) {
+    const RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(key->additional_primes, i);
+    if (!BN_mul(&n, &n, ap->prime, ctx) ||
+        !BN_sub(&pm1, ap->prime, BN_value_one()) ||
+        !BN_mul(&lcm, &lcm, &pm1, ctx) ||
+        !BN_gcd(&gcd, &gcd, &pm1, ctx)) {
+      OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
+      goto out;
+    }
+  }
+
+  if (!BN_div(&lcm, NULL, &lcm, &gcd, ctx) ||
       !BN_gcd(&gcd, &pm1, &qm1, ctx) ||
-      !BN_div(&lcm, NULL, &lcm, &gcd, ctx) ||
-      /* de = d*e mod lcm(p-1, q-1) */
+      /* de = d*e mod lcm(prime-1, for all primes). */
       !BN_mod_mul(&de, key->d, key->e, &lcm, ctx)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_check_key, ERR_LIB_BN);
+    OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
     goto out;
   }
 
   if (BN_cmp(&n, key->n) != 0) {
-    OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_N_NOT_EQUAL_P_Q);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_N_NOT_EQUAL_P_Q);
     goto out;
   }
 
   if (!BN_is_one(&de)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_D_E_NOT_CONGRUENT_TO_1);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1);
     goto out;
   }
 
   has_crt_values = key->dmp1 != NULL;
   if (has_crt_values != (key->dmq1 != NULL) ||
       has_crt_values != (key->iqmp != NULL)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_INCONSISTENT_SET_OF_CRT_VALUES);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_INCONSISTENT_SET_OF_CRT_VALUES);
     goto out;
   }
 
-  if (has_crt_values) {
+  if (has_crt_values && num_additional_primes == 0) {
     if (/* dmp1 = d mod (p-1) */
         !BN_mod(&dmp1, key->d, &pm1, ctx) ||
         /* dmq1 = d mod (q-1) */
         !BN_mod(&dmq1, key->d, &qm1, ctx) ||
         /* iqmp = q^-1 mod p */
         !BN_mod_inverse(&iqmp, key->q, key->p, ctx)) {
-      OPENSSL_PUT_ERROR(RSA, RSA_check_key, ERR_LIB_BN);
+      OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
       goto out;
     }
 
     if (BN_cmp(&dmp1, key->dmp1) != 0 ||
         BN_cmp(&dmq1, key->dmq1) != 0 ||
         BN_cmp(&iqmp, key->iqmp) != 0) {
-      OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_CRT_VALUES_INCORRECT);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_VALUES_INCORRECT);
       goto out;
     }
   }
@@ -613,13 +656,17 @@
   int ok = 0;
 
   if (rsa->n == NULL || rsa->e == NULL || rsa->d == NULL) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, RSA_R_EMPTY_PUBLIC_KEY);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY);
     return 0;
   }
 
   if (rsa->p || rsa->q || rsa->dmp1 || rsa->dmq1 || rsa->iqmp) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params,
-                      RSA_R_CRT_PARAMS_ALREADY_GIVEN);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_PARAMS_ALREADY_GIVEN);
+    return 0;
+  }
+
+  if (rsa->additional_primes != NULL) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY);
     return 0;
   }
 
@@ -628,7 +675,7 @@
 
   ctx = BN_CTX_new();
   if (ctx == NULL) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     return 0;
   }
 
@@ -641,7 +688,7 @@
 
   if (totient == NULL || rem == NULL || multiple == NULL || p_plus_q == NULL ||
       p_minus_q == NULL) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -669,12 +716,12 @@
       !BN_div(multiple, NULL, totient, rsa->n, ctx) ||
       !BN_add_word(multiple, 1) ||
       !BN_div(totient, rem, totient, multiple, ctx)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB);
     goto err;
   }
 
   if (!BN_is_zero(rem)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, RSA_R_BAD_RSA_PARAMETERS);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_RSA_PARAMETERS);
     goto err;
   }
 
@@ -685,7 +732,7 @@
   rsa->iqmp = BN_new();
   if (rsa->p == NULL || rsa->q == NULL || rsa->dmp1 == NULL || rsa->dmq1 ==
       NULL || rsa->iqmp == NULL) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -703,12 +750,12 @@
       !BN_rshift1(rsa->q, rsa->q) ||
       !BN_div(rsa->p, NULL, rsa->n, rsa->q, ctx) ||
       !BN_mul(multiple, rsa->p, rsa->q, ctx)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB);
     goto err;
   }
 
   if (BN_cmp(multiple, rsa->n) != 0) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, RSA_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_INTERNAL_ERROR);
     goto err;
   }
 
@@ -717,7 +764,7 @@
       !BN_sub(rem, rsa->q, BN_value_one()) ||
       !BN_mod(rsa->dmq1, rsa->d, rem, ctx) ||
       !BN_mod_inverse(rsa->iqmp, rsa->q, rsa->p, ctx)) {
-    OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_BN_LIB);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB);
     goto err;
   }
 
diff --git a/src/crypto/rsa/rsa_asn1.c b/src/crypto/rsa/rsa_asn1.c
index 924cb8a..e3756ba 100644
--- a/src/crypto/rsa/rsa_asn1.c
+++ b/src/crypto/rsa/rsa_asn1.c
@@ -55,45 +55,384 @@
 
 #include <openssl/rsa.h>
 
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
 #include <openssl/asn1.h>
 #include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
 
 #include "internal.h"
 
 
-/* Override the default free and new methods */
-static int rsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
-                  void *exarg) {
-  if (operation == ASN1_OP_NEW_PRE) {
-    *pval = (ASN1_VALUE *)RSA_new();
-    if (*pval) {
-      return 2;
-    }
+static int parse_integer_buggy(CBS *cbs, BIGNUM **out, int buggy) {
+  assert(*out == NULL);
+  *out = BN_new();
+  if (*out == NULL) {
     return 0;
-  } else if (operation == ASN1_OP_FREE_PRE) {
-    RSA_free((RSA *)*pval);
-    *pval = NULL;
-    return 2;
+  }
+  if (buggy) {
+    return BN_cbs2unsigned_buggy(cbs, *out);
+  }
+  return BN_cbs2unsigned(cbs, *out);
+}
+
+static int parse_integer(CBS *cbs, BIGNUM **out) {
+  return parse_integer_buggy(cbs, out, 0 /* not buggy */);
+}
+
+static int marshal_integer(CBB *cbb, BIGNUM *bn) {
+  if (bn == NULL) {
+    /* An RSA object may be missing some components. */
+    OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
+    return 0;
+  }
+  return BN_bn2cbb(cbb, bn);
+}
+
+static RSA *parse_public_key(CBS *cbs, int buggy) {
+  RSA *ret = RSA_new();
+  if (ret == NULL) {
+    return NULL;
+  }
+  CBS child;
+  if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
+      !parse_integer_buggy(&child, &ret->n, buggy) ||
+      !parse_integer(&child, &ret->e) ||
+      CBS_len(&child) != 0) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+    RSA_free(ret);
+    return NULL;
+  }
+  return ret;
+}
+
+RSA *RSA_parse_public_key(CBS *cbs) {
+  return parse_public_key(cbs, 0 /* not buggy */);
+}
+
+RSA *RSA_parse_public_key_buggy(CBS *cbs) {
+  /* Estonian IDs issued between September 2014 to September 2015 are
+   * broken. See https://crbug.com/532048 and https://crbug.com/534766.
+   *
+   * TODO(davidben): Remove this code and callers in March 2016. */
+  return parse_public_key(cbs, 1 /* buggy */);
+}
+
+RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len) {
+  CBS cbs;
+  CBS_init(&cbs, in, in_len);
+  RSA *ret = RSA_parse_public_key(&cbs);
+  if (ret == NULL || CBS_len(&cbs) != 0) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+    RSA_free(ret);
+    return NULL;
+  }
+  return ret;
+}
+
+int RSA_marshal_public_key(CBB *cbb, const RSA *rsa) {
+  CBB child;
+  if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) ||
+      !marshal_integer(&child, rsa->n) ||
+      !marshal_integer(&child, rsa->e) ||
+      !CBB_flush(cbb)) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+    return 0;
   }
   return 1;
 }
 
-ASN1_SEQUENCE_cb(RSAPrivateKey, rsa_cb) = {
-  ASN1_SIMPLE(RSA, version, LONG),
-  ASN1_SIMPLE(RSA, n, BIGNUM),
-  ASN1_SIMPLE(RSA, e, BIGNUM),
-  ASN1_SIMPLE(RSA, d, BIGNUM),
-  ASN1_SIMPLE(RSA, p, BIGNUM),
-  ASN1_SIMPLE(RSA, q, BIGNUM),
-  ASN1_SIMPLE(RSA, dmp1, BIGNUM),
-  ASN1_SIMPLE(RSA, dmq1, BIGNUM),
-  ASN1_SIMPLE(RSA, iqmp, BIGNUM),
-} ASN1_SEQUENCE_END_cb(RSA, RSAPrivateKey);
+int RSA_public_key_to_bytes(uint8_t **out_bytes, size_t *out_len,
+                            const RSA *rsa) {
+  CBB cbb;
+  CBB_zero(&cbb);
+  if (!CBB_init(&cbb, 0) ||
+      !RSA_marshal_public_key(&cbb, rsa) ||
+      !CBB_finish(&cbb, out_bytes, out_len)) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+    CBB_cleanup(&cbb);
+    return 0;
+  }
+  return 1;
+}
 
-ASN1_SEQUENCE_cb(RSAPublicKey, rsa_cb) = {
-    ASN1_SIMPLE(RSA, n, BIGNUM),
-    ASN1_SIMPLE(RSA, e, BIGNUM),
-} ASN1_SEQUENCE_END_cb(RSA, RSAPublicKey);
+/* kVersionTwoPrime and kVersionMulti are the supported values of the version
+ * field of an RSAPrivateKey structure (RFC 3447). */
+static const uint64_t kVersionTwoPrime = 0;
+static const uint64_t kVersionMulti = 1;
+
+/* rsa_parse_additional_prime parses a DER-encoded OtherPrimeInfo from |cbs| and
+ * advances |cbs|. It returns a newly-allocated |RSA_additional_prime| on
+ * success or NULL on error. The |r| and |method_mod| fields of the result are
+ * set to NULL. */
+static RSA_additional_prime *rsa_parse_additional_prime(CBS *cbs) {
+  RSA_additional_prime *ret = OPENSSL_malloc(sizeof(RSA_additional_prime));
+  if (ret == NULL) {
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+    return 0;
+  }
+  memset(ret, 0, sizeof(RSA_additional_prime));
+
+  CBS child;
+  if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
+      !parse_integer(&child, &ret->prime) ||
+      !parse_integer(&child, &ret->exp) ||
+      !parse_integer(&child, &ret->coeff) ||
+      CBS_len(&child) != 0) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+    RSA_additional_prime_free(ret);
+    return NULL;
+  }
+
+  return ret;
+}
+
+RSA *RSA_parse_private_key(CBS *cbs) {
+  BN_CTX *ctx = NULL;
+  BIGNUM *product_of_primes_so_far = NULL;
+  RSA *ret = RSA_new();
+  if (ret == NULL) {
+    return NULL;
+  }
+
+  CBS child;
+  uint64_t version;
+  if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
+      !CBS_get_asn1_uint64(&child, &version) ||
+      (version != kVersionTwoPrime && version != kVersionMulti) ||
+      !parse_integer(&child, &ret->n) ||
+      !parse_integer(&child, &ret->e) ||
+      !parse_integer(&child, &ret->d) ||
+      !parse_integer(&child, &ret->p) ||
+      !parse_integer(&child, &ret->q) ||
+      !parse_integer(&child, &ret->dmp1) ||
+      !parse_integer(&child, &ret->dmq1) ||
+      !parse_integer(&child, &ret->iqmp)) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_VERSION);
+    goto err;
+  }
+
+  /* Multi-prime RSA requires a newer version. */
+  if (version == kVersionMulti &&
+      CBS_peek_asn1_tag(&child, CBS_ASN1_SEQUENCE)) {
+    CBS other_prime_infos;
+    if (!CBS_get_asn1(&child, &other_prime_infos, CBS_ASN1_SEQUENCE) ||
+        CBS_len(&other_prime_infos) == 0) {
+      OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+      goto err;
+    }
+    ret->additional_primes = sk_RSA_additional_prime_new_null();
+    if (ret->additional_primes == NULL) {
+      OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+
+    ctx = BN_CTX_new();
+    product_of_primes_so_far = BN_new();
+    if (ctx == NULL ||
+        product_of_primes_so_far == NULL ||
+        !BN_mul(product_of_primes_so_far, ret->p, ret->q, ctx)) {
+      goto err;
+    }
+
+    while (CBS_len(&other_prime_infos) > 0) {
+      RSA_additional_prime *ap = rsa_parse_additional_prime(&other_prime_infos);
+      if (ap == NULL) {
+        goto err;
+      }
+      if (!sk_RSA_additional_prime_push(ret->additional_primes, ap)) {
+        OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+        RSA_additional_prime_free(ap);
+        goto err;
+      }
+      ap->r = BN_dup(product_of_primes_so_far);
+      if (ap->r == NULL ||
+          !BN_mul(product_of_primes_so_far, product_of_primes_so_far,
+                  ap->prime, ctx)) {
+        goto err;
+      }
+    }
+  }
+
+  if (CBS_len(&child) != 0) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+    goto err;
+  }
+
+  BN_CTX_free(ctx);
+  BN_free(product_of_primes_so_far);
+  return ret;
+
+err:
+  BN_CTX_free(ctx);
+  BN_free(product_of_primes_so_far);
+  RSA_free(ret);
+  return NULL;
+}
+
+RSA *RSA_private_key_from_bytes(const uint8_t *in, size_t in_len) {
+  CBS cbs;
+  CBS_init(&cbs, in, in_len);
+  RSA *ret = RSA_parse_private_key(&cbs);
+  if (ret == NULL || CBS_len(&cbs) != 0) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+    RSA_free(ret);
+    return NULL;
+  }
+  return ret;
+}
+
+int RSA_marshal_private_key(CBB *cbb, const RSA *rsa) {
+  const int is_multiprime =
+      sk_RSA_additional_prime_num(rsa->additional_primes) > 0;
+
+  CBB child;
+  if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) ||
+      !CBB_add_asn1_uint64(&child,
+                           is_multiprime ? kVersionMulti : kVersionTwoPrime) ||
+      !marshal_integer(&child, rsa->n) ||
+      !marshal_integer(&child, rsa->e) ||
+      !marshal_integer(&child, rsa->d) ||
+      !marshal_integer(&child, rsa->p) ||
+      !marshal_integer(&child, rsa->q) ||
+      !marshal_integer(&child, rsa->dmp1) ||
+      !marshal_integer(&child, rsa->dmq1) ||
+      !marshal_integer(&child, rsa->iqmp)) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+    return 0;
+  }
+
+  if (is_multiprime) {
+    CBB other_prime_infos;
+    if (!CBB_add_asn1(&child, &other_prime_infos, CBS_ASN1_SEQUENCE)) {
+      OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+      return 0;
+    }
+    size_t i;
+    for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) {
+      RSA_additional_prime *ap =
+              sk_RSA_additional_prime_value(rsa->additional_primes, i);
+      CBB other_prime_info;
+      if (!CBB_add_asn1(&other_prime_infos, &other_prime_info,
+                        CBS_ASN1_SEQUENCE) ||
+          !marshal_integer(&other_prime_info, ap->prime) ||
+          !marshal_integer(&other_prime_info, ap->exp) ||
+          !marshal_integer(&other_prime_info, ap->coeff)) {
+        OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+        return 0;
+      }
+    }
+  }
+
+  if (!CBB_flush(cbb)) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+    return 0;
+  }
+  return 1;
+}
+
+int RSA_private_key_to_bytes(uint8_t **out_bytes, size_t *out_len,
+                             const RSA *rsa) {
+  CBB cbb;
+  CBB_zero(&cbb);
+  if (!CBB_init(&cbb, 0) ||
+      !RSA_marshal_private_key(&cbb, rsa) ||
+      !CBB_finish(&cbb, out_bytes, out_len)) {
+    OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+    CBB_cleanup(&cbb);
+    return 0;
+  }
+  return 1;
+}
+
+RSA *d2i_RSAPublicKey(RSA **out, const uint8_t **inp, long len) {
+  if (len < 0) {
+    return NULL;
+  }
+  CBS cbs;
+  CBS_init(&cbs, *inp, (size_t)len);
+  RSA *ret = RSA_parse_public_key(&cbs);
+  if (ret == NULL) {
+    return NULL;
+  }
+  if (out != NULL) {
+    RSA_free(*out);
+    *out = ret;
+  }
+  *inp += (size_t)len - CBS_len(&cbs);
+  return ret;
+}
+
+int i2d_RSAPublicKey(const RSA *in, uint8_t **outp) {
+  uint8_t *der;
+  size_t der_len;
+  if (!RSA_public_key_to_bytes(&der, &der_len, in)) {
+    return -1;
+  }
+  if (der_len > INT_MAX) {
+    OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
+    OPENSSL_free(der);
+    return -1;
+  }
+  if (outp != NULL) {
+    if (*outp == NULL) {
+      *outp = der;
+      der = NULL;
+    } else {
+      memcpy(*outp, der, der_len);
+      *outp += der_len;
+    }
+  }
+  OPENSSL_free(der);
+  return (int)der_len;
+}
+
+RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len) {
+  if (len < 0) {
+    return NULL;
+  }
+  CBS cbs;
+  CBS_init(&cbs, *inp, (size_t)len);
+  RSA *ret = RSA_parse_private_key(&cbs);
+  if (ret == NULL) {
+    return NULL;
+  }
+  if (out != NULL) {
+    RSA_free(*out);
+    *out = ret;
+  }
+  *inp += (size_t)len - CBS_len(&cbs);
+  return ret;
+}
+
+int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp) {
+  uint8_t *der;
+  size_t der_len;
+  if (!RSA_private_key_to_bytes(&der, &der_len, in)) {
+    return -1;
+  }
+  if (der_len > INT_MAX) {
+    OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
+    OPENSSL_free(der);
+    return -1;
+  }
+  if (outp != NULL) {
+    if (*outp == NULL) {
+      *outp = der;
+      der = NULL;
+    } else {
+      memcpy(*outp, der, der_len);
+      *outp += der_len;
+    }
+  }
+  OPENSSL_free(der);
+  return (int)der_len;
+}
 
 ASN1_SEQUENCE(RSA_PSS_PARAMS) = {
   ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0),
@@ -104,22 +443,24 @@
 
 IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS);
 
-ASN1_SEQUENCE(RSA_OAEP_PARAMS) = {
-  ASN1_EXP_OPT(RSA_OAEP_PARAMS, hashFunc, X509_ALGOR, 0),
-  ASN1_EXP_OPT(RSA_OAEP_PARAMS, maskGenFunc, X509_ALGOR, 1),
-  ASN1_EXP_OPT(RSA_OAEP_PARAMS, pSourceFunc, X509_ALGOR, 2),
-} ASN1_SEQUENCE_END(RSA_OAEP_PARAMS);
-
-IMPLEMENT_ASN1_FUNCTIONS(RSA_OAEP_PARAMS);
-
-IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(RSA, RSAPrivateKey, RSAPrivateKey);
-
-IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(RSA, RSAPublicKey, RSAPublicKey);
-
 RSA *RSAPublicKey_dup(const RSA *rsa) {
-  return ASN1_item_dup(ASN1_ITEM_rptr(RSAPublicKey), (RSA *) rsa);
+  uint8_t *der;
+  size_t der_len;
+  if (!RSA_public_key_to_bytes(&der, &der_len, rsa)) {
+    return NULL;
+  }
+  RSA *ret = RSA_public_key_from_bytes(der, der_len);
+  OPENSSL_free(der);
+  return ret;
 }
 
 RSA *RSAPrivateKey_dup(const RSA *rsa) {
-  return ASN1_item_dup(ASN1_ITEM_rptr(RSAPrivateKey), (RSA *) rsa);
+  uint8_t *der;
+  size_t der_len;
+  if (!RSA_private_key_to_bytes(&der, &der_len, rsa)) {
+    return NULL;
+  }
+  RSA *ret = RSA_private_key_from_bytes(der, der_len);
+  OPENSSL_free(der);
+  return ret;
 }
diff --git a/src/crypto/rsa/rsa_impl.c b/src/crypto/rsa/rsa_impl.c
index e14f0f5..eb4a36f 100644
--- a/src/crypto/rsa/rsa_impl.c
+++ b/src/crypto/rsa/rsa_impl.c
@@ -78,6 +78,15 @@
   BN_MONT_CTX_free(rsa->_method_mod_p);
   BN_MONT_CTX_free(rsa->_method_mod_q);
 
+  if (rsa->additional_primes != NULL) {
+    size_t i;
+    for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) {
+      RSA_additional_prime *ap =
+          sk_RSA_additional_prime_value(rsa->additional_primes, i);
+      BN_MONT_CTX_free(ap->method_mod);
+    }
+  }
+
   return 1;
 }
 
@@ -94,24 +103,24 @@
   int i, ret = 0;
 
   if (rsa_size > OPENSSL_RSA_MAX_MODULUS_BITS) {
-    OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_MODULUS_TOO_LARGE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE);
     return 0;
   }
 
   if (max_out < rsa_size) {
-    OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
     return 0;
   }
 
   if (BN_ucmp(rsa->n, rsa->e) <= 0) {
-    OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_BAD_E_VALUE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
     return 0;
   }
 
   /* for large moduli, enforce exponent limit */
   if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS &&
       BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) {
-    OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_BAD_E_VALUE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
     return 0;
   }
 
@@ -125,7 +134,7 @@
   result = BN_CTX_get(ctx);
   buf = OPENSSL_malloc(rsa_size);
   if (!f || !result || !buf) {
-    OPENSSL_PUT_ERROR(RSA, encrypt, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -142,7 +151,7 @@
       i = RSA_padding_add_none(buf, rsa_size, in, in_len);
       break;
     default:
-      OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_PADDING_TYPE);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
       goto err;
   }
 
@@ -156,7 +165,7 @@
 
   if (BN_ucmp(f, rsa->n) >= 0) {
     /* usually the padding functions would catch this */
-    OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
     goto err;
   }
 
@@ -175,7 +184,7 @@
   /* put in leading 0 bytes if the number is less than the length of the
    * modulus */
   if (!BN_bn2bin_padded(out, rsa_size, result)) {
-    OPENSSL_PUT_ERROR(RSA, encrypt, ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
     goto err;
   }
 
@@ -309,13 +318,13 @@
   int i, ret = 0;
 
   if (max_out < rsa_size) {
-    OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
     return 0;
   }
 
   buf = OPENSSL_malloc(rsa_size);
   if (buf == NULL) {
-    OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -327,7 +336,7 @@
       i = RSA_padding_add_none(buf, rsa_size, in, in_len);
       break;
     default:
-      OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_UNKNOWN_PADDING_TYPE);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
       goto err;
   }
 
@@ -359,18 +368,23 @@
   int ret = 0;
 
   if (max_out < rsa_size) {
-    OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
     return 0;
   }
 
-  buf = OPENSSL_malloc(rsa_size);
-  if (buf == NULL) {
-    OPENSSL_PUT_ERROR(RSA, decrypt, ERR_R_MALLOC_FAILURE);
-    goto err;
+  if (padding == RSA_NO_PADDING) {
+    buf = out;
+  } else {
+    /* Allocate a temporary buffer to hold the padded plaintext. */
+    buf = OPENSSL_malloc(rsa_size);
+    if (buf == NULL) {
+      OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
   }
 
   if (in_len != rsa_size) {
-    OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
     goto err;
   }
 
@@ -388,22 +402,22 @@
                                             NULL, 0, NULL, NULL);
       break;
     case RSA_NO_PADDING:
-      r = RSA_padding_check_none(out, rsa_size, buf, rsa_size);
+      r = rsa_size;
       break;
     default:
-      OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_UNKNOWN_PADDING_TYPE);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
       goto err;
   }
 
   if (r < 0) {
-    OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_PADDING_CHECK_FAILED);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED);
   } else {
     *out_len = r;
     ret = 1;
   }
 
 err:
-  if (buf != NULL) {
+  if (padding != RSA_NO_PADDING && buf != NULL) {
     OPENSSL_cleanse(buf, rsa_size);
     OPENSSL_free(buf);
   }
@@ -421,24 +435,24 @@
   BN_CTX *ctx = NULL;
 
   if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS) {
-    OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_MODULUS_TOO_LARGE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE);
     return 0;
   }
 
   if (BN_ucmp(rsa->n, rsa->e) <= 0) {
-    OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_BAD_E_VALUE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
     return 0;
   }
 
   if (max_out < rsa_size) {
-    OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
     return 0;
   }
 
   /* for large moduli, enforce exponent limit */
   if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS &&
       BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) {
-    OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_BAD_E_VALUE);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
     return 0;
   }
 
@@ -450,14 +464,23 @@
   BN_CTX_start(ctx);
   f = BN_CTX_get(ctx);
   result = BN_CTX_get(ctx);
-  buf = OPENSSL_malloc(rsa_size);
-  if (!f || !result || !buf) {
-    OPENSSL_PUT_ERROR(RSA, verify_raw, ERR_R_MALLOC_FAILURE);
+  if (padding == RSA_NO_PADDING) {
+    buf = out;
+  } else {
+    /* Allocate a temporary buffer to hold the padded plaintext. */
+    buf = OPENSSL_malloc(rsa_size);
+    if (buf == NULL) {
+      OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
+  if (!f || !result) {
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
   if (in_len != rsa_size) {
-    OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
     goto err;
   }
 
@@ -466,7 +489,7 @@
   }
 
   if (BN_ucmp(f, rsa->n) >= 0) {
-    OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
     goto err;
   }
 
@@ -483,7 +506,7 @@
   }
 
   if (!BN_bn2bin_padded(buf, rsa_size, result)) {
-    OPENSSL_PUT_ERROR(RSA, verify_raw, ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
     goto err;
   }
 
@@ -492,15 +515,15 @@
       r = RSA_padding_check_PKCS1_type_1(out, rsa_size, buf, rsa_size);
       break;
     case RSA_NO_PADDING:
-      r = RSA_padding_check_none(out, rsa_size, buf, rsa_size);
+      r = rsa_size;
       break;
     default:
-      OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_PADDING_TYPE);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
       goto err;
   }
 
   if (r < 0) {
-    OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_PADDING_CHECK_FAILED);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED);
   } else {
     *out_len = r;
     ret = 1;
@@ -511,7 +534,7 @@
     BN_CTX_end(ctx);
     BN_CTX_free(ctx);
   }
-  if (buf != NULL) {
+  if (padding != RSA_NO_PADDING && buf != NULL) {
     OPENSSL_cleanse(buf, rsa_size);
     OPENSSL_free(buf);
   }
@@ -535,7 +558,7 @@
   result = BN_CTX_get(ctx);
 
   if (f == NULL || result == NULL) {
-    OPENSSL_PUT_ERROR(RSA, private_transform, ERR_R_MALLOC_FAILURE);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
     goto err;
   }
 
@@ -545,14 +568,14 @@
 
   if (BN_ucmp(f, rsa->n) >= 0) {
     /* Usually the padding functions would catch this. */
-    OPENSSL_PUT_ERROR(RSA, private_transform, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
+    OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
     goto err;
   }
 
   if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) {
     blinding = rsa_blinding_get(rsa, &blinding_index, ctx);
     if (blinding == NULL) {
-      OPENSSL_PUT_ERROR(RSA, private_transform, ERR_R_INTERNAL_ERROR);
+      OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
       goto err;
     }
     if (!BN_BLINDING_convert_ex(f, NULL, blinding, ctx)) {
@@ -593,7 +616,7 @@
   }
 
   if (!BN_bn2bin_padded(out, len, result)) {
-    OPENSSL_PUT_ERROR(RSA, private_transform, ERR_R_INTERNAL_ERROR);
+    OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
     goto err;
   }
 
@@ -616,6 +639,11 @@
   BIGNUM local_dmp1, local_dmq1, local_c, local_r1;
   BIGNUM *dmp1, *dmq1, *c, *pr1;
   int ret = 0;
+  size_t i, num_additional_primes = 0;
+
+  if (rsa->additional_primes != NULL) {
+    num_additional_primes = sk_RSA_additional_prime_num(rsa->additional_primes);
+  }
 
   BN_CTX_start(ctx);
   r1 = BN_CTX_get(ctx);
@@ -724,6 +752,42 @@
     goto err;
   }
 
+  for (i = 0; i < num_additional_primes; i++) {
+    /* multi-prime RSA. */
+    BIGNUM local_exp, local_prime;
+    BIGNUM *exp = &local_exp, *prime = &local_prime;
+    RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(rsa->additional_primes, i);
+
+    BN_with_flags(exp, ap->exp, BN_FLG_CONSTTIME);
+    BN_with_flags(prime, ap->prime, BN_FLG_CONSTTIME);
+
+    /* c will already point to a BIGNUM with the correct flags. */
+    if (!BN_mod(r1, c, prime, ctx)) {
+      goto err;
+    }
+
+    if ((rsa->flags & RSA_FLAG_CACHE_PRIVATE) &&
+        !BN_MONT_CTX_set_locked(&ap->method_mod, &rsa->lock, prime, ctx)) {
+      goto err;
+    }
+
+    if (!rsa->meth->bn_mod_exp(m1, r1, exp, prime, ctx, ap->method_mod)) {
+      goto err;
+    }
+
+    BN_set_flags(m1, BN_FLG_CONSTTIME);
+
+    if (!BN_sub(m1, m1, r0) ||
+        !BN_mul(m1, m1, ap->coeff, ctx) ||
+        !BN_mod(m1, m1, prime, ctx) ||
+        (BN_is_negative(m1) && !BN_add(m1, m1, prime)) ||
+        !BN_mul(m1, m1, ap->r, ctx) ||
+        !BN_add(r0, r0, m1)) {
+      goto err;
+    }
+  }
+
   if (rsa->e && rsa->n) {
     if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx,
                                rsa->_method_mod_n)) {
@@ -766,12 +830,20 @@
   return ret;
 }
 
-static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
+static int keygen_multiprime(RSA *rsa, int bits, int num_primes,
+                             BIGNUM *e_value, BN_GENCB *cb) {
   BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp;
   BIGNUM local_r0, local_d, local_p;
   BIGNUM *pr0, *d, *p;
-  int bitsp, bitsq, ok = -1, n = 0;
+  int prime_bits, ok = -1, n = 0, i, j;
   BN_CTX *ctx = NULL;
+  STACK_OF(RSA_additional_prime) *additional_primes = NULL;
+
+  if (num_primes < 2) {
+    ok = 0; /* we set our own err */
+    OPENSSL_PUT_ERROR(RSA, RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES);
+    goto err;
+  }
 
   ctx = BN_CTX_new();
   if (ctx == NULL) {
@@ -782,12 +854,36 @@
   r1 = BN_CTX_get(ctx);
   r2 = BN_CTX_get(ctx);
   r3 = BN_CTX_get(ctx);
-  if (r3 == NULL) {
+  if (r0 == NULL || r1 == NULL || r2 == NULL || r3 == NULL) {
     goto err;
   }
 
-  bitsp = (bits + 1) / 2;
-  bitsq = bits - bitsp;
+  if (num_primes > 2) {
+    additional_primes = sk_RSA_additional_prime_new_null();
+    if (additional_primes == NULL) {
+      goto err;
+    }
+  }
+
+  for (i = 2; i < num_primes; i++) {
+    RSA_additional_prime *ap = OPENSSL_malloc(sizeof(RSA_additional_prime));
+    if (ap == NULL) {
+      goto err;
+    }
+    memset(ap, 0, sizeof(RSA_additional_prime));
+    ap->prime = BN_new();
+    ap->exp = BN_new();
+    ap->coeff = BN_new();
+    ap->r = BN_new();
+    if (ap->prime == NULL ||
+        ap->exp == NULL ||
+        ap->coeff == NULL ||
+        ap->r == NULL ||
+        !sk_RSA_additional_prime_push(additional_primes, ap)) {
+      RSA_additional_prime_free(ap);
+      goto err;
+    }
+  }
 
   /* We need the RSA components non-NULL */
   if (!rsa->n && ((rsa->n = BN_new()) == NULL)) {
@@ -815,11 +911,14 @@
     goto err;
   }
 
-  BN_copy(rsa->e, e_value);
+  if (!BN_copy(rsa->e, e_value)) {
+    goto err;
+  }
 
   /* generate p and q */
+  prime_bits = (bits + (num_primes - 1)) / num_primes;
   for (;;) {
-    if (!BN_generate_prime_ex(rsa->p, bitsp, 0, NULL, NULL, cb) ||
+    if (!BN_generate_prime_ex(rsa->p, prime_bits, 0, NULL, NULL, cb) ||
         !BN_sub(r2, rsa->p, BN_value_one()) ||
         !BN_gcd(r1, r2, rsa->e, ctx)) {
       goto err;
@@ -834,19 +933,20 @@
   if (!BN_GENCB_call(cb, 3, 0)) {
     goto err;
   }
+  prime_bits = ((bits - prime_bits) + (num_primes - 2)) / (num_primes - 1);
   for (;;) {
     /* When generating ridiculously small keys, we can get stuck
      * continually regenerating the same prime values. Check for
      * this and bail if it happens 3 times. */
     unsigned int degenerate = 0;
     do {
-      if (!BN_generate_prime_ex(rsa->q, bitsq, 0, NULL, NULL, cb)) {
+      if (!BN_generate_prime_ex(rsa->q, prime_bits, 0, NULL, NULL, cb)) {
         goto err;
       }
     } while ((BN_cmp(rsa->p, rsa->q) == 0) && (++degenerate < 3));
     if (degenerate == 3) {
       ok = 0; /* we set our own err */
-      OPENSSL_PUT_ERROR(RSA, keygen, RSA_R_KEY_SIZE_TOO_SMALL);
+      OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
       goto err;
     }
     if (!BN_sub(r2, rsa->q, BN_value_one()) ||
@@ -860,20 +960,91 @@
       goto err;
     }
   }
-  if (!BN_GENCB_call(cb, 3, 1)) {
+
+  if (!BN_GENCB_call(cb, 3, 1) ||
+      !BN_mul(rsa->n, rsa->p, rsa->q, ctx)) {
     goto err;
   }
+
+  for (i = 2; i < num_primes; i++) {
+    RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(additional_primes, i - 2);
+    prime_bits = ((bits - BN_num_bits(rsa->n)) + (num_primes - (i + 1))) /
+                 (num_primes - i);
+
+    for (;;) {
+      if (!BN_generate_prime_ex(ap->prime, prime_bits, 0, NULL, NULL, cb)) {
+        goto err;
+      }
+      if (BN_cmp(rsa->p, ap->prime) == 0 ||
+          BN_cmp(rsa->q, ap->prime) == 0) {
+        continue;
+      }
+
+      for (j = 0; j < i - 2; j++) {
+        if (BN_cmp(sk_RSA_additional_prime_value(additional_primes, j)->prime,
+                   ap->prime) == 0) {
+          break;
+        }
+      }
+      if (j != i - 2) {
+        continue;
+      }
+
+      if (!BN_sub(r2, ap->prime, BN_value_one()) ||
+          !BN_gcd(r1, r2, rsa->e, ctx)) {
+        goto err;
+      }
+
+      if (!BN_is_one(r1)) {
+        continue;
+      }
+      if (i != num_primes - 1) {
+        break;
+      }
+
+      /* For the last prime we'll check that it makes n large enough. In the
+       * two prime case this isn't a problem because we generate primes with
+       * the top two bits set and so the product is always of the expected
+       * size. In the multi prime case, this doesn't follow. */
+      if (!BN_mul(r1, rsa->n, ap->prime, ctx)) {
+        goto err;
+      }
+      if (BN_num_bits(r1) == bits) {
+        break;
+      }
+
+      if (!BN_GENCB_call(cb, 2, n++)) {
+        goto err;
+      }
+    }
+
+    /* ap->r is is the product of all the primes prior to the current one
+     * (including p and q). */
+    if (!BN_copy(ap->r, rsa->n)) {
+      goto err;
+    }
+    if (i == num_primes - 1) {
+      /* In the case of the last prime, we calculated n as |r1| in the loop
+       * above. */
+      if (!BN_copy(rsa->n, r1)) {
+        goto err;
+      }
+    } else if (!BN_mul(rsa->n, rsa->n, ap->prime, ctx)) {
+      goto err;
+    }
+
+    if (!BN_GENCB_call(cb, 3, 1)) {
+      goto err;
+    }
+  }
+
   if (BN_cmp(rsa->p, rsa->q) < 0) {
     tmp = rsa->p;
     rsa->p = rsa->q;
     rsa->q = tmp;
   }
 
-  /* calculate n */
-  if (!BN_mul(rsa->n, rsa->p, rsa->q, ctx)) {
-    goto err;
-  }
-
   /* calculate d */
   if (!BN_sub(r1, rsa->p, BN_value_one())) {
     goto err; /* p-1 */
@@ -884,6 +1055,14 @@
   if (!BN_mul(r0, r1, r2, ctx)) {
     goto err; /* (p-1)(q-1) */
   }
+  for (i = 2; i < num_primes; i++) {
+    RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(additional_primes, i - 2);
+    if (!BN_sub(r3, ap->prime, BN_value_one()) ||
+        !BN_mul(r0, r0, r3, ctx)) {
+      goto err;
+    }
+  }
   pr0 = &local_r0;
   BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
   if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) {
@@ -912,21 +1091,38 @@
     goto err;
   }
 
+  for (i = 2; i < num_primes; i++) {
+    RSA_additional_prime *ap =
+        sk_RSA_additional_prime_value(additional_primes, i - 2);
+    if (!BN_sub(ap->exp, ap->prime, BN_value_one()) ||
+        !BN_mod(ap->exp, rsa->d, ap->exp, ctx) ||
+        !BN_mod_inverse(ap->coeff, ap->r, ap->prime, ctx)) {
+      goto err;
+    }
+  }
+
   ok = 1;
+  rsa->additional_primes = additional_primes;
+  additional_primes = NULL;
 
 err:
   if (ok == -1) {
-    OPENSSL_PUT_ERROR(RSA, keygen, ERR_LIB_BN);
+    OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
     ok = 0;
   }
   if (ctx != NULL) {
     BN_CTX_end(ctx);
     BN_CTX_free(ctx);
   }
-
+  sk_RSA_additional_prime_pop_free(additional_primes,
+                                   RSA_additional_prime_free);
   return ok;
 }
 
+static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
+  return keygen_multiprime(rsa, bits, 2 /* num primes */, e_value, cb);
+}
+
 const struct rsa_meth_st RSA_default_method = {
   {
     0 /* references */,
@@ -955,4 +1151,7 @@
   RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE,
 
   keygen,
+  keygen_multiprime,
+
+  NULL /* supports_digest */,
 };
diff --git a/src/crypto/rsa/rsa_test.c b/src/crypto/rsa/rsa_test.c
deleted file mode 100644
index 318cf3f..0000000
--- a/src/crypto/rsa/rsa_test.c
+++ /dev/null
@@ -1,511 +0,0 @@
-/* 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/rsa.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <openssl/bn.h>
-#include <openssl/crypto.h>
-#include <openssl/err.h>
-#include <openssl/obj.h>
-
-
-#define SetKey                                              \
-  key->n = BN_bin2bn(n, sizeof(n) - 1, key->n);             \
-  key->e = BN_bin2bn(e, sizeof(e) - 1, key->e);             \
-  key->d = BN_bin2bn(d, sizeof(d) - 1, key->d);             \
-  key->p = BN_bin2bn(p, sizeof(p) - 1, key->p);             \
-  key->q = BN_bin2bn(q, sizeof(q) - 1, key->q);             \
-  key->dmp1 = BN_bin2bn(dmp1, sizeof(dmp1) - 1, key->dmp1); \
-  key->dmq1 = BN_bin2bn(dmq1, sizeof(dmq1) - 1, key->dmq1); \
-  key->iqmp = BN_bin2bn(iqmp, sizeof(iqmp) - 1, key->iqmp); \
-  memcpy(c, ctext_ex, sizeof(ctext_ex) - 1);                \
-  return (sizeof(ctext_ex) - 1);
-
-static int key1(RSA *key, unsigned char *c) {
-  static unsigned char n[] =
-      "\x00\xAA\x36\xAB\xCE\x88\xAC\xFD\xFF\x55\x52\x3C\x7F\xC4\x52\x3F"
-      "\x90\xEF\xA0\x0D\xF3\x77\x4A\x25\x9F\x2E\x62\xB4\xC5\xD9\x9C\xB5"
-      "\xAD\xB3\x00\xA0\x28\x5E\x53\x01\x93\x0E\x0C\x70\xFB\x68\x76\x93"
-      "\x9C\xE6\x16\xCE\x62\x4A\x11\xE0\x08\x6D\x34\x1E\xBC\xAC\xA0\xA1"
-      "\xF5";
-
-  static unsigned char e[] = "\x11";
-
-  static unsigned char d[] =
-      "\x0A\x03\x37\x48\x62\x64\x87\x69\x5F\x5F\x30\xBC\x38\xB9\x8B\x44"
-      "\xC2\xCD\x2D\xFF\x43\x40\x98\xCD\x20\xD8\xA1\x38\xD0\x90\xBF\x64"
-      "\x79\x7C\x3F\xA7\xA2\xCD\xCB\x3C\xD1\xE0\xBD\xBA\x26\x54\xB4\xF9"
-      "\xDF\x8E\x8A\xE5\x9D\x73\x3D\x9F\x33\xB3\x01\x62\x4A\xFD\x1D\x51";
-
-  static unsigned char p[] =
-      "\x00\xD8\x40\xB4\x16\x66\xB4\x2E\x92\xEA\x0D\xA3\xB4\x32\x04\xB5"
-      "\xCF\xCE\x33\x52\x52\x4D\x04\x16\xA5\xA4\x41\xE7\x00\xAF\x46\x12"
-      "\x0D";
-
-  static unsigned char q[] =
-      "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9"
-      "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5A\x0F\x20\x35\x02\x8B\x9D"
-      "\x89";
-
-  static unsigned char dmp1[] =
-      "\x59\x0B\x95\x72\xA2\xC2\xA9\xC4\x06\x05\x9D\xC2\xAB\x2F\x1D\xAF"
-      "\xEB\x7E\x8B\x4F\x10\xA7\x54\x9E\x8E\xED\xF5\xB4\xFC\xE0\x9E\x05";
-
-  static unsigned char dmq1[] =
-      "\x00\x8E\x3C\x05\x21\xFE\x15\xE0\xEA\x06\xA3\x6F\xF0\xF1\x0C\x99"
-      "\x52\xC3\x5B\x7A\x75\x14\xFD\x32\x38\xB8\x0A\xAD\x52\x98\x62\x8D"
-      "\x51";
-
-  static unsigned char iqmp[] =
-      "\x36\x3F\xF7\x18\x9D\xA8\xE9\x0B\x1D\x34\x1F\x71\xD0\x9B\x76\xA8"
-      "\xA9\x43\xE1\x1D\x10\xB2\x4D\x24\x9F\x2D\xEA\xFE\xF8\x0C\x18\x26";
-
-  static unsigned char ctext_ex[] =
-      "\x1b\x8f\x05\xf9\xca\x1a\x79\x52\x6e\x53\xf3\xcc\x51\x4f\xdb\x89"
-      "\x2b\xfb\x91\x93\x23\x1e\x78\xb9\x92\xe6\x8d\x50\xa4\x80\xcb\x52"
-      "\x33\x89\x5c\x74\x95\x8d\x5d\x02\xab\x8c\x0f\xd0\x40\xeb\x58\x44"
-      "\xb0\x05\xc3\x9e\xd8\x27\x4a\x9d\xbf\xa8\x06\x71\x40\x94\x39\xd2";
-
-  SetKey;
-}
-
-static int key2(RSA *key, unsigned char *c) {
-  static unsigned char n[] =
-      "\x00\xA3\x07\x9A\x90\xDF\x0D\xFD\x72\xAC\x09\x0C\xCC\x2A\x78\xB8"
-      "\x74\x13\x13\x3E\x40\x75\x9C\x98\xFA\xF8\x20\x4F\x35\x8A\x0B\x26"
-      "\x3C\x67\x70\xE7\x83\xA9\x3B\x69\x71\xB7\x37\x79\xD2\x71\x7B\xE8"
-      "\x34\x77\xCF";
-
-  static unsigned char e[] = "\x3";
-
-  static unsigned char d[] =
-      "\x6C\xAF\xBC\x60\x94\xB3\xFE\x4C\x72\xB0\xB3\x32\xC6\xFB\x25\xA2"
-      "\xB7\x62\x29\x80\x4E\x68\x65\xFC\xA4\x5A\x74\xDF\x0F\x8F\xB8\x41"
-      "\x3B\x52\xC0\xD0\xE5\x3D\x9B\x59\x0F\xF1\x9B\xE7\x9F\x49\xDD\x21"
-      "\xE5\xEB";
-
-  static unsigned char p[] =
-      "\x00\xCF\x20\x35\x02\x8B\x9D\x86\x98\x40\xB4\x16\x66\xB4\x2E\x92"
-      "\xEA\x0D\xA3\xB4\x32\x04\xB5\xCF\xCE\x91";
-
-  static unsigned char q[] =
-      "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9"
-      "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5F";
-
-  static unsigned char dmp1[] =
-      "\x00\x8A\x15\x78\xAC\x5D\x13\xAF\x10\x2B\x22\xB9\x99\xCD\x74\x61"
-      "\xF1\x5E\x6D\x22\xCC\x03\x23\xDF\xDF\x0B";
-
-  static unsigned char dmq1[] =
-      "\x00\x86\x55\x21\x4A\xC5\x4D\x8D\x4E\xCD\x61\x77\xF1\xC7\x36\x90"
-      "\xCE\x2A\x48\x2C\x8B\x05\x99\xCB\xE0\x3F";
-
-  static unsigned char iqmp[] =
-      "\x00\x83\xEF\xEF\xB8\xA9\xA4\x0D\x1D\xB6\xED\x98\xAD\x84\xED\x13"
-      "\x35\xDC\xC1\x08\xF3\x22\xD0\x57\xCF\x8D";
-
-  static unsigned char ctext_ex[] =
-      "\x14\xbd\xdd\x28\xc9\x83\x35\x19\x23\x80\xe8\xe5\x49\xb1\x58\x2a"
-      "\x8b\x40\xb4\x48\x6d\x03\xa6\xa5\x31\x1f\x1f\xd5\xf0\xa1\x80\xe4"
-      "\x17\x53\x03\x29\xa9\x34\x90\x74\xb1\x52\x13\x54\x29\x08\x24\x52"
-      "\x62\x51";
-
-  SetKey;
-}
-
-static int key3(RSA *key, unsigned char *c) {
-  static unsigned char n[] =
-      "\x00\xBB\xF8\x2F\x09\x06\x82\xCE\x9C\x23\x38\xAC\x2B\x9D\xA8\x71"
-      "\xF7\x36\x8D\x07\xEE\xD4\x10\x43\xA4\x40\xD6\xB6\xF0\x74\x54\xF5"
-      "\x1F\xB8\xDF\xBA\xAF\x03\x5C\x02\xAB\x61\xEA\x48\xCE\xEB\x6F\xCD"
-      "\x48\x76\xED\x52\x0D\x60\xE1\xEC\x46\x19\x71\x9D\x8A\x5B\x8B\x80"
-      "\x7F\xAF\xB8\xE0\xA3\xDF\xC7\x37\x72\x3E\xE6\xB4\xB7\xD9\x3A\x25"
-      "\x84\xEE\x6A\x64\x9D\x06\x09\x53\x74\x88\x34\xB2\x45\x45\x98\x39"
-      "\x4E\xE0\xAA\xB1\x2D\x7B\x61\xA5\x1F\x52\x7A\x9A\x41\xF6\xC1\x68"
-      "\x7F\xE2\x53\x72\x98\xCA\x2A\x8F\x59\x46\xF8\xE5\xFD\x09\x1D\xBD"
-      "\xCB";
-
-  static unsigned char e[] = "\x11";
-
-  static unsigned char d[] =
-      "\x00\xA5\xDA\xFC\x53\x41\xFA\xF2\x89\xC4\xB9\x88\xDB\x30\xC1\xCD"
-      "\xF8\x3F\x31\x25\x1E\x06\x68\xB4\x27\x84\x81\x38\x01\x57\x96\x41"
-      "\xB2\x94\x10\xB3\xC7\x99\x8D\x6B\xC4\x65\x74\x5E\x5C\x39\x26\x69"
-      "\xD6\x87\x0D\xA2\xC0\x82\xA9\x39\xE3\x7F\xDC\xB8\x2E\xC9\x3E\xDA"
-      "\xC9\x7F\xF3\xAD\x59\x50\xAC\xCF\xBC\x11\x1C\x76\xF1\xA9\x52\x94"
-      "\x44\xE5\x6A\xAF\x68\xC5\x6C\x09\x2C\xD3\x8D\xC3\xBE\xF5\xD2\x0A"
-      "\x93\x99\x26\xED\x4F\x74\xA1\x3E\xDD\xFB\xE1\xA1\xCE\xCC\x48\x94"
-      "\xAF\x94\x28\xC2\xB7\xB8\x88\x3F\xE4\x46\x3A\x4B\xC8\x5B\x1C\xB3"
-      "\xC1";
-
-  static unsigned char p[] =
-      "\x00\xEE\xCF\xAE\x81\xB1\xB9\xB3\xC9\x08\x81\x0B\x10\xA1\xB5\x60"
-      "\x01\x99\xEB\x9F\x44\xAE\xF4\xFD\xA4\x93\xB8\x1A\x9E\x3D\x84\xF6"
-      "\x32\x12\x4E\xF0\x23\x6E\x5D\x1E\x3B\x7E\x28\xFA\xE7\xAA\x04\x0A"
-      "\x2D\x5B\x25\x21\x76\x45\x9D\x1F\x39\x75\x41\xBA\x2A\x58\xFB\x65"
-      "\x99";
-
-  static unsigned char q[] =
-      "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9"
-      "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5A\x0F\x20\x35\x02\x8B\x9D"
-      "\x86\x98\x40\xB4\x16\x66\xB4\x2E\x92\xEA\x0D\xA3\xB4\x32\x04\xB5"
-      "\xCF\xCE\x33\x52\x52\x4D\x04\x16\xA5\xA4\x41\xE7\x00\xAF\x46\x15"
-      "\x03";
-
-  static unsigned char dmp1[] =
-      "\x54\x49\x4C\xA6\x3E\xBA\x03\x37\xE4\xE2\x40\x23\xFC\xD6\x9A\x5A"
-      "\xEB\x07\xDD\xDC\x01\x83\xA4\xD0\xAC\x9B\x54\xB0\x51\xF2\xB1\x3E"
-      "\xD9\x49\x09\x75\xEA\xB7\x74\x14\xFF\x59\xC1\xF7\x69\x2E\x9A\x2E"
-      "\x20\x2B\x38\xFC\x91\x0A\x47\x41\x74\xAD\xC9\x3C\x1F\x67\xC9\x81";
-
-  static unsigned char dmq1[] =
-      "\x47\x1E\x02\x90\xFF\x0A\xF0\x75\x03\x51\xB7\xF8\x78\x86\x4C\xA9"
-      "\x61\xAD\xBD\x3A\x8A\x7E\x99\x1C\x5C\x05\x56\xA9\x4C\x31\x46\xA7"
-      "\xF9\x80\x3F\x8F\x6F\x8A\xE3\x42\xE9\x31\xFD\x8A\xE4\x7A\x22\x0D"
-      "\x1B\x99\xA4\x95\x84\x98\x07\xFE\x39\xF9\x24\x5A\x98\x36\xDA\x3D";
-
-  static unsigned char iqmp[] =
-      "\x00\xB0\x6C\x4F\xDA\xBB\x63\x01\x19\x8D\x26\x5B\xDB\xAE\x94\x23"
-      "\xB3\x80\xF2\x71\xF7\x34\x53\x88\x50\x93\x07\x7F\xCD\x39\xE2\x11"
-      "\x9F\xC9\x86\x32\x15\x4F\x58\x83\xB1\x67\xA9\x67\xBF\x40\x2B\x4E"
-      "\x9E\x2E\x0F\x96\x56\xE6\x98\xEA\x36\x66\xED\xFB\x25\x79\x80\x39"
-      "\xF7";
-
-  static unsigned char ctext_ex[] =
-      "\xb8\x24\x6b\x56\xa6\xed\x58\x81\xae\xb5\x85\xd9\xa2\x5b\x2a\xd7"
-      "\x90\xc4\x17\xe0\x80\x68\x1b\xf1\xac\x2b\xc3\xde\xb6\x9d\x8b\xce"
-      "\xf0\xc4\x36\x6f\xec\x40\x0a\xf0\x52\xa7\x2e\x9b\x0e\xff\xb5\xb3"
-      "\xf2\xf1\x92\xdb\xea\xca\x03\xc1\x27\x40\x05\x71\x13\xbf\x1f\x06"
-      "\x69\xac\x22\xe9\xf3\xa7\x85\x2e\x3c\x15\xd9\x13\xca\xb0\xb8\x86"
-      "\x3a\x95\xc9\x92\x94\xce\x86\x74\x21\x49\x54\x61\x03\x46\xf4\xd4"
-      "\x74\xb2\x6f\x7c\x48\xb4\x2e\xe6\x8e\x1f\x57\x2a\x1f\xc4\x02\x6a"
-      "\xc4\x56\xb4\xf5\x9f\x7b\x62\x1e\xa1\xb9\xd8\x8f\x64\x20\x2f\xb1";
-
-  SetKey;
-}
-
-static int test_bad_key(void) {
-  RSA *key = RSA_new();
-  BIGNUM e;
-
-  BN_init(&e);
-  BN_set_word(&e, RSA_F4);
-
-  if (!RSA_generate_key_ex(key, 512, &e, NULL)) {
-    fprintf(stderr, "RSA_generate_key_ex failed.\n");
-    ERR_print_errors_fp(stderr);
-    return 0;
-  }
-
-  if (!BN_add(key->p, key->p, BN_value_one())) {
-    fprintf(stderr, "BN error.\n");
-    ERR_print_errors_fp(stderr);
-    return 0;
-  }
-
-  if (RSA_check_key(key)) {
-    fprintf(stderr, "RSA_check_key passed with invalid key!\n");
-    return 0;
-  }
-
-  ERR_clear_error();
-  BN_free(&e);
-  RSA_free(key);
-  return 1;
-}
-
-static int test_only_d_given(void) {
-  RSA *key = RSA_new();
-  uint8_t buf[64];
-  unsigned buf_len = sizeof(buf);
-  const uint8_t kDummyHash[16] = {0};
-  int ret = 0;
-
-  if (!BN_hex2bn(&key->n,
-                 "00e77bbf3889d4ef36a9a25d4d69f3f632eb4362214c74517da6d6aeaa9bd"
-                 "09ac42b26621cd88f3a6eb013772fc3bf9f83914b6467231c630202c35b3e"
-                 "5808c659") ||
-      !BN_hex2bn(&key->e, "010001") ||
-      !BN_hex2bn(&key->d,
-                 "0365db9eb6d73b53b015c40cd8db4de7dd7035c68b5ac1bf786d7a4ee2cea"
-                 "316eaeca21a73ac365e58713195f2ae9849348525ca855386b6d028e437a9"
-                 "495a01") ||
-      RSA_size(key) > sizeof(buf)) {
-    goto err;
-  }
-
-  if (!RSA_check_key(key)) {
-    fprintf(stderr, "RSA_check_key failed with only d given.\n");
-    ERR_print_errors_fp(stderr);
-    goto err;
-  }
-
-  if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
-                key)) {
-    fprintf(stderr, "RSA_sign failed with only d given.\n");
-    ERR_print_errors_fp(stderr);
-    goto err;
-  }
-
-  if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
-                  key)) {
-    fprintf(stderr, "RSA_verify failed with only d given.\n");
-    ERR_print_errors_fp(stderr);
-    goto err;
-  }
-
-  ret = 1;
-
-err:
-  RSA_free(key);
-  return ret;
-}
-
-static int test_recover_crt_params(void) {
-  RSA *key1, *key2;
-  BIGNUM *e = BN_new();
-  uint8_t buf[128];
-  unsigned buf_len = sizeof(buf);
-  const uint8_t kDummyHash[16] = {0};
-  unsigned i;
-
-  BN_set_word(e, RSA_F4);
-
-  ERR_clear_error();
-
-  for (i = 0; i < 1; i++) {
-    key1 = RSA_new();
-    if (!RSA_generate_key_ex(key1, 512, e, NULL)) {
-      fprintf(stderr, "RSA_generate_key_ex failed.\n");
-      ERR_print_errors_fp(stderr);
-      return 0;
-    }
-
-    if (!RSA_check_key(key1)) {
-      fprintf(stderr, "RSA_check_key failed with original key.\n");
-      ERR_print_errors_fp(stderr);
-      return 0;
-    }
-
-    key2 = RSA_new();
-    key2->n = BN_dup(key1->n);
-    key2->e = BN_dup(key1->e);
-    key2->d = BN_dup(key1->d);
-    RSA_free(key1);
-
-    if (!RSA_recover_crt_params(key2)) {
-      fprintf(stderr, "RSA_recover_crt_params failed.\n");
-      ERR_print_errors_fp(stderr);
-      return 0;
-    }
-
-    if (RSA_size(key2) > buf_len) {
-      return 0;
-    }
-
-    if (!RSA_check_key(key2)) {
-      fprintf(stderr, "RSA_check_key failed with recovered key.\n");
-      ERR_print_errors_fp(stderr);
-      return 0;
-    }
-
-    if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
-                  key2)) {
-      fprintf(stderr, "RSA_sign failed with recovered key.\n");
-      ERR_print_errors_fp(stderr);
-      return 0;
-    }
-
-    if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
-                    key2)) {
-      fprintf(stderr, "RSA_verify failed with recovered key.\n");
-      ERR_print_errors_fp(stderr);
-      return 0;
-    }
-
-    RSA_free(key2);
-  }
-
-  BN_free(e);
-  return 1;
-}
-
-int main(int argc, char *argv[]) {
-  int err = 0;
-  int v;
-  RSA *key;
-  unsigned char ptext[256];
-  unsigned char ctext[256];
-  static unsigned char ptext_ex[] = "\x54\x85\x9b\x34\x2c\x49\xea\x2a";
-  unsigned char ctext_ex[256];
-  int plen;
-  int clen = 0;
-  int num;
-  int n;
-
-  CRYPTO_library_init();
-
-  plen = sizeof(ptext_ex) - 1;
-
-  for (v = 0; v < 3; v++) {
-    key = RSA_new();
-    switch (v) {
-      case 0:
-        clen = key1(key, ctext_ex);
-        break;
-      case 1:
-        clen = key2(key, ctext_ex);
-        break;
-      case 2:
-        clen = key3(key, ctext_ex);
-        break;
-      default:
-        abort();
-    }
-
-    if (!RSA_check_key(key)) {
-      printf("%d: RSA_check_key failed\n", v);
-      err = 1;
-      goto oaep;
-    }
-
-    num = RSA_public_encrypt(plen, ptext_ex, ctext, key, RSA_PKCS1_PADDING);
-    if (num != clen) {
-      printf("PKCS#1 v1.5 encryption failed!\n");
-      err = 1;
-      goto oaep;
-    }
-
-    num = RSA_private_decrypt(num, ctext, ptext, key, RSA_PKCS1_PADDING);
-    if (num != plen || memcmp(ptext, ptext_ex, num) != 0) {
-      printf("PKCS#1 v1.5 decryption failed!\n");
-      err = 1;
-    } else {
-      printf("PKCS #1 v1.5 encryption/decryption ok\n");
-    }
-
-  oaep:
-    ERR_clear_error();
-    num =
-        RSA_public_encrypt(plen, ptext_ex, ctext, key, RSA_PKCS1_OAEP_PADDING);
-    if (num == -1) {
-      printf("No OAEP support\n");
-      goto next;
-    }
-    if (num != clen) {
-      printf("OAEP encryption failed!\n");
-      err = 1;
-      goto next;
-    }
-
-    num = RSA_private_decrypt(num, ctext, ptext, key, RSA_PKCS1_OAEP_PADDING);
-    if (num != plen || memcmp(ptext, ptext_ex, num) != 0) {
-      printf("OAEP decryption (encrypted data) failed!\n");
-      err = 1;
-    } else if (memcmp(ctext, ctext_ex, num) == 0) {
-      printf("OAEP test vector %d passed!\n", v);
-    }
-
-    /* Different ciphertexts (rsa_oaep.c without -DPKCS_TESTVECT).
-       Try decrypting ctext_ex */
-
-    num =
-        RSA_private_decrypt(clen, ctext_ex, ptext, key, RSA_PKCS1_OAEP_PADDING);
-
-    if (num != plen || memcmp(ptext, ptext_ex, num) != 0) {
-      printf("OAEP decryption (test vector data) failed!\n");
-      err = 1;
-    } else {
-      printf("OAEP encryption/decryption ok\n");
-    }
-
-    /* Try decrypting corrupted ciphertexts */
-    for (n = 0; n < clen; ++n) {
-      int b;
-      unsigned char saved = ctext[n];
-      for (b = 0; b < 256; ++b) {
-        if (b == saved) {
-          continue;
-        }
-        ctext[n] = b;
-        num =
-            RSA_private_decrypt(num, ctext, ptext, key, RSA_PKCS1_OAEP_PADDING);
-        if (num > 0) {
-          printf("Corrupt data decrypted!\n");
-          err = 1;
-        }
-      }
-    }
-
-  next:
-    RSA_free(key);
-  }
-
-  if (err != 0 ||
-      !test_only_d_given() ||
-      !test_recover_crt_params() ||
-      !test_bad_key()) {
-    err = 1;
-  }
-
-  if (err == 0) {
-    printf("PASS\n");
-  }
-  return err;
-}
diff --git a/src/crypto/rsa/rsa_test.cc b/src/crypto/rsa/rsa_test.cc
new file mode 100644
index 0000000..d52b78b
--- /dev/null
+++ b/src/crypto/rsa/rsa_test.cc
@@ -0,0 +1,869 @@
+/* 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/rsa.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/bytestring.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+
+#include "../test/scoped_types.h"
+
+
+// kPlaintext is a sample plaintext.
+static const uint8_t kPlaintext[] = "\x54\x85\x9b\x34\x2c\x49\xea\x2a";
+static const size_t kPlaintextLen = sizeof(kPlaintext) - 1;
+
+// kKey1 is a DER-encoded RSAPrivateKey.
+static const uint8_t kKey1[] =
+    "\x30\x82\x01\x38\x02\x01\x00\x02\x41\x00\xaa\x36\xab\xce\x88\xac\xfd\xff"
+    "\x55\x52\x3c\x7f\xc4\x52\x3f\x90\xef\xa0\x0d\xf3\x77\x4a\x25\x9f\x2e\x62"
+    "\xb4\xc5\xd9\x9c\xb5\xad\xb3\x00\xa0\x28\x5e\x53\x01\x93\x0e\x0c\x70\xfb"
+    "\x68\x76\x93\x9c\xe6\x16\xce\x62\x4a\x11\xe0\x08\x6d\x34\x1e\xbc\xac\xa0"
+    "\xa1\xf5\x02\x01\x11\x02\x40\x0a\x03\x37\x48\x62\x64\x87\x69\x5f\x5f\x30"
+    "\xbc\x38\xb9\x8b\x44\xc2\xcd\x2d\xff\x43\x40\x98\xcd\x20\xd8\xa1\x38\xd0"
+    "\x90\xbf\x64\x79\x7c\x3f\xa7\xa2\xcd\xcb\x3c\xd1\xe0\xbd\xba\x26\x54\xb4"
+    "\xf9\xdf\x8e\x8a\xe5\x9d\x73\x3d\x9f\x33\xb3\x01\x62\x4a\xfd\x1d\x51\x02"
+    "\x21\x00\xd8\x40\xb4\x16\x66\xb4\x2e\x92\xea\x0d\xa3\xb4\x32\x04\xb5\xcf"
+    "\xce\x33\x52\x52\x4d\x04\x16\xa5\xa4\x41\xe7\x00\xaf\x46\x12\x0d\x02\x21"
+    "\x00\xc9\x7f\xb1\xf0\x27\xf4\x53\xf6\x34\x12\x33\xea\xaa\xd1\xd9\x35\x3f"
+    "\x6c\x42\xd0\x88\x66\xb1\xd0\x5a\x0f\x20\x35\x02\x8b\x9d\x89\x02\x20\x59"
+    "\x0b\x95\x72\xa2\xc2\xa9\xc4\x06\x05\x9d\xc2\xab\x2f\x1d\xaf\xeb\x7e\x8b"
+    "\x4f\x10\xa7\x54\x9e\x8e\xed\xf5\xb4\xfc\xe0\x9e\x05\x02\x21\x00\x8e\x3c"
+    "\x05\x21\xfe\x15\xe0\xea\x06\xa3\x6f\xf0\xf1\x0c\x99\x52\xc3\x5b\x7a\x75"
+    "\x14\xfd\x32\x38\xb8\x0a\xad\x52\x98\x62\x8d\x51\x02\x20\x36\x3f\xf7\x18"
+    "\x9d\xa8\xe9\x0b\x1d\x34\x1f\x71\xd0\x9b\x76\xa8\xa9\x43\xe1\x1d\x10\xb2"
+    "\x4d\x24\x9f\x2d\xea\xfe\xf8\x0c\x18\x26";
+
+// kOAEPCiphertext1 is a sample encryption of |kPlaintext| with |kKey1| using
+// RSA OAEP.
+static const uint8_t kOAEPCiphertext1[] =
+    "\x1b\x8f\x05\xf9\xca\x1a\x79\x52\x6e\x53\xf3\xcc\x51\x4f\xdb\x89\x2b\xfb"
+    "\x91\x93\x23\x1e\x78\xb9\x92\xe6\x8d\x50\xa4\x80\xcb\x52\x33\x89\x5c\x74"
+    "\x95\x8d\x5d\x02\xab\x8c\x0f\xd0\x40\xeb\x58\x44\xb0\x05\xc3\x9e\xd8\x27"
+    "\x4a\x9d\xbf\xa8\x06\x71\x40\x94\x39\xd2";
+
+// kKey2 is a DER-encoded RSAPrivateKey.
+static const uint8_t kKey2[] =
+    "\x30\x81\xfb\x02\x01\x00\x02\x33\x00\xa3\x07\x9a\x90\xdf\x0d\xfd\x72\xac"
+    "\x09\x0c\xcc\x2a\x78\xb8\x74\x13\x13\x3e\x40\x75\x9c\x98\xfa\xf8\x20\x4f"
+    "\x35\x8a\x0b\x26\x3c\x67\x70\xe7\x83\xa9\x3b\x69\x71\xb7\x37\x79\xd2\x71"
+    "\x7b\xe8\x34\x77\xcf\x02\x01\x03\x02\x32\x6c\xaf\xbc\x60\x94\xb3\xfe\x4c"
+    "\x72\xb0\xb3\x32\xc6\xfb\x25\xa2\xb7\x62\x29\x80\x4e\x68\x65\xfc\xa4\x5a"
+    "\x74\xdf\x0f\x8f\xb8\x41\x3b\x52\xc0\xd0\xe5\x3d\x9b\x59\x0f\xf1\x9b\xe7"
+    "\x9f\x49\xdd\x21\xe5\xeb\x02\x1a\x00\xcf\x20\x35\x02\x8b\x9d\x86\x98\x40"
+    "\xb4\x16\x66\xb4\x2e\x92\xea\x0d\xa3\xb4\x32\x04\xb5\xcf\xce\x91\x02\x1a"
+    "\x00\xc9\x7f\xb1\xf0\x27\xf4\x53\xf6\x34\x12\x33\xea\xaa\xd1\xd9\x35\x3f"
+    "\x6c\x42\xd0\x88\x66\xb1\xd0\x5f\x02\x1a\x00\x8a\x15\x78\xac\x5d\x13\xaf"
+    "\x10\x2b\x22\xb9\x99\xcd\x74\x61\xf1\x5e\x6d\x22\xcc\x03\x23\xdf\xdf\x0b"
+    "\x02\x1a\x00\x86\x55\x21\x4a\xc5\x4d\x8d\x4e\xcd\x61\x77\xf1\xc7\x36\x90"
+    "\xce\x2a\x48\x2c\x8b\x05\x99\xcb\xe0\x3f\x02\x1a\x00\x83\xef\xef\xb8\xa9"
+    "\xa4\x0d\x1d\xb6\xed\x98\xad\x84\xed\x13\x35\xdc\xc1\x08\xf3\x22\xd0\x57"
+    "\xcf\x8d";
+
+// kOAEPCiphertext2 is a sample encryption of |kPlaintext| with |kKey2| using
+// RSA OAEP.
+static const uint8_t kOAEPCiphertext2[] =
+    "\x14\xbd\xdd\x28\xc9\x83\x35\x19\x23\x80\xe8\xe5\x49\xb1\x58\x2a\x8b\x40"
+    "\xb4\x48\x6d\x03\xa6\xa5\x31\x1f\x1f\xd5\xf0\xa1\x80\xe4\x17\x53\x03\x29"
+    "\xa9\x34\x90\x74\xb1\x52\x13\x54\x29\x08\x24\x52\x62\x51";
+
+// kKey3 is a DER-encoded RSAPrivateKey.
+static const uint8_t kKey3[] =
+    "\x30\x82\x02\x5b\x02\x01\x00\x02\x81\x81\x00\xbb\xf8\x2f\x09\x06\x82\xce"
+    "\x9c\x23\x38\xac\x2b\x9d\xa8\x71\xf7\x36\x8d\x07\xee\xd4\x10\x43\xa4\x40"
+    "\xd6\xb6\xf0\x74\x54\xf5\x1f\xb8\xdf\xba\xaf\x03\x5c\x02\xab\x61\xea\x48"
+    "\xce\xeb\x6f\xcd\x48\x76\xed\x52\x0d\x60\xe1\xec\x46\x19\x71\x9d\x8a\x5b"
+    "\x8b\x80\x7f\xaf\xb8\xe0\xa3\xdf\xc7\x37\x72\x3e\xe6\xb4\xb7\xd9\x3a\x25"
+    "\x84\xee\x6a\x64\x9d\x06\x09\x53\x74\x88\x34\xb2\x45\x45\x98\x39\x4e\xe0"
+    "\xaa\xb1\x2d\x7b\x61\xa5\x1f\x52\x7a\x9a\x41\xf6\xc1\x68\x7f\xe2\x53\x72"
+    "\x98\xca\x2a\x8f\x59\x46\xf8\xe5\xfd\x09\x1d\xbd\xcb\x02\x01\x11\x02\x81"
+    "\x81\x00\xa5\xda\xfc\x53\x41\xfa\xf2\x89\xc4\xb9\x88\xdb\x30\xc1\xcd\xf8"
+    "\x3f\x31\x25\x1e\x06\x68\xb4\x27\x84\x81\x38\x01\x57\x96\x41\xb2\x94\x10"
+    "\xb3\xc7\x99\x8d\x6b\xc4\x65\x74\x5e\x5c\x39\x26\x69\xd6\x87\x0d\xa2\xc0"
+    "\x82\xa9\x39\xe3\x7f\xdc\xb8\x2e\xc9\x3e\xda\xc9\x7f\xf3\xad\x59\x50\xac"
+    "\xcf\xbc\x11\x1c\x76\xf1\xa9\x52\x94\x44\xe5\x6a\xaf\x68\xc5\x6c\x09\x2c"
+    "\xd3\x8d\xc3\xbe\xf5\xd2\x0a\x93\x99\x26\xed\x4f\x74\xa1\x3e\xdd\xfb\xe1"
+    "\xa1\xce\xcc\x48\x94\xaf\x94\x28\xc2\xb7\xb8\x88\x3f\xe4\x46\x3a\x4b\xc8"
+    "\x5b\x1c\xb3\xc1\x02\x41\x00\xee\xcf\xae\x81\xb1\xb9\xb3\xc9\x08\x81\x0b"
+    "\x10\xa1\xb5\x60\x01\x99\xeb\x9f\x44\xae\xf4\xfd\xa4\x93\xb8\x1a\x9e\x3d"
+    "\x84\xf6\x32\x12\x4e\xf0\x23\x6e\x5d\x1e\x3b\x7e\x28\xfa\xe7\xaa\x04\x0a"
+    "\x2d\x5b\x25\x21\x76\x45\x9d\x1f\x39\x75\x41\xba\x2a\x58\xfb\x65\x99\x02"
+    "\x41\x00\xc9\x7f\xb1\xf0\x27\xf4\x53\xf6\x34\x12\x33\xea\xaa\xd1\xd9\x35"
+    "\x3f\x6c\x42\xd0\x88\x66\xb1\xd0\x5a\x0f\x20\x35\x02\x8b\x9d\x86\x98\x40"
+    "\xb4\x16\x66\xb4\x2e\x92\xea\x0d\xa3\xb4\x32\x04\xb5\xcf\xce\x33\x52\x52"
+    "\x4d\x04\x16\xa5\xa4\x41\xe7\x00\xaf\x46\x15\x03\x02\x40\x54\x49\x4c\xa6"
+    "\x3e\xba\x03\x37\xe4\xe2\x40\x23\xfc\xd6\x9a\x5a\xeb\x07\xdd\xdc\x01\x83"
+    "\xa4\xd0\xac\x9b\x54\xb0\x51\xf2\xb1\x3e\xd9\x49\x09\x75\xea\xb7\x74\x14"
+    "\xff\x59\xc1\xf7\x69\x2e\x9a\x2e\x20\x2b\x38\xfc\x91\x0a\x47\x41\x74\xad"
+    "\xc9\x3c\x1f\x67\xc9\x81\x02\x40\x47\x1e\x02\x90\xff\x0a\xf0\x75\x03\x51"
+    "\xb7\xf8\x78\x86\x4c\xa9\x61\xad\xbd\x3a\x8a\x7e\x99\x1c\x5c\x05\x56\xa9"
+    "\x4c\x31\x46\xa7\xf9\x80\x3f\x8f\x6f\x8a\xe3\x42\xe9\x31\xfd\x8a\xe4\x7a"
+    "\x22\x0d\x1b\x99\xa4\x95\x84\x98\x07\xfe\x39\xf9\x24\x5a\x98\x36\xda\x3d"
+    "\x02\x41\x00\xb0\x6c\x4f\xda\xbb\x63\x01\x19\x8d\x26\x5b\xdb\xae\x94\x23"
+    "\xb3\x80\xf2\x71\xf7\x34\x53\x88\x50\x93\x07\x7f\xcd\x39\xe2\x11\x9f\xc9"
+    "\x86\x32\x15\x4f\x58\x83\xb1\x67\xa9\x67\xbf\x40\x2b\x4e\x9e\x2e\x0f\x96"
+    "\x56\xe6\x98\xea\x36\x66\xed\xfb\x25\x79\x80\x39\xf7";
+
+// kOAEPCiphertext3 is a sample encryption of |kPlaintext| with |kKey3| using
+// RSA OAEP.
+static const uint8_t kOAEPCiphertext3[] =
+    "\xb8\x24\x6b\x56\xa6\xed\x58\x81\xae\xb5\x85\xd9\xa2\x5b\x2a\xd7\x90\xc4"
+    "\x17\xe0\x80\x68\x1b\xf1\xac\x2b\xc3\xde\xb6\x9d\x8b\xce\xf0\xc4\x36\x6f"
+    "\xec\x40\x0a\xf0\x52\xa7\x2e\x9b\x0e\xff\xb5\xb3\xf2\xf1\x92\xdb\xea\xca"
+    "\x03\xc1\x27\x40\x05\x71\x13\xbf\x1f\x06\x69\xac\x22\xe9\xf3\xa7\x85\x2e"
+    "\x3c\x15\xd9\x13\xca\xb0\xb8\x86\x3a\x95\xc9\x92\x94\xce\x86\x74\x21\x49"
+    "\x54\x61\x03\x46\xf4\xd4\x74\xb2\x6f\x7c\x48\xb4\x2e\xe6\x8e\x1f\x57\x2a"
+    "\x1f\xc4\x02\x6a\xc4\x56\xb4\xf5\x9f\x7b\x62\x1e\xa1\xb9\xd8\x8f\x64\x20"
+    "\x2f\xb1";
+
+static const uint8_t kTwoPrimeKey[] =
+    "\x30\x82\x04\xa1\x02\x01\x00\x02\x82\x01\x01\x00\x93\x3a\x4f\xc9\x6a\x0a"
+    "\x6b\x28\x04\xfa\xb7\x05\x56\xdf\xa0\xaa\x4f\xaa\xab\x94\xa0\xa9\x25\xef"
+    "\xc5\x96\xd2\xd4\x66\x16\x62\x2c\x13\x7b\x91\xd0\x36\x0a\x10\x11\x6d\x7a"
+    "\x91\xb6\xe4\x74\x57\xc1\x3d\x7a\xbe\x24\x05\x3a\x04\x0b\x73\x91\x53\xb1"
+    "\x74\x10\xe1\x87\xdc\x91\x28\x9c\x1e\xe5\xf2\xb9\xfc\xa2\x48\x34\xb6\x78"
+    "\xed\x6d\x95\xfb\xf2\xc0\x4e\x1c\xa4\x15\x00\x3c\x8a\x68\x2b\xd6\xce\xd5"
+    "\xb3\x9f\x66\x02\xa7\x0d\x08\xa3\x23\x9b\xe5\x36\x96\x13\x22\xf9\x69\xa6"
+    "\x87\x88\x9b\x85\x3f\x83\x9c\xab\x1a\x1b\x6d\x8d\x16\xf4\x5e\xbd\xee\x4b"
+    "\x59\x56\xf8\x9d\x58\xcd\xd2\x83\x85\x59\x43\x84\x63\x4f\xe6\x1a\x86\x66"
+    "\x0d\xb5\xa0\x87\x89\xb6\x13\x82\x43\xda\x34\x92\x3b\x68\xc4\x95\x71\x2f"
+    "\x15\xc2\xe0\x43\x67\x3c\x08\x00\x36\x10\xc3\xb4\x46\x4c\x4e\x6e\xf5\x44"
+    "\xa9\x04\x44\x9d\xce\xc7\x05\x79\xee\x11\xcf\xaf\x2c\xd7\x9a\x32\xd3\xa5"
+    "\x30\xd4\x3a\x78\x43\x37\x74\x22\x90\x24\x04\x11\xd7\x95\x08\x52\xa4\x71"
+    "\x41\x68\x94\xb0\xa0\xc3\xec\x4e\xd2\xc4\x30\x71\x98\x64\x9c\xe3\x7c\x76"
+    "\xef\x33\xa3\x2b\xb1\x87\x63\xd2\x5c\x09\xfc\x90\x2d\x92\xf4\x57\x02\x01"
+    "\x03\x02\x82\x01\x00\x62\x26\xdf\xdb\x9c\x06\xf2\x1a\xad\xfc\x7a\x03\x8f"
+    "\x3f\xc0\x71\x8a\x71\xc7\xb8\x6b\x1b\x6e\x9f\xd9\x0f\x37\x38\x44\x0e\xec"
+    "\x1d\x62\x52\x61\x35\x79\x5c\x0a\xb6\x48\xfc\x61\x24\x98\x4d\x8f\xd6\x28"
+    "\xfc\x7e\xc2\xae\x26\xad\x5c\xf7\xb6\x37\xcb\xa2\xb5\xeb\xaf\xe8\x60\xc5"
+    "\xbd\x69\xee\xa1\xd1\x53\x16\xda\xcd\xce\xfb\x48\xf3\xb9\x52\xa1\xd5\x89"
+    "\x68\x6d\x63\x55\x7d\xb1\x9a\xc7\xe4\x89\xe3\xcd\x14\xee\xac\x6f\x5e\x05"
+    "\xc2\x17\xbd\x43\x79\xb9\x62\x17\x50\xf1\x19\xaf\xb0\x67\xae\x2a\x57\xbd"
+    "\xc7\x66\xbc\xf3\xb3\x64\xa1\xe3\x16\x74\x9e\xea\x02\x5c\xab\x94\xd8\x97"
+    "\x02\x42\x0c\x2c\xba\x54\xb9\xaf\xe0\x45\x93\xad\x7f\xb3\x10\x6a\x96\x50"
+    "\x4b\xaf\xcf\xc8\x27\x62\x2d\x83\xe9\x26\xc6\x94\xc1\xef\x5c\x8e\x06\x42"
+    "\x53\xe5\x56\xaf\xc2\x99\x01\xaa\x9a\x71\xbc\xe8\x21\x33\x2a\x2d\xa3\x36"
+    "\xac\x1b\x86\x19\xf8\xcd\x1f\x80\xa4\x26\x98\xb8\x9f\x62\x62\xd5\x1a\x7f"
+    "\xee\xdb\xdf\x81\xd3\x21\xdb\x33\x92\xee\xff\xe2\x2f\x32\x77\x73\x6a\x58"
+    "\xab\x21\xf3\xe3\xe1\xbc\x4f\x12\x72\xa6\xb5\xc2\xfb\x27\x9e\xc8\xca\xab"
+    "\x64\xa0\x87\x07\x9d\xef\xca\x0f\xdb\x02\x81\x81\x00\xe6\xd3\x4d\xc0\xa1"
+    "\x91\x0e\x62\xfd\xb0\xdd\xc6\x30\xb8\x8c\xcb\x14\xc1\x4b\x69\x30\xdd\xcd"
+    "\x86\x67\xcb\x37\x14\xc5\x03\xd2\xb4\x69\xab\x3d\xe5\x16\x81\x0f\xe5\x50"
+    "\xf4\x18\xb1\xec\xbc\x71\xe9\x80\x99\x06\xe4\xa3\xfe\x44\x84\x4a\x2d\x1e"
+    "\x07\x7f\x22\x70\x6d\x4f\xd4\x93\x0b\x8b\x99\xce\x1e\xab\xcd\x4c\xd2\xd3"
+    "\x10\x47\x5c\x09\x9f\x6d\x82\xc0\x08\x75\xe3\x3d\x83\xc2\x19\x50\x29\xec"
+    "\x1f\x84\x29\xcc\xf1\x56\xee\xbd\x54\x5d\xe6\x19\xdf\x0d\x1c\xa4\xbb\x0a"
+    "\xfe\x84\x44\x29\x1d\xf9\x5c\x80\x96\x5b\x24\xb4\xf7\x02\x1b\x02\x81\x81"
+    "\x00\xa3\x48\xf1\x9c\x58\xc2\x5f\x38\xfb\xd8\x12\x39\xf1\x8e\x73\xa1\xcf"
+    "\x78\x12\xe0\xed\x2a\xbb\xef\xac\x23\xb2\xbf\xd6\x0c\xe9\x6e\x1e\xab\xea"
+    "\x3f\x68\x36\xa7\x1f\xe5\xab\xe0\x86\xa5\x76\x32\x98\xdd\x75\xb5\x2b\xbc"
+    "\xcb\x8a\x03\x00\x7c\x2e\xca\xf8\xbc\x19\xe4\xe3\xa3\x31\xbd\x1d\x20\x2b"
+    "\x09\xad\x6f\x4c\xed\x48\xd4\xdf\x87\xf9\xf0\x46\xb9\x86\x4c\x4b\x71\xe7"
+    "\x48\x78\xdc\xed\xc7\x82\x02\x44\xd3\xa6\xb3\x10\x5f\x62\x81\xfc\xb8\xe4"
+    "\x0e\xf4\x1a\xdd\xab\x3f\xbc\x63\x79\x5b\x39\x69\x5e\xea\xa9\x15\xfe\x90"
+    "\xec\xda\x75\x02\x81\x81\x00\x99\xe2\x33\xd5\xc1\x0b\x5e\xec\xa9\x20\x93"
+    "\xd9\x75\xd0\x5d\xdc\xb8\x80\xdc\xf0\xcb\x3e\x89\x04\x45\x32\x24\xb8\x83"
+    "\x57\xe1\xcd\x9b\xc7\x7e\x98\xb9\xab\x5f\xee\x35\xf8\x10\x76\x9d\xd2\xf6"
+    "\x9b\xab\x10\xaf\x43\x17\xfe\xd8\x58\x31\x73\x69\x5a\x54\xc1\xa0\x48\xdf"
+    "\xe3\x0c\xb2\x5d\x11\x34\x14\x72\x88\xdd\xe1\xe2\x0a\xda\x3d\x5b\xbf\x9e"
+    "\x57\x2a\xb0\x4e\x97\x7e\x57\xd6\xbb\x8a\xc6\x9d\x6a\x58\x1b\xdd\xf6\x39"
+    "\xf4\x7e\x38\x3e\x99\x66\x94\xb3\x68\x6d\xd2\x07\x54\x58\x2d\x70\xbe\xa6"
+    "\x3d\xab\x0e\xe7\x6d\xcd\xfa\x01\x67\x02\x81\x80\x6c\xdb\x4b\xbd\x90\x81"
+    "\x94\xd0\xa7\xe5\x61\x7b\xf6\x5e\xf7\xc1\x34\xfa\xb7\x40\x9e\x1c\x7d\x4a"
+    "\x72\xc2\x77\x2a\x8e\xb3\x46\x49\x69\xc7\xf1\x7f\x9a\xcf\x1a\x15\x43\xc7"
+    "\xeb\x04\x6e\x4e\xcc\x65\xe8\xf9\x23\x72\x7d\xdd\x06\xac\xaa\xfd\x74\x87"
+    "\x50\x7d\x66\x98\x97\xc2\x21\x28\xbe\x15\x72\x06\x73\x9f\x88\x9e\x30\x8d"
+    "\xea\x5a\xa6\xa0\x2f\x26\x59\x88\x32\x4b\xef\x85\xa5\xe8\x9e\x85\x01\x56"
+    "\xd8\x8d\x19\xcc\xb5\x94\xec\x56\xa8\x7b\x42\xb4\xa2\xbc\x93\xc7\x7f\xd2"
+    "\xec\xfb\x92\x26\x46\x3f\x47\x1b\x63\xff\x0b\x48\x91\xa3\x02\x81\x80\x2c"
+    "\x4a\xb9\xa4\x46\x7b\xff\x50\x7e\xbf\x60\x47\x3b\x2b\x66\x82\xdc\x0e\x53"
+    "\x65\x71\xe9\xda\x2a\xb8\x32\x93\x42\xb7\xff\xea\x67\x66\xf1\xbc\x87\x28"
+    "\x65\x29\x79\xca\xab\x93\x56\xda\x95\xc1\x26\x44\x3d\x27\xc1\x91\xc6\x9b"
+    "\xd9\xec\x9d\xb7\x49\xe7\x16\xee\x99\x87\x50\x95\x81\xd4\x5c\x5b\x5a\x5d"
+    "\x0a\x43\xa5\xa7\x8f\x5a\x80\x49\xa0\xb7\x10\x85\xc7\xf4\x42\x34\x86\xb6"
+    "\x5f\x3f\x88\x9e\xc7\xf5\x59\x29\x39\x68\x48\xf2\xd7\x08\x5b\x92\x8e\x6b"
+    "\xea\xa5\x63\x5f\xc0\xfb\xe4\xe1\xb2\x7d\xb7\x40\xe9\x55\x06\xbf\x58\x25"
+    "\x6f";
+
+static const uint8_t kTwoPrimeEncryptedMessage[] = {
+    0x63, 0x0a, 0x30, 0x45, 0x43, 0x11, 0x45, 0xb7, 0x99, 0x67, 0x90, 0x35,
+    0x37, 0x27, 0xff, 0xbc, 0xe0, 0xbf, 0xa6, 0xd1, 0x47, 0x50, 0xbb, 0x6c,
+    0x1c, 0xaa, 0x66, 0xf2, 0xff, 0x9d, 0x9a, 0xa6, 0xb4, 0x16, 0x63, 0xb0,
+    0xa1, 0x7c, 0x7c, 0x0c, 0xef, 0xb3, 0x66, 0x52, 0x42, 0xd7, 0x5e, 0xf3,
+    0xa4, 0x15, 0x33, 0x40, 0x43, 0xe8, 0xb1, 0xfc, 0xe0, 0x42, 0x83, 0x46,
+    0x28, 0xce, 0xde, 0x7b, 0x01, 0xeb, 0x28, 0x92, 0x70, 0xdf, 0x8d, 0x54,
+    0x9e, 0xed, 0x23, 0xb4, 0x78, 0xc3, 0xca, 0x85, 0x53, 0x48, 0xd6, 0x8a,
+    0x87, 0xf7, 0x69, 0xcd, 0x82, 0x8c, 0x4f, 0x5c, 0x05, 0x55, 0xa6, 0x78,
+    0x89, 0xab, 0x4c, 0xd8, 0xa9, 0xd6, 0xa5, 0xf4, 0x29, 0x4c, 0x23, 0xc8,
+    0xcf, 0xf0, 0x4c, 0x64, 0x6b, 0x4e, 0x02, 0x17, 0x69, 0xd6, 0x47, 0x83,
+    0x30, 0x43, 0x02, 0x29, 0xda, 0xda, 0x75, 0x3b, 0xd7, 0xa7, 0x2b, 0x31,
+    0xb3, 0xe9, 0x71, 0xa4, 0x41, 0xf7, 0x26, 0x9b, 0xcd, 0x23, 0xfa, 0x45,
+    0x3c, 0x9b, 0x7d, 0x28, 0xf7, 0xf9, 0x67, 0x04, 0xba, 0xfc, 0x46, 0x75,
+    0x11, 0x3c, 0xd5, 0x27, 0x43, 0x53, 0xb1, 0xb6, 0x9e, 0x18, 0xeb, 0x11,
+    0xb4, 0x25, 0x20, 0x30, 0x0b, 0xe0, 0x1c, 0x17, 0x36, 0x22, 0x10, 0x0f,
+    0x99, 0xb5, 0x50, 0x14, 0x73, 0x07, 0xf0, 0x2f, 0x5d, 0x4c, 0xe3, 0xf2,
+    0x86, 0xc2, 0x05, 0xc8, 0x38, 0xed, 0xeb, 0x2a, 0x4a, 0xab, 0x76, 0xe3,
+    0x1a, 0x75, 0x44, 0xf7, 0x6e, 0x94, 0xdc, 0x25, 0x62, 0x7e, 0x31, 0xca,
+    0xc2, 0x73, 0x51, 0xb5, 0x03, 0xfb, 0xf9, 0xf6, 0xb5, 0x8d, 0x4e, 0x6c,
+    0x21, 0x0e, 0xf9, 0x97, 0x26, 0x57, 0xf3, 0x52, 0x72, 0x07, 0xf8, 0xb4,
+    0xcd, 0xb4, 0x39, 0xcf, 0xbf, 0x78, 0xcc, 0xb6, 0x87, 0xf9, 0xb7, 0x8b,
+    0x6a, 0xce, 0x9f, 0xc8,
+};
+
+static const uint8_t kThreePrimeKey[] =
+    "\x30\x82\x04\xd7\x02\x01\x01\x02\x82\x01\x00\x62\x91\xe9\xea\xb3\x5d\x6c"
+    "\x29\xae\x21\x83\xbb\xb5\x82\xb1\x9e\xea\xe0\x64\x5b\x1e\x2f\x5e\x2c\x0a"
+    "\x80\x3d\x29\xd4\xfa\x9a\xe7\x44\xe6\x21\xbd\x98\xc0\x3d\xe0\x53\x59\xae"
+    "\xd3\x3e\xfe\xc4\xc2\xc4\x5a\x5a\x89\x07\xf4\x4f\xdc\xb0\x6a\xd4\x3e\x99"
+    "\x7d\x7a\x97\x26\x4e\xe1\x93\xca\x6e\xed\x07\xfc\xb4\xfa\x95\x1e\x73\x7b"
+    "\x86\x08\x6a\xb9\xd4\x29\xb0\x7e\x59\xb7\x9d\x7b\xeb\x67\x6e\xf0\xbb\x5e"
+    "\xcf\xb9\xcd\x58\x93\xf0\xe7\x88\x17\x6c\x0d\x76\x1e\xb9\x27\x9a\x4d\x02"
+    "\x16\xb6\x49\x6d\xa7\x83\x23\x4d\x02\x48\x0c\x0c\x1f\x0e\x85\x21\xe3\x06"
+    "\x76\x0a\x73\xe6\xc1\x21\xfa\x30\x18\x78\x29\x5c\x31\xd0\x29\xae\x6f\x7d"
+    "\x87\xd8\x2f\x16\xfa\xbc\x67\x8a\x94\x71\x59\x9b\xec\x22\x40\x55\x9f\xc2"
+    "\x94\xb5\xbd\x78\x01\xc9\xef\x18\xc8\x6d\x0d\xdc\x53\x42\xb2\x5c\xab\x65"
+    "\x05\xbd\x35\x08\x85\x1b\xf8\xe9\x47\xbc\xfe\xc5\xae\x47\x29\x63\x44\x8e"
+    "\x4d\xb7\x47\xab\x0d\xd8\x76\x68\x4f\xc7\x07\x02\xe4\x86\xb0\xcf\xd8\x19"
+    "\xad\xf4\x85\x76\x8b\x3b\x4e\x40\x8d\x29\x7a\x8a\x07\x36\xf3\x78\xae\x17"
+    "\xa6\x8f\x53\x58\x65\x4c\x86\x9e\xd7\x8b\xec\x38\x4f\x99\xc7\x02\x01\x03"
+    "\x02\x82\x01\x00\x41\xb6\x9b\xf1\xcc\xe8\xf2\xc6\x74\x16\x57\xd2\x79\x01"
+    "\xcb\xbf\x47\x40\x42\xe7\x69\x74\xe9\x72\xb1\xaa\xd3\x71\x38\xa7\x11\xef"
+    "\x83\x44\x16\x7e\x65\xd5\x7e\x95\x8c\xe6\x74\x8c\xd4\xa9\xd8\x81\xd8\x3c"
+    "\x3c\x5b\x5a\xa2\xdf\xe8\x75\x9c\x8d\x7f\x10\xfe\x51\xba\x19\x89\xeb\xb7"
+    "\xdc\x49\xf3\x5a\xa8\x78\xa7\x0e\x14\x4c\xfd\x04\x05\x9c\x7b\xe2\xc5\xa3"
+    "\x04\xee\xd9\x4c\xfd\x7d\x47\xb0\x0d\x9b\x3d\x70\x91\x81\x2c\xab\x2b\x87"
+    "\xad\x11\x68\x24\xfc\x2b\xd4\xee\x5e\x28\xeb\x6d\xab\xde\x0f\x77\x15\x58"
+    "\x76\x39\xc9\x59\x3a\x7f\x19\x9d\xc6\x7e\x86\xe4\xd5\x38\x70\x9e\xae\xb9"
+    "\xfb\x33\x33\xd1\x0c\x2d\xab\x01\x20\xe1\x8b\x29\x99\xd3\xeb\x87\x05\x72"
+    "\xaa\x43\x58\x64\x8e\x9e\x31\xdb\x45\x9b\x2b\xac\x58\x80\x5d\x33\xa2\x43"
+    "\x05\x96\xcc\xca\x2d\x04\x5f\xd6\xb7\x3d\x8b\x8f\x2d\xa3\xa5\xf8\x73\xf5"
+    "\xd7\xc0\x19\xff\x10\xe6\xee\x3a\x26\x2f\xe1\x64\x3d\x11\xcd\x2d\xe4\x0a"
+    "\x84\x27\xe3\xcb\x16\x62\x19\xe7\xe3\x0d\x13\xe8\x09\x5a\x53\xd0\x20\x56"
+    "\x15\xf5\xb3\x67\xac\xa1\xb5\x94\x6b\xab\xdc\x71\xc7\xbf\x0a\xde\x76\xf5"
+    "\x03\xa0\x30\xd8\x27\x9d\x00\x2b\x02\x57\x00\xf1\x4f\xc2\x86\x13\x06\x17"
+    "\xf7\x69\x7e\x37\xdf\x67\xc5\x32\xa0\x74\x1c\x32\x69\x0f\x9f\x08\x88\x24"
+    "\xb1\x51\xbc\xbc\x92\xba\x73\x1f\x9c\x75\xc2\x14\x6d\x4f\xc4\x5a\xcf\xda"
+    "\x44\x35\x00\x6b\x42\x3b\x9f\x14\xf1\x05\xb3\x51\x22\xb6\xbe\x9c\xe0\xc1"
+    "\x5c\x48\x61\xdf\x4e\x4c\x72\xb8\x05\x35\x7c\xac\xf1\xbb\xa0\x3b\x2a\xea"
+    "\xf7\x86\xe9\xd2\xff\x1e\x1d\x02\x56\x00\xca\xb1\x39\xf6\xa2\xc6\x3b\x65"
+    "\x45\x2f\x39\x00\xcd\x6e\xd6\x55\xf7\x71\x37\x89\xc2\xe7\x7a\xc0\x1a\xa6"
+    "\x2f\xea\x17\x7c\xaa\x2a\x91\x8f\xd4\xc7\x50\x8b\xab\x8e\x99\x3b\x33\x91"
+    "\xbc\x02\x10\x58\x4b\x58\x40\x9b\xc4\x8f\x48\x2b\xa7\x44\xfd\x07\x04\xf0"
+    "\x98\x67\x56\xea\x25\x92\x8b\x2e\x4b\x4a\xa1\xd3\xc2\xa4\xb4\x9b\x59\x70"
+    "\x32\xa6\xd8\x8b\xd9\x02\x57\x00\xa0\xdf\xd7\x04\x0c\xae\xba\xa4\xf0\xfe"
+    "\xcf\xea\x45\x2e\x21\xc0\x4d\x68\x21\x9b\x5f\xbf\x5b\x05\x6d\xcb\x8b\xd3"
+    "\x28\x61\xd1\xa2\x15\x12\xf9\x2c\x0d\x9e\x35\x2d\x91\xdf\xe6\xd8\x23\x55"
+    "\x9c\xd6\xd2\x6a\x0d\xf6\x03\xcc\xe0\xc1\xcf\x29\xbd\xeb\x2b\x92\xda\xeb"
+    "\xea\x34\x32\xf7\x25\x58\xce\x53\x1d\xf6\x7d\x15\x7c\xc7\x47\x4f\xaf\x46"
+    "\x8c\xaa\x14\x13\x02\x56\x00\x87\x20\xd1\x4f\x17\x2e\xd2\x43\x83\x74\xd0"
+    "\xab\x33\x9f\x39\x8e\xa4\xf6\x25\x06\x81\xef\xa7\x2a\xbc\x6e\xca\x9c\x0f"
+    "\xa8\x71\x71\xb6\x5f\xe3\x2f\x8b\x07\xc7\xb4\x66\x27\x77\xb6\x7d\x56\xb5"
+    "\x90\x32\x3a\xd5\xbd\x2d\xb4\xda\xc7\xc4\xd8\xa8\xaf\x58\xa0\x65\x9a\x39"
+    "\xf1\x6e\x61\xb2\x1e\xdc\xdc\x6b\xe2\x81\xc3\x23\x12\x3b\xa0\x21\xc4\x90"
+    "\x5d\x3b\x02\x57\x00\xe6\x8a\xaa\xb8\x6d\x2c\x81\x43\xb5\xd6\xa0\x2b\x42"
+    "\x49\xa9\x0a\x51\xfa\x18\xc8\x32\xea\x54\x18\xf3\x60\xc2\xb5\x4a\x43\x05"
+    "\x93\x9c\x01\xd9\x28\xed\x73\xfa\x82\xbc\x12\x64\xcb\xc4\x24\xa9\x3e\xae"
+    "\x7c\x4b\x8f\x94\x57\x7b\x14\x10\x41\xdc\x62\x12\x8c\xb2\x4a\x7c\xf6\x53"
+    "\xd4\xc6\xe4\xda\xd1\xa2\x00\x0e\x3d\x30\xf7\x05\x4f\x1d\x82\xbc\x52\xd9"
+    "\xb1\x30\x82\x01\x0a\x30\x82\x01\x06\x02\x56\x00\x84\x12\x4f\xf7\x3b\x65"
+    "\x53\x34\x6c\x6c\x4d\x77\xdf\xfd\x1f\xb6\x16\xe2\x25\x15\xca\xc9\xc1\x41"
+    "\x9a\x50\xda\xeb\x88\x4f\x3d\xb3\x01\x00\x44\xc4\xac\xe7\x14\x62\xa6\x56"
+    "\xde\xc5\xb7\xc3\x1d\x07\xbd\x7d\x64\xc5\x7e\x45\x25\x56\xed\x7a\xd2\x14"
+    "\xdb\x4e\x27\xd4\x1f\xf8\x94\xa7\xef\x07\xce\xdb\x24\xb7\xdd\x71\x5c\x63"
+    "\xc9\x33\xfe\xde\x40\x52\xeb\x02\x55\x58\x0c\x35\x4f\x7c\xee\x37\x78\x48"
+    "\x48\x33\xa5\x3f\xfe\x15\x24\x0f\x41\x6e\x0e\x87\x31\x2b\x81\x11\x8b\x3c"
+    "\x9d\x05\x8a\x29\x22\x00\xaa\xd8\x83\x1d\xef\x62\xec\x6e\xe4\x94\x83\xcf"
+    "\xd7\x68\xaf\xd3\xa8\xed\xd8\xfe\xd8\xc3\x8f\x48\xfc\x8c\x0d\xe7\x89\x6f"
+    "\xe2\xbf\xfb\x0d\xc5\x4a\x05\x34\x92\x18\x7a\x93\xa0\xe8\x42\x86\x22\xa9"
+    "\xe9\x80\x37\x47\x02\x55\x60\x76\xab\xde\x2b\xf5\xa2\x2c\xaa\x0c\x99\x81"
+    "\xee\x72\x2c\x7d\x22\x59\x2a\x35\xea\x50\x4e\x47\x6b\x92\x2d\x30\xa1\x01"
+    "\xa5\x9e\x26\x6e\x27\xca\xf5\xf2\x87\x5d\x31\xaf\xe9\x32\xcd\x10\xfd\x4d"
+    "\xdb\xf9\x86\x05\x12\x1b\x01\x84\x55\x97\x5f\xe2\x78\x27\xd9\xe4\x26\x7d"
+    "\xab\x0e\xe0\x1b\x6f\xcb\x4b\x14\xdd\xdc\xdc\x8b\xe8\x9f\xd0\x62\x96\xca"
+    "\xcf";
+
+static const uint8_t kThreePrimeEncryptedMessage[] = {
+    0x58, 0xd9, 0xea, 0x8a, 0xf6, 0x3d, 0xb4, 0xd9, 0xf7, 0xbb, 0x02, 0xc5,
+    0x58, 0xd2, 0xa9, 0x46, 0x80, 0x70, 0x70, 0x16, 0x07, 0x64, 0x32, 0x4c,
+    0x4e, 0x92, 0x61, 0xb7, 0xff, 0x92, 0xdc, 0xfc, 0xf8, 0xf0, 0x2c, 0x84,
+    0x56, 0xbc, 0xe5, 0x93, 0x76, 0xe5, 0xa3, 0x72, 0x98, 0xf2, 0xdf, 0xef,
+    0x99, 0x53, 0xf6, 0xd8, 0x4b, 0x09, 0xac, 0xa9, 0xa3, 0xdb, 0x63, 0xa1,
+    0xb5, 0x09, 0x8e, 0x40, 0x84, 0x8f, 0x4d, 0xd5, 0x1d, 0xac, 0x6c, 0xaa,
+    0x6b, 0x15, 0xe7, 0xb1, 0x0c, 0x67, 0xd2, 0xb2, 0x81, 0x58, 0x30, 0x0e,
+    0x18, 0x27, 0xa1, 0x9b, 0x96, 0xad, 0xae, 0x76, 0x1a, 0x32, 0xf7, 0x10,
+    0x0b, 0x53, 0x85, 0x31, 0xd6, 0x2a, 0xf6, 0x1c, 0x9f, 0xc2, 0xc7, 0xb1,
+    0x05, 0x63, 0x0b, 0xa5, 0x07, 0x1f, 0x1c, 0x01, 0xf0, 0xe0, 0x06, 0xea,
+    0x20, 0x69, 0x41, 0x19, 0x57, 0x92, 0x17, 0xf7, 0x0c, 0x5c, 0x66, 0x75,
+    0x0e, 0xe5, 0xb3, 0xf1, 0x67, 0x3b, 0x27, 0x47, 0xb2, 0x8e, 0x1c, 0xb6,
+    0x3f, 0xdd, 0x76, 0x42, 0x31, 0x13, 0x68, 0x96, 0xdf, 0x3b, 0xd4, 0x87,
+    0xd9, 0x16, 0x44, 0x71, 0x52, 0x2e, 0x54, 0x3e, 0x09, 0xcd, 0x71, 0xc1,
+    0x1e, 0x5e, 0x96, 0x13, 0xc9, 0x1e, 0xa4, 0xe6, 0xe6, 0x97, 0x2c, 0x6b,
+    0xf2, 0xa9, 0x5c, 0xc6, 0x60, 0x2a, 0xbc, 0x82, 0xf8, 0xcb, 0xd4, 0xd7,
+    0xea, 0x8a, 0xa1, 0x8a, 0xd9, 0xa5, 0x14, 0x8b, 0x9e, 0xf9, 0x25, 0x02,
+    0xd2, 0xab, 0x0c, 0x42, 0xca, 0x2d, 0x45, 0xa3, 0x56, 0x5e, 0xa2, 0x2a,
+    0xc8, 0x60, 0xa5, 0x87, 0x5d, 0x85, 0x5c, 0xde, 0xc7, 0xa2, 0x47, 0xc3,
+    0x99, 0x29, 0x23, 0x79, 0x36, 0x88, 0xad, 0x40, 0x3e, 0x27, 0x7d, 0xf0,
+    0xb6, 0xfa, 0x95, 0x20, 0x3c, 0xec, 0xfc, 0x56, 0x3b, 0x20, 0x91, 0xee,
+    0x98, 0x10, 0x2c, 0x82,
+};
+
+static const uint8_t kSixPrimeKey[] =
+    "\x30\x82\x05\x20\x02\x01\x01\x02\x82\x01\x00\x1c\x04\x39\x44\xb9\xb8\x71"
+    "\x1c\x1c\xf7\xdc\x11\x1b\x85\x3b\x2b\xe8\xa6\xeb\xeb\xe9\xb6\x86\x97\x73"
+    "\x5d\x75\x46\xd1\x35\x25\xf8\x30\x9a\xc3\x57\x44\x89\xa6\x44\x59\xe3\x3a"
+    "\x60\xb5\x33\x84\x72\xa4\x03\xc5\x1a\x20\x98\x70\xbd\xe8\x3b\xc1\x9b\x8a"
+    "\x3a\x24\x45\xb6\x6a\x73\xb4\xd0\x6c\x18\xc6\xa7\x94\xd3\x24\x70\xf0\x2d"
+    "\x0c\xa5\xb2\x3b\xc5\x33\x90\x9d\x56\x8d\x33\xf6\x93\x7d\xa7\x95\x88\x05"
+    "\xdf\xf5\x65\x58\xb9\x5b\xd3\x07\x9c\x16\x8e\x74\xfc\xb8\x76\xaf\x62\x99"
+    "\x6c\xd4\xc5\xb3\x69\xe5\x64\xdf\x38\x00\x25\x24\xe9\xb1\x4a\x85\xa6\xf4"
+    "\xb6\x23\x68\x67\x4a\x2c\xbd\x9d\x01\x3b\x04\x8c\x70\x94\x82\x76\x45\x0c"
+    "\x8b\x95\x8a\x07\x1c\x32\xe7\x09\x97\x3a\xfd\xca\x57\xe9\x57\x0c\xae\x2b"
+    "\xa3\x25\xd1\xf2\x0d\x34\xa1\xe6\x2f\x7b\x1b\x36\x53\x83\x95\xb9\x26\x6e"
+    "\x4f\x36\x26\xf8\x47\xae\xdf\xe8\x4d\xf6\xb2\xff\x03\x23\x74\xfa\xa5\x6d"
+    "\xcb\xcb\x80\x12\xc3\x77\xf0\x19\xb7\xf2\x6b\x19\x5c\xde\x0a\xd7\xee\x8c"
+    "\x48\x2f\x50\x24\xa5\x2e\xcc\x2a\xed\xc2\x35\xe0\x3d\x29\x31\x17\xd6\x8f"
+    "\x44\xaa\x5b\x33\xbd\xb4\x88\x87\xd9\x29\x3f\x94\xe7\x75\xe3\x02\x01\x03"
+    "\x02\x82\x01\x00\x12\xad\x7b\x83\x26\x7a\xf6\x12\xbd\xfa\x92\xb6\x12\x58"
+    "\xd2\x1d\x45\xc4\x9d\x47\xf1\x24\x59\xba\x4c\xe8\xf8\xd9\xe0\xce\x19\x50"
+    "\x20\x67\x2c\xe4\xd8\x5b\xc4\x2d\x91\x41\xeb\x05\x4f\xf4\xb4\x20\xc7\xbc"
+    "\xd6\xe2\x5c\xa0\x27\xcf\xb8\xb3\x3b\x5c\xeb\x5e\x96\xb7\x99\x4b\x8a\xc3"
+    "\x70\xaf\x7f\xd8\x5f\xeb\xcb\x1a\x79\x44\x68\x97\x84\xd8\x29\x87\x64\xba"
+    "\x18\x2e\x95\x66\x1a\x7d\xd9\x35\x3a\x5c\x92\x7a\x81\x1b\x6c\xa9\xf8\xfa"
+    "\x05\x23\x18\x5b\xb2\xf8\x77\x1c\xc5\x1b\x7d\x26\x5f\x48\x69\x1b\xc4\x34"
+    "\xef\x6e\xa1\x15\xd2\xb2\xac\xb8\xa8\xed\x1e\xee\xdc\xb5\xb9\x5c\x79\x25"
+    "\x48\xbb\xe5\x9d\xd8\xe5\xe2\x94\xdf\xd5\x32\x22\x84\xbf\xc2\xaa\xa4\x54"
+    "\xbb\x29\xdb\x13\x4a\x28\x3d\x83\x3a\xff\xa3\xae\x38\x08\xfc\x36\x84\x91"
+    "\x30\xd1\xfd\x82\x64\xf1\x0f\xae\xba\xd7\x9a\x43\x58\x03\x5e\x5f\x01\xcb"
+    "\x8b\x90\x8d\x77\x34\x6f\x37\x40\xb6\x6d\x22\x23\x90\xb2\xfd\x32\xb5\x96"
+    "\x45\xbf\xae\x8c\xc4\x62\x03\x6c\x68\x90\x59\x31\x1a\xcb\xfb\xa4\x0b\x94"
+    "\x15\x13\xda\x1a\x8d\xa7\x0b\x34\x62\x93\xea\xbe\x6e\x71\xc2\x1d\xc8\x9d"
+    "\xac\x66\xcc\x31\x87\xff\x99\xab\x02\x2c\x00\xa5\x57\x41\x66\x87\x68\x02"
+    "\x6a\xdf\x97\xb0\xfe\x6b\x34\xc4\x33\x88\x2b\xce\x82\xaf\x2d\x33\x5a\xad"
+    "\x75\x2d\xac\xa5\xd6\x3a\x2d\x65\x43\x68\xfb\x44\x9e\xb8\x25\x05\xed\x97"
+    "\x02\x2c\x00\xd2\x77\x34\x24\xac\x60\x9a\xc4\x68\x34\xe5\x6a\xa3\xdc\xe2"
+    "\xb0\x58\x5c\x35\x83\x5a\xc7\xa7\xc1\x0b\x7e\x9e\xa5\x85\x32\x47\x93\x22"
+    "\xee\xb6\x59\xe9\xe3\x61\x94\xd0\x0e\xcb\x02\x2b\x6e\x3a\x2b\x99\xaf\x9a"
+    "\xac\x47\x3f\xba\x75\xfe\xf2\x23\x2d\x77\xb0\x1d\x34\x57\x1f\x73\x77\x91"
+    "\xc8\xf8\xc9\x1d\xc3\xe4\x26\xc8\xee\x2c\xf0\xa7\x83\x14\x7a\xc3\x59\x49"
+    "\x0f\x02\x2c\x00\x8c\x4f\x78\x18\x72\xeb\x11\xd8\x45\x78\x98\xf1\xc2\x93"
+    "\x41\xca\xe5\x92\xce\x57\x91\xda\x6f\xd6\x07\xa9\xbf\x19\x03\x76\xda\x62"
+    "\x17\x49\xce\xe6\x9b\xec\xeb\xb8\x8a\xb4\x87\x02\x2c\x00\xa3\xc2\x29\xa6"
+    "\xa7\xe1\x3c\xe9\xcf\x0f\x50\x51\x1c\xcc\xc8\x5b\x08\x9c\x97\x24\x3a\x86"
+    "\x23\xa8\x0b\xbb\x54\xa6\xb9\x70\x3d\x1d\xd0\x1b\xa3\xac\xd9\xb2\x03\x80"
+    "\xd7\x67\xec\x30\x82\x02\x29\x30\x81\x88\x02\x2c\x00\x97\x5d\x3b\xf2\xcc"
+    "\xba\xd9\x77\x67\xaa\xd2\x22\xa7\xa3\x49\x08\xc7\xb8\x27\xa1\x59\x4b\xa7"
+    "\xa5\xd2\x74\x05\xe7\x5a\x35\xd7\x25\x79\x18\x20\x8a\x25\xec\x3b\x52\xaf"
+    "\xcb\xdb\x02\x2b\x64\xe8\xd2\xa1\xdd\xd1\xe6\x4f\x9a\x71\xe1\x6c\x6f\xc2"
+    "\x30\xb0\x85\x25\x6f\xc0\xe6\x32\x6f\xc3\xe1\xa2\xae\x9a\x3c\x23\xe4\xc3"
+    "\xa6\x10\x15\xb1\x6e\x9d\x7c\xe1\xca\x87\xe7\x02\x2b\x5e\xef\x25\x29\xed"
+    "\xf6\x52\x15\xd3\x60\xb6\x88\xcf\x0f\xe2\x24\xa4\x04\x97\x9c\x9d\x58\x13"
+    "\xbb\x00\x6d\x39\xf6\xad\x21\x7e\x56\x2c\x2e\x06\x06\xc4\x6d\x44\xac\x79"
+    "\x1f\xe5\x30\x81\x89\x02\x2c\x00\xdb\xf1\x78\xf9\xa4\x94\xea\x39\x8a\x3f"
+    "\x23\x48\x2a\x23\x8f\xd2\x18\x97\xd2\xdf\x0f\xb8\x2b\x33\xa0\xe8\x8f\xbc"
+    "\x4e\x42\xfd\x54\xc7\x0f\xde\xba\x6d\xba\x96\xa7\xce\x67\x3d\x02\x2c\x00"
+    "\x92\xa0\xfb\x51\x18\x63\x46\xd1\x06\xd4\xc2\x30\x1c\x17\xb5\x36\xbb\x0f"
+    "\xe1\xea\x0a\x7a\xc7\x77\xc0\x9b\x0a\x7d\x89\x81\xfe\x38\x84\xb5\x3f\x26"
+    "\xf3\xd1\xb9\xc5\x34\x44\xd3\x02\x2b\x4c\xbd\x1d\x44\xc8\x19\x23\xd8\xb3"
+    "\x96\x66\x4b\x62\xcb\x3e\xe6\x6c\x11\xdf\xb2\x92\xd3\xc8\x34\xb9\xa6\x5a"
+    "\x2f\x19\xf4\x0b\xb2\xe6\x8e\xa6\xaf\xa3\xae\xa4\xb3\x92\xc4\x79\x30\x81"
+    "\x85\x02\x2b\x00\x89\xab\x30\xfc\x7b\x37\x94\x11\x9f\x4d\x31\x3b\xac\x09"
+    "\x57\xe6\x64\xec\xa0\xc8\xf8\x04\x1a\xf9\x2a\xa4\x4b\x36\x18\xbb\x5f\xdc"
+    "\xcd\xf0\xc8\xcb\x97\xd1\xdf\x13\x12\x3f\x02\x2a\x5b\xc7\x75\xfd\xa7\x7a"
+    "\x62\xb6\x6a\x33\x76\x27\xc8\x06\x3a\x99\x98\x9d\xc0\x85\xfa\xad\x67\x50"
+    "\xc7\x18\x32\x24\x10\x7c\xea\x93\x33\xf5\xdb\x32\x65\x36\x94\xb7\x61\x7f"
+    "\x02\x2a\x16\x6c\x96\xa1\x50\x6f\x3a\x92\xc0\x75\x43\xb5\x6b\x9c\x17\x09"
+    "\xd3\xf0\x67\x69\x45\x92\xfb\x7b\x50\xa8\x42\x9b\x33\x92\xab\xd5\xe6\x49"
+    "\xb3\x26\x99\x55\x16\x3a\x39\x63\x30\x81\x87\x02\x2b\x00\xc1\x25\x19\x1d"
+    "\x6e\x18\xcb\x2d\x64\xe2\xe6\xb6\x1c\xe4\xaa\x9c\xb9\xee\x18\xd4\xf7\x5f"
+    "\x66\x40\xf0\xe1\x31\x38\xf2\x53\x00\x8b\xcc\xe4\x0d\xb7\x81\xb4\xe6\x1c"
+    "\x19\xaf\x02\x2b\x00\x80\xc3\x66\x13\x9e\xbb\x32\x1e\x43\x41\xef\x24\x13"
+    "\x43\x1c\x68\x7b\xf4\x10\x8d\xfa\x3f\x99\x80\xa0\x96\x20\xd0\xa1\x8c\xab"
+    "\x07\xdd\xed\x5e\x7a\x56\x78\x99\x68\x11\x1f\x02\x2b\x00\xb0\x59\xea\x67"
+    "\x93\x42\xbf\x07\x54\x38\x41\xcb\x73\xa4\x0e\xc2\xae\x56\x19\x41\xc9\x8a"
+    "\xb2\x2f\xa8\x0a\xb1\x4e\x12\x39\x2e\xc0\x94\x9a\xc6\xa3\xe4\xaf\x8a\x16"
+    "\x06\xb8";
+
+static const uint8_t kSixPrimeEncryptedMessage[] = {
+    0x0a, 0xcb, 0x6c, 0x02, 0x9d, 0x1a, 0x7c, 0xf3, 0x4e, 0xff, 0x16, 0x88,
+    0xee, 0x22, 0x1d, 0x8d, 0xd2, 0xfd, 0xde, 0x83, 0xb3, 0xd9, 0x35, 0x2c,
+    0x82, 0xe0, 0xff, 0xe6, 0x79, 0x6d, 0x06, 0x21, 0x74, 0xa8, 0x04, 0x0c,
+    0xe2, 0xd3, 0x98, 0x3f, 0xbf, 0xd0, 0xe9, 0x88, 0x24, 0xe2, 0x05, 0xa4,
+    0x45, 0x51, 0x87, 0x6b, 0x1c, 0xef, 0x5f, 0x2d, 0x61, 0xb6, 0xf1, 0x4c,
+    0x1f, 0x3d, 0xbf, 0x4b, 0xf2, 0xda, 0x09, 0x97, 0x81, 0xde, 0x91, 0xb7,
+    0x0d, 0xb4, 0xc2, 0xab, 0x41, 0x64, 0x9d, 0xd9, 0x39, 0x46, 0x79, 0x66,
+    0x43, 0xf1, 0x34, 0x21, 0x56, 0x2f, 0xc6, 0x68, 0x40, 0x4a, 0x2d, 0x73,
+    0x96, 0x50, 0xe1, 0xb0, 0xaf, 0x49, 0x39, 0xb4, 0xf0, 0x3a, 0x78, 0x38,
+    0x70, 0xa9, 0x91, 0x5d, 0x5e, 0x07, 0xf4, 0xec, 0xbb, 0xc4, 0xe5, 0x8a,
+    0xb8, 0x06, 0xba, 0xdf, 0xc6, 0x48, 0x78, 0x4b, 0xca, 0x2a, 0x8a, 0x92,
+    0x64, 0xe3, 0xa6, 0xae, 0x87, 0x97, 0x12, 0x16, 0x46, 0x67, 0x59, 0xdf,
+    0xf2, 0xf3, 0x89, 0x6f, 0xe8, 0xa9, 0x13, 0x57, 0x63, 0x4e, 0x07, 0x98,
+    0xcc, 0x73, 0xa0, 0x84, 0x9d, 0xe8, 0xb3, 0x50, 0x59, 0xb5, 0x51, 0xb3,
+    0x41, 0x7d, 0x55, 0xfe, 0xd9, 0xf0, 0xc6, 0xff, 0x6e, 0x96, 0x4f, 0x22,
+    0xb2, 0x0d, 0x6b, 0xc9, 0x83, 0x2d, 0x98, 0x98, 0xb2, 0xd1, 0xb7, 0xe4,
+    0x50, 0x83, 0x1a, 0xa9, 0x02, 0x9f, 0xaf, 0x54, 0x74, 0x2a, 0x2c, 0x63,
+    0x10, 0x79, 0x45, 0x5c, 0x95, 0x0d, 0xa1, 0x9b, 0x55, 0xf3, 0x1e, 0xb7,
+    0x56, 0x59, 0xf1, 0x59, 0x8d, 0xd6, 0x15, 0x89, 0xf6, 0xfe, 0xc0, 0x00,
+    0xdd, 0x1f, 0x2b, 0xf0, 0xf7, 0x5d, 0x64, 0x84, 0x76, 0xd3, 0xc2, 0x92,
+    0x35, 0xac, 0xb5, 0xf9, 0xf6, 0xa8, 0x05, 0x89, 0x4c, 0x95, 0x41, 0x4e,
+    0x34, 0x25, 0x11, 0x14,
+};
+
+// kEstonianRSAKey is an RSAPublicKey encoded with a negative modulus. See
+// https://crbug.com/532048.
+static const uint8_t kEstonianRSAKey[] = {
+    0x30, 0x82, 0x01, 0x09, 0x02, 0x82, 0x01, 0x00, 0x96, 0xa6, 0x2e, 0x9c,
+    0x4e, 0x6a, 0xc3, 0xcc, 0xcd, 0x8f, 0x70, 0xc3, 0x55, 0xbf, 0x5e, 0x9c,
+    0xd4, 0xf3, 0x17, 0xc3, 0x97, 0x70, 0xae, 0xdf, 0x12, 0x5c, 0x15, 0x80,
+    0x03, 0xef, 0x2b, 0x18, 0x9d, 0x6a, 0xcb, 0x52, 0x22, 0xc1, 0x81, 0xb8,
+    0x7e, 0x61, 0xe8, 0x0f, 0x79, 0x24, 0x0f, 0x82, 0x70, 0x24, 0x4e, 0x29,
+    0x20, 0x05, 0x54, 0xeb, 0xd4, 0xa9, 0x65, 0x59, 0xb6, 0x3c, 0x75, 0x95,
+    0x2f, 0x4c, 0xf6, 0x9d, 0xd1, 0xaf, 0x5f, 0x14, 0x14, 0xe7, 0x25, 0xea,
+    0xa5, 0x47, 0x5d, 0xc6, 0x3e, 0x28, 0x8d, 0xdc, 0x54, 0x87, 0x2a, 0x7c,
+    0x10, 0xe9, 0xc6, 0x76, 0x2d, 0xe7, 0x79, 0xd8, 0x0e, 0xbb, 0xa9, 0xac,
+    0xb5, 0x18, 0x98, 0xd6, 0x47, 0x6e, 0x06, 0x70, 0xbf, 0x9e, 0x82, 0x25,
+    0x95, 0x4e, 0xfd, 0x70, 0xd7, 0x73, 0x45, 0x2e, 0xc1, 0x1f, 0x7a, 0x9a,
+    0x9d, 0x60, 0xc0, 0x1f, 0x67, 0x06, 0x2a, 0x4e, 0x87, 0x3f, 0x19, 0x88,
+    0x69, 0x64, 0x4d, 0x9f, 0x75, 0xf5, 0xd3, 0x1a, 0x41, 0x3d, 0x35, 0x17,
+    0xb6, 0xd1, 0x44, 0x0d, 0x25, 0x8b, 0xe7, 0x94, 0x39, 0xb0, 0x7c, 0xaf,
+    0x3e, 0x6a, 0xfa, 0x8d, 0x90, 0x21, 0x0f, 0x8a, 0x43, 0x94, 0x37, 0x7c,
+    0x2a, 0x15, 0x4c, 0xa0, 0xfa, 0xa9, 0x2f, 0x21, 0xa6, 0x6f, 0x8e, 0x2f,
+    0x89, 0xbc, 0xbb, 0x33, 0xf8, 0x31, 0xfc, 0xdf, 0xcd, 0x68, 0x9a, 0xbc,
+    0x75, 0x06, 0x95, 0xf1, 0x3d, 0xef, 0xca, 0x76, 0x27, 0xd2, 0xba, 0x8e,
+    0x0e, 0x1c, 0x43, 0xd7, 0x70, 0xb9, 0xc6, 0x15, 0xca, 0xd5, 0x4d, 0x87,
+    0xb9, 0xd1, 0xae, 0xde, 0x69, 0x73, 0x00, 0x2a, 0x97, 0x51, 0x4b, 0x30,
+    0x01, 0xc2, 0x85, 0xd0, 0x05, 0xcc, 0x2e, 0xe8, 0xc7, 0x42, 0xe7, 0x94,
+    0x51, 0xe3, 0xf5, 0x19, 0x35, 0xdc, 0x57, 0x96, 0xe7, 0xd9, 0xb4, 0x49,
+    0x02, 0x03, 0x01, 0x00, 0x01,
+};
+
+static bool TestRSA(const uint8_t *der, size_t der_len,
+                    const uint8_t *oaep_ciphertext,
+                    size_t oaep_ciphertext_len) {
+  ScopedRSA key(d2i_RSAPrivateKey(nullptr, &der, der_len));
+  if (!key) {
+    return false;
+  }
+
+  if (!RSA_check_key(key.get())) {
+    fprintf(stderr, "RSA_check_key failed\n");
+    return false;
+  }
+
+  uint8_t ciphertext[256];
+
+  int num = RSA_public_encrypt(kPlaintextLen, kPlaintext, ciphertext, key.get(),
+                               RSA_PKCS1_PADDING);
+  if (num < 0 || (size_t)num != RSA_size(key.get())) {
+    fprintf(stderr, "PKCS#1 v1.5 encryption failed!\n");
+    return false;
+  }
+
+  uint8_t plaintext[256];
+  num = RSA_private_decrypt(num, ciphertext, plaintext, key.get(),
+                            RSA_PKCS1_PADDING);
+  if (num < 0 ||
+      (size_t)num != kPlaintextLen || memcmp(plaintext, kPlaintext, num) != 0) {
+    fprintf(stderr, "PKCS#1 v1.5 decryption failed!\n");
+    return false;
+  }
+
+  num = RSA_public_encrypt(kPlaintextLen, kPlaintext, ciphertext, key.get(),
+                           RSA_PKCS1_OAEP_PADDING);
+  if (num < 0 || (size_t)num != RSA_size(key.get())) {
+    fprintf(stderr, "OAEP encryption failed!\n");
+    return false;
+  }
+
+  num = RSA_private_decrypt(num, ciphertext, plaintext, key.get(),
+                            RSA_PKCS1_OAEP_PADDING);
+  if (num < 0 ||
+      (size_t)num != kPlaintextLen || memcmp(plaintext, kPlaintext, num) != 0) {
+    fprintf(stderr, "OAEP decryption (encrypted data) failed!\n");
+    return false;
+  }
+
+  // |oaep_ciphertext| should decrypt to |kPlaintext|.
+  num = RSA_private_decrypt(oaep_ciphertext_len, oaep_ciphertext, plaintext,
+                            key.get(), RSA_PKCS1_OAEP_PADDING);
+
+  if (num < 0 ||
+      (size_t)num != kPlaintextLen || memcmp(plaintext, kPlaintext, num) != 0) {
+    fprintf(stderr, "OAEP decryption (test vector data) failed!\n");
+    return false;
+  }
+
+  // Try decrypting corrupted ciphertexts.
+  memcpy(ciphertext, oaep_ciphertext, oaep_ciphertext_len);
+  for (size_t i = 0; i < oaep_ciphertext_len; i++) {
+    uint8_t saved = ciphertext[i];
+    for (unsigned b = 0; b < 256; b++) {
+      if (b == saved) {
+        continue;
+      }
+      ciphertext[i] = b;
+      num = RSA_private_decrypt(num, ciphertext, plaintext, key.get(),
+                                RSA_PKCS1_OAEP_PADDING);
+      if (num > 0) {
+        fprintf(stderr, "Corrupt data decrypted!\n");
+        return false;
+      }
+    }
+    ciphertext[i] = saved;
+  }
+
+  return true;
+}
+
+static bool TestMultiPrimeKey(int nprimes, const uint8_t *der, size_t der_size,
+                              const uint8_t *enc, size_t enc_size) {
+  ScopedRSA rsa(d2i_RSAPrivateKey(nullptr, &der, der_size));
+  if (!rsa) {
+    fprintf(stderr, "%d-prime key failed to parse.\n", nprimes);
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  if (!RSA_check_key(rsa.get())) {
+    fprintf(stderr, "RSA_check_key failed for %d-prime key.\n", nprimes);
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  uint8_t out[256];
+  size_t out_len;
+  if (!RSA_decrypt(rsa.get(), &out_len, out, sizeof(out), enc, enc_size,
+                   RSA_PKCS1_PADDING) ||
+      out_len != 11 ||
+      memcmp(out, "hello world", 11) != 0) {
+    fprintf(stderr, "%d-prime key failed to decrypt.\n", nprimes);
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestMultiPrimeKeygen() {
+  static const char kMessage[] = "Hello world.";
+  static const size_t kBits = 1024;
+  uint8_t encrypted[kBits / 8], decrypted[kBits / 8];
+  size_t encrypted_len, decrypted_len;
+
+  ScopedRSA rsa(RSA_new());
+  ScopedBIGNUM e(BN_new());
+  if (!rsa || !e ||
+      !BN_set_word(e.get(), RSA_F4) ||
+      !RSA_generate_multi_prime_key(rsa.get(), kBits, 3, e.get(), nullptr) ||
+      !RSA_check_key(rsa.get()) ||
+      !RSA_encrypt(rsa.get(), &encrypted_len, encrypted, sizeof(encrypted),
+                   (const uint8_t *)kMessage, sizeof(kMessage),
+                   RSA_PKCS1_PADDING) ||
+      !RSA_decrypt(rsa.get(), &decrypted_len, decrypted, sizeof(decrypted),
+                   encrypted, encrypted_len, RSA_PKCS1_PADDING) ||
+      decrypted_len != sizeof(kMessage) ||
+      memcmp(decrypted, kMessage, sizeof(kMessage)) != 0) {
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestBadKey() {
+  ScopedRSA key(RSA_new());
+  ScopedBIGNUM e(BN_new());
+
+  if (!key || !e || !BN_set_word(e.get(), RSA_F4)) {
+    return false;
+  }
+
+  if (!RSA_generate_key_ex(key.get(), 512, e.get(), nullptr)) {
+    fprintf(stderr, "RSA_generate_key_ex failed.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  if (!BN_add(key->p, key->p, BN_value_one())) {
+    fprintf(stderr, "BN error.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  if (RSA_check_key(key.get())) {
+    fprintf(stderr, "RSA_check_key passed with invalid key!\n");
+    return false;
+  }
+
+  ERR_clear_error();
+  return true;
+}
+
+static bool TestOnlyDGiven() {
+  uint8_t buf[64];
+  unsigned buf_len = sizeof(buf);
+  ScopedRSA key(RSA_new());
+  if (!key ||
+      !BN_hex2bn(&key->n,
+                 "00e77bbf3889d4ef36a9a25d4d69f3f632eb4362214c74517da6d6aeaa9bd"
+                 "09ac42b26621cd88f3a6eb013772fc3bf9f83914b6467231c630202c35b3e"
+                 "5808c659") ||
+      !BN_hex2bn(&key->e, "010001") ||
+      !BN_hex2bn(&key->d,
+                 "0365db9eb6d73b53b015c40cd8db4de7dd7035c68b5ac1bf786d7a4ee2cea"
+                 "316eaeca21a73ac365e58713195f2ae9849348525ca855386b6d028e437a9"
+                 "495a01") ||
+      RSA_size(key.get()) > sizeof(buf)) {
+    return false;
+  }
+
+  if (!RSA_check_key(key.get())) {
+    fprintf(stderr, "RSA_check_key failed with only d given.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  const uint8_t kDummyHash[16] = {0};
+
+  if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
+                key.get())) {
+    fprintf(stderr, "RSA_sign failed with only d given.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
+                  key.get())) {
+    fprintf(stderr, "RSA_verify failed with only d given.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  return true;
+}
+
+static bool TestRecoverCRTParams() {
+  ScopedBIGNUM e(BN_new());
+  if (!e || !BN_set_word(e.get(), RSA_F4)) {
+    return false;
+  }
+
+  ERR_clear_error();
+
+  for (unsigned i = 0; i < 1; i++) {
+    ScopedRSA key1(RSA_new());
+    if (!key1 ||
+        !RSA_generate_key_ex(key1.get(), 512, e.get(), nullptr)) {
+      fprintf(stderr, "RSA_generate_key_ex failed.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+
+    if (!RSA_check_key(key1.get())) {
+      fprintf(stderr, "RSA_check_key failed with original key.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+
+    ScopedRSA key2(RSA_new());
+    if (!key2) {
+      return false;
+    }
+    key2->n = BN_dup(key1->n);
+    key2->e = BN_dup(key1->e);
+    key2->d = BN_dup(key1->d);
+    if (key2->n == nullptr || key2->e == nullptr || key2->d == nullptr) {
+      return false;
+    }
+
+    if (!RSA_recover_crt_params(key2.get())) {
+      fprintf(stderr, "RSA_recover_crt_params failed.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+
+    uint8_t buf[128];
+    unsigned buf_len = sizeof(buf);
+    if (RSA_size(key2.get()) > buf_len) {
+      return false;
+    }
+
+    if (!RSA_check_key(key2.get())) {
+      fprintf(stderr, "RSA_check_key failed with recovered key.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+
+    const uint8_t kDummyHash[16] = {0};
+    if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
+                  key2.get())) {
+      fprintf(stderr, "RSA_sign failed with recovered key.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+
+    if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
+                    key2.get())) {
+      fprintf(stderr, "RSA_verify failed with recovered key.\n");
+      ERR_print_errors_fp(stderr);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool TestASN1() {
+  // Test that private keys may be decoded.
+  ScopedRSA rsa(RSA_private_key_from_bytes(kKey1, sizeof(kKey1) - 1));
+  if (!rsa) {
+    return false;
+  }
+
+  // Test that the serialization round-trips.
+  uint8_t *der;
+  size_t der_len;
+  if (!RSA_private_key_to_bytes(&der, &der_len, rsa.get())) {
+    return false;
+  }
+  ScopedOpenSSLBytes delete_der(der);
+  if (der_len != sizeof(kKey1) - 1 || memcmp(der, kKey1, der_len) != 0) {
+    return false;
+  }
+
+  // Test that serializing public keys works.
+  if (!RSA_public_key_to_bytes(&der, &der_len, rsa.get())) {
+    return false;
+  }
+  delete_der.reset(der);
+
+  // Public keys may be parsed back out.
+  rsa.reset(RSA_public_key_from_bytes(der, der_len));
+  if (!rsa || rsa->p != NULL || rsa->q != NULL) {
+    return false;
+  }
+
+  // Serializing the result round-trips.
+  uint8_t *der2;
+  size_t der2_len;
+  if (!RSA_public_key_to_bytes(&der2, &der2_len, rsa.get())) {
+    return false;
+  }
+  ScopedOpenSSLBytes delete_der2(der2);
+  if (der_len != der2_len || memcmp(der, der2, der_len) != 0) {
+    return false;
+  }
+
+  // Public keys cannot be serialized as private keys.
+  if (RSA_private_key_to_bytes(&der, &der_len, rsa.get())) {
+    OPENSSL_free(der);
+    return false;
+  }
+  ERR_clear_error();
+
+  // Public keys with negative moduli are invalid.
+  rsa.reset(RSA_public_key_from_bytes(kEstonianRSAKey,
+                                      sizeof(kEstonianRSAKey)));
+  if (rsa) {
+    return false;
+  }
+  ERR_clear_error();
+
+  // But |RSA_parse_public_key_buggy| will accept it.
+  CBS cbs;
+  CBS_init(&cbs, kEstonianRSAKey, sizeof(kEstonianRSAKey));
+  rsa.reset(RSA_parse_public_key_buggy(&cbs));
+  if (!rsa || CBS_len(&cbs) != 0) {
+    return false;
+  }
+
+  return true;
+}
+
+int main(int argc, char *argv[]) {
+  CRYPTO_library_init();
+
+  if (!TestRSA(kKey1, sizeof(kKey1) - 1, kOAEPCiphertext1,
+               sizeof(kOAEPCiphertext1) - 1) ||
+      !TestRSA(kKey2, sizeof(kKey2) - 1, kOAEPCiphertext2,
+               sizeof(kOAEPCiphertext2) - 1) ||
+      !TestRSA(kKey3, sizeof(kKey3) - 1, kOAEPCiphertext3,
+               sizeof(kOAEPCiphertext3) - 1) ||
+      !TestOnlyDGiven() ||
+      !TestRecoverCRTParams() ||
+      !TestBadKey() ||
+      !TestMultiPrimeKey(2, kTwoPrimeKey, sizeof(kTwoPrimeKey) - 1,
+                            kTwoPrimeEncryptedMessage,
+                            sizeof(kTwoPrimeEncryptedMessage)) ||
+      !TestMultiPrimeKey(3, kThreePrimeKey, sizeof(kThreePrimeKey) - 1,
+                            kThreePrimeEncryptedMessage,
+                            sizeof(kThreePrimeEncryptedMessage)) ||
+      !TestMultiPrimeKey(6, kSixPrimeKey, sizeof(kSixPrimeKey) - 1,
+                            kSixPrimeEncryptedMessage,
+                            sizeof(kSixPrimeEncryptedMessage)) ||
+      !TestMultiPrimeKeygen() ||
+      !TestASN1()) {
+    return 1;
+  }
+
+  printf("PASS\n");
+  return 0;
+}
diff --git a/src/crypto/sha/CMakeLists.txt b/src/crypto/sha/CMakeLists.txt
index 5a10c85..ecff09b 100644
--- a/src/crypto/sha/CMakeLists.txt
+++ b/src/crypto/sha/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 if (${ARCH} STREQUAL "x86_64")
   set(
diff --git a/src/crypto/sha/asm/sha1-586.pl b/src/crypto/sha/asm/sha1-586.pl
index 4895eb3..e0b5d83 100644
--- a/src/crypto/sha/asm/sha1-586.pl
+++ b/src/crypto/sha/asm/sha1-586.pl
@@ -66,9 +66,9 @@
 # switch to AVX alone improves performance by as little as 4% in
 # comparison to SSSE3 code path. But below result doesn't look like
 # 4% improvement... Trouble is that Sandy Bridge decodes 'ro[rl]' as
-# pair of µ-ops, and it's the additional µ-ops, two per round, that
+# pair of µ-ops, and it's the additional µ-ops, two per round, that
 # make it run slower than Core2 and Westmere. But 'sh[rl]d' is decoded
-# as single µ-op by Sandy Bridge and it's replacing 'ro[rl]' with
+# as single µ-op by Sandy Bridge and it's replacing 'ro[rl]' with
 # equivalent 'sh[rl]d' that is responsible for the impressive 5.1
 # cycles per processed byte. But 'sh[rl]d' is not something that used
 # to be fast, nor does it appear to be fast in upcoming Bulldozer
diff --git a/src/crypto/sha/asm/sha1-armv4-large.pl b/src/crypto/sha/asm/sha1-armv4-large.pl
index a20d336..64e2ed6 100644
--- a/src/crypto/sha/asm/sha1-armv4-large.pl
+++ b/src/crypto/sha/asm/sha1-armv4-large.pl
@@ -178,7 +178,7 @@
 }
 
 $code=<<___;
-#include "arm_arch.h"
+#include <openssl/arm_arch.h>
 
 .text
 .code	32
diff --git a/src/crypto/sha/asm/sha1-armv8.pl b/src/crypto/sha/asm/sha1-armv8.pl
index a8c08c2..1c4fe4a 100644
--- a/src/crypto/sha/asm/sha1-armv8.pl
+++ b/src/crypto/sha/asm/sha1-armv8.pl
@@ -162,7 +162,7 @@
 }
 
 $code.=<<___;
-#include "arm_arch.h"
+#include <openssl/arm_arch.h>
 
 .text
 
diff --git a/src/crypto/sha/asm/sha256-586.pl b/src/crypto/sha/asm/sha256-586.pl
index 6462e45..e907714 100644
--- a/src/crypto/sha/asm/sha256-586.pl
+++ b/src/crypto/sha/asm/sha256-586.pl
@@ -10,7 +10,7 @@
 # SHA256 block transform for x86. September 2007.
 #
 # Performance improvement over compiler generated code varies from
-# 10% to 40% [see below]. Not very impressive on some µ-archs, but
+# 10% to 40% [see below]. Not very impressive on some µ-archs, but
 # it's 5 times smaller and optimizies amount of writes.
 #
 # May 2012.
diff --git a/src/crypto/sha/asm/sha256-armv4.pl b/src/crypto/sha/asm/sha256-armv4.pl
index df71676..7e07147 100644
--- a/src/crypto/sha/asm/sha256-armv4.pl
+++ b/src/crypto/sha/asm/sha256-armv4.pl
@@ -168,7 +168,7 @@
 
 $code=<<___;
 #ifndef __KERNEL__
-# include "arm_arch.h"
+# include <openssl/arm_arch.h>
 #else
 # define __ARM_ARCH__ __LINUX_ARM_ARCH__
 # define __ARM_MAX_ARCH__ 7
diff --git a/src/crypto/sha/asm/sha512-586.pl b/src/crypto/sha/asm/sha512-586.pl
index e96ec00..2f6a202 100644
--- a/src/crypto/sha/asm/sha512-586.pl
+++ b/src/crypto/sha/asm/sha512-586.pl
@@ -37,7 +37,7 @@
 #
 # IALU code-path is optimized for elder Pentiums. On vanilla Pentium
 # performance improvement over compiler generated code reaches ~60%,
-# while on PIII - ~35%. On newer µ-archs improvement varies from 15%
+# while on PIII - ~35%. On newer µ-archs improvement varies from 15%
 # to 50%, but it's less important as they are expected to execute SSE2
 # code-path, which is commonly ~2-3x faster [than compiler generated
 # code]. SSE2 code-path is as fast as original sha512-sse2.pl, even
diff --git a/src/crypto/sha/asm/sha512-armv4.pl b/src/crypto/sha/asm/sha512-armv4.pl
index 2964a39..cd3662a 100644
--- a/src/crypto/sha/asm/sha512-armv4.pl
+++ b/src/crypto/sha/asm/sha512-armv4.pl
@@ -191,7 +191,7 @@
 }
 $code=<<___;
 #ifndef __KERNEL__
-# include "arm_arch.h"
+# include <openssl/arm_arch.h>
 # define VFP_ABI_PUSH	vstmdb	sp!,{d8-d15}
 # define VFP_ABI_POP	vldmia	sp!,{d8-d15}
 #else
diff --git a/src/crypto/sha/asm/sha512-armv8.pl b/src/crypto/sha/asm/sha512-armv8.pl
index 43e7293..40eb17a 100644
--- a/src/crypto/sha/asm/sha512-armv8.pl
+++ b/src/crypto/sha/asm/sha512-armv8.pl
@@ -164,7 +164,7 @@
 }
 
 $code.=<<___;
-#include "arm_arch.h"
+#include <openssl/arm_arch.h>
 
 .text
 
diff --git a/src/crypto/stack/CMakeLists.txt b/src/crypto/stack/CMakeLists.txt
index bdb0599..dcd8ef4 100644
--- a/src/crypto/stack/CMakeLists.txt
+++ b/src/crypto/stack/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   stack
diff --git a/src/crypto/test/CMakeLists.txt b/src/crypto/test/CMakeLists.txt
index 84a6174..8c75314 100644
--- a/src/crypto/test/CMakeLists.txt
+++ b/src/crypto/test/CMakeLists.txt
@@ -5,4 +5,5 @@
 
   file_test.cc
   malloc.cc
+  test_util.cc
 )
diff --git a/src/crypto/test/file_test.cc b/src/crypto/test/file_test.cc
index 8df6f9a..6723350 100644
--- a/src/crypto/test/file_test.cc
+++ b/src/crypto/test/file_test.cc
@@ -128,6 +128,7 @@
       const char *delimiter = FindDelimiter(buf);
       if (delimiter == nullptr) {
         fprintf(stderr, "Line %u: Could not parse attribute.\n", line_);
+        return kReadError;
       }
       std::string key = StripSpace(buf, delimiter - buf);
       std::string value = StripSpace(delimiter + 1,
diff --git a/src/crypto/test/file_test.h b/src/crypto/test/file_test.h
index 7303d8a..24651ab 100644
--- a/src/crypto/test/file_test.h
+++ b/src/crypto/test/file_test.h
@@ -18,11 +18,19 @@
 #include <stdint.h>
 #include <stdio.h>
 
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable: 4702)
+#endif
+
 #include <string>
 #include <map>
 #include <set>
 #include <vector>
 
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
 
 // File-based test framework.
 //
diff --git a/src/crypto/test/malloc.cc b/src/crypto/test/malloc.cc
index 9ffdf01..898f2a7 100644
--- a/src/crypto/test/malloc.cc
+++ b/src/crypto/test/malloc.cc
@@ -34,6 +34,8 @@
 #if defined(__linux__) && defined(OPENSSL_GLIBC) && !defined(OPENSSL_ARM) && \
     !defined(OPENSSL_AARCH64) && !defined(OPENSSL_ASAN)
 
+#include <errno.h>
+#include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -45,14 +47,14 @@
 /* This file defines overrides for the standard allocation functions that allow
  * a given allocation to be made to fail for testing. If the program is run
  * with MALLOC_NUMBER_TO_FAIL set to a base-10 number then that allocation will
- * return NULL. If MALLOC_ABORT_ON_FAIL is also defined then the allocation
- * will abort() rather than return NULL.
+ * return NULL. If MALLOC_BREAK_ON_FAIL is also defined then the allocation
+ * will signal SIGTRAP rather than return NULL.
  *
  * This code is not thread safe. */
 
 static uint64_t current_malloc_count = 0;
 static uint64_t malloc_number_to_fail = 0;
-static char failure_enabled = 0, abort_on_fail = 0;
+static char failure_enabled = 0, break_on_fail = 0;
 static int in_call = 0;
 
 extern "C" {
@@ -95,7 +97,7 @@
         std::set_new_handler(cpp_new_handler);
       }
     }
-    abort_on_fail = (NULL != getenv("MALLOC_ABORT_ON_FAIL"));
+    break_on_fail = (NULL != getenv("MALLOC_BREAK_ON_FAIL"));
     init = 1;
   }
 
@@ -108,8 +110,8 @@
   should_fail = (current_malloc_count == malloc_number_to_fail);
   current_malloc_count++;
 
-  if (should_fail && abort_on_fail) {
-    abort();
+  if (should_fail && break_on_fail) {
+    raise(SIGTRAP);
   }
   return should_fail;
 }
@@ -118,6 +120,7 @@
 
 void *malloc(size_t size) {
   if (should_fail_allocation()) {
+    errno = ENOMEM;
     return NULL;
   }
 
@@ -126,6 +129,7 @@
 
 void *calloc(size_t num_elems, size_t size) {
   if (should_fail_allocation()) {
+    errno = ENOMEM;
     return NULL;
   }
 
@@ -134,6 +138,7 @@
 
 void *realloc(void *ptr, size_t size) {
   if (should_fail_allocation()) {
+    errno = ENOMEM;
     return NULL;
   }
 
diff --git a/src/crypto/test/scoped_types.h b/src/crypto/test/scoped_types.h
index c5c8cfe..e44c6ed 100644
--- a/src/crypto/test/scoped_types.h
+++ b/src/crypto/test/scoped_types.h
@@ -18,6 +18,7 @@
 #include <stdint.h>
 #include <stdio.h>
 
+#include <openssl/aead.h>
 #include <openssl/bio.h>
 #include <openssl/bn.h>
 #include <openssl/cmac.h>
@@ -112,9 +113,13 @@
 using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
 using ScopedX509 = ScopedOpenSSLType<X509, X509_free>;
 using ScopedX509_ALGOR = ScopedOpenSSLType<X509_ALGOR, X509_ALGOR_free>;
+using ScopedX509_SIG = ScopedOpenSSLType<X509_SIG, X509_SIG_free>;
 
 using ScopedX509Stack = ScopedOpenSSLStack<STACK_OF(X509), X509, X509_free>;
 
+using ScopedEVP_AEAD_CTX = ScopedOpenSSLContext<EVP_AEAD_CTX, void,
+                                                EVP_AEAD_CTX_zero,
+                                                EVP_AEAD_CTX_cleanup>;
 using ScopedEVP_CIPHER_CTX = ScopedOpenSSLContext<EVP_CIPHER_CTX, int,
                                                   EVP_CIPHER_CTX_init,
                                                   EVP_CIPHER_CTX_cleanup>;
diff --git a/src/crypto/test/test_util.cc b/src/crypto/test/test_util.cc
new file mode 100644
index 0000000..8021aaa
--- /dev/null
+++ b/src/crypto/test/test_util.cc
@@ -0,0 +1,30 @@
+/* Copyright (c) 2015, 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 <stdint.h>
+#include <stdio.h>
+
+#include "test_util.h"
+
+
+void hexdump(FILE *fp, const char *msg, const void *in, size_t len) {
+  const uint8_t *data = reinterpret_cast<const uint8_t*>(in);
+  size_t i;
+
+  fputs(msg, fp);
+  for (i = 0; i < len; i++) {
+    fprintf(fp, "%02x", data[i]);
+  }
+  fputs("\n", fp);
+}
diff --git a/src/crypto/test/test_util.h b/src/crypto/test/test_util.h
new file mode 100644
index 0000000..972e206
--- /dev/null
+++ b/src/crypto/test/test_util.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2015, 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_CRYPTO_TEST_TEST_UTIL_H
+#define OPENSSL_HEADER_CRYPTO_TEST_TEST_UTIL_H
+
+#include <stddef.h>
+#include <stdio.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* hexdump writes |msg| to |fp| followed by the hex encoding of |len| bytes
+ * from |in|. */
+void hexdump(FILE *fp, const char *msg, const void *in, size_t len);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* OPENSSL_HEADER_CRYPTO_TEST_TEST_UTIL_H */
diff --git a/src/crypto/x509/CMakeLists.txt b/src/crypto/x509/CMakeLists.txt
index 3bb5704..258c263 100644
--- a/src/crypto/x509/CMakeLists.txt
+++ b/src/crypto/x509/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   x509
@@ -15,6 +15,7 @@
   i2d_pr.c
   pkcs7.c
   t_crl.c
+  t_req.c
   t_x509.c
   t_x509a.c
   x509.c
diff --git a/src/crypto/x509/a_digest.c b/src/crypto/x509/a_digest.c
index 6060bbd..430e2e6 100644
--- a/src/crypto/x509/a_digest.c
+++ b/src/crypto/x509/a_digest.c
@@ -71,7 +71,7 @@
 	i=i2d(data,NULL);
 	if ((str=(unsigned char *)OPENSSL_malloc(i)) == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, ASN1_digest, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return(0);
 		}
 	p=str;
diff --git a/src/crypto/x509/a_sign.c b/src/crypto/x509/a_sign.c
index f219c23..4e9be8a 100644
--- a/src/crypto/x509/a_sign.c
+++ b/src/crypto/x509/a_sign.c
@@ -106,7 +106,7 @@
 	if ((buf_in == NULL) || (buf_out == NULL))
 		{
 		outl=0;
-		OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 
@@ -114,7 +114,7 @@
 		|| !EVP_DigestSignFinal(ctx, buf_out, &outl))
 		{
 		outl=0;
-		OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, ERR_R_EVP_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB);
 		goto err;
 		}
 	if (signature->data != NULL) OPENSSL_free(signature->data);
diff --git a/src/crypto/x509/a_verify.c b/src/crypto/x509/a_verify.c
index 72e0a62..572a139 100644
--- a/src/crypto/x509/a_verify.c
+++ b/src/crypto/x509/a_verify.c
@@ -80,13 +80,13 @@
 
 	if (!pkey)
 		{
-		OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_PASSED_NULL_PARAMETER);
+		OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER);
 		return 0;
 		}
 
 	if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7)
 		{
-		OPENSSL_PUT_ERROR(X509, ASN1_item_verify, X509_R_INVALID_BIT_STRING_BITS_LEFT);
+		OPENSSL_PUT_ERROR(X509, X509_R_INVALID_BIT_STRING_BITS_LEFT);
 		return 0;
 		}
 
@@ -101,7 +101,7 @@
 	
 	if (buf_in == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 
@@ -109,7 +109,7 @@
 		{
 		OPENSSL_cleanse(buf_in,(unsigned int)inl);
 		OPENSSL_free(buf_in);
-		OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_EVP_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB);
 		goto err;
 		}
 
@@ -119,7 +119,7 @@
 	if (EVP_DigestVerifyFinal(&ctx,signature->data,
 			(size_t)signature->length) <= 0)
 		{
-		OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_EVP_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB);
 		goto err;
 		}
 	/* we don't need to zero the 'ctx' because we just checked
diff --git a/src/crypto/x509/asn1_gen.c b/src/crypto/x509/asn1_gen.c
index d4d1ee6..850a816 100644
--- a/src/crypto/x509/asn1_gen.c
+++ b/src/crypto/x509/asn1_gen.c
@@ -171,7 +171,7 @@
 		{
 		if (!cnf)
 			{
-			OPENSSL_PUT_ERROR(ASN1, ASN1_generate_v3, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG);
 			return NULL;
 			}
 		ret = asn1_multi(asn1_tags.utype, asn1_tags.str, cnf);
@@ -314,7 +314,7 @@
 
 	if (utype == -1)
 		{
-		OPENSSL_PUT_ERROR(ASN1, asn1_cb, ASN1_R_UNKNOWN_TAG);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_TAG);
 		ERR_add_error_data(2, "tag=", elem);
 		return -1;
 		}
@@ -327,7 +327,7 @@
 		/* If no value and not end of string, error */
 		if (!vstart && elem[len])
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_cb, ASN1_R_MISSING_VALUE);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE);
 			return -1;
 			}
 		return 0;
@@ -340,7 +340,7 @@
 		/* Check for illegal multiple IMPLICIT tagging */
 		if (arg->imp_tag != -1)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_cb, ASN1_R_ILLEGAL_NESTED_TAGGING);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING);
 			return -1;
 			}
 		if (!parse_tagging(vstart, vlen, &arg->imp_tag, &arg->imp_class))
@@ -378,7 +378,7 @@
 		case ASN1_GEN_FLAG_FORMAT:
 		if (!vstart)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_cb, ASN1_R_UNKNOWN_FORMAT);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT);
 			return -1;
 			}
 		if (!strncmp(vstart, "ASCII", 5))
@@ -391,7 +391,7 @@
 			arg->format = ASN1_GEN_FORMAT_BITLIST;
 		else
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_cb, ASN1_R_UNKNOWN_FORMAT);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT);
 			return -1;
 			}
 		break;
@@ -415,7 +415,7 @@
 		return 0;
 	if (tag_num < 0)
 		{
-		OPENSSL_PUT_ERROR(ASN1, parse_tagging, ASN1_R_INVALID_NUMBER);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_NUMBER);
 		return 0;
 		}
 	*ptag = tag_num;
@@ -448,7 +448,7 @@
 			default:
 			erch[0] = *eptr;
 			erch[1] = 0;
-			OPENSSL_PUT_ERROR(ASN1, parse_tagging, ASN1_R_INVALID_MODIFIER);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_MODIFIER);
 			ERR_add_error_data(2, "Char=", erch);
 			return 0;
 			break;
@@ -534,13 +534,13 @@
 	/* Can only have IMPLICIT if permitted */
 	if ((arg->imp_tag != -1) && !imp_ok)
 		{
-		OPENSSL_PUT_ERROR(ASN1, append_exp, ASN1_R_ILLEGAL_IMPLICIT_TAG);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_IMPLICIT_TAG);
 		return 0;
 		}
 
 	if (arg->exp_count == ASN1_FLAG_EXP_MAX)
 		{
-		OPENSSL_PUT_ERROR(ASN1, append_exp, ASN1_R_DEPTH_EXCEEDED);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_DEPTH_EXCEEDED);
 		return 0;
 		}
 
@@ -658,7 +658,7 @@
 
 	if (!(atmp = ASN1_TYPE_new()))
 		{
-		OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return NULL;
 		}
 
@@ -671,7 +671,7 @@
 		case V_ASN1_NULL:
 		if (str && *str)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_ILLEGAL_NULL_VALUE);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NULL_VALUE);
 			goto bad_form;
 			}
 		break;
@@ -679,7 +679,7 @@
 		case V_ASN1_BOOLEAN:
 		if (format != ASN1_GEN_FORMAT_ASCII)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_NOT_ASCII_FORMAT);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ASCII_FORMAT);
 			goto bad_form;
 			}
 		vtmp.name = NULL;
@@ -687,7 +687,7 @@
 		vtmp.value = (char *)str;
 		if (!X509V3_get_value_bool(&vtmp, &atmp->value.boolean))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_ILLEGAL_BOOLEAN);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_BOOLEAN);
 			goto bad_str;
 			}
 		break;
@@ -696,12 +696,12 @@
 		case V_ASN1_ENUMERATED:
 		if (format != ASN1_GEN_FORMAT_ASCII)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_INTEGER_NOT_ASCII_FORMAT);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_NOT_ASCII_FORMAT);
 			goto bad_form;
 			}
 		if (!(atmp->value.integer = s2i_ASN1_INTEGER(NULL, (char *)str)))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_ILLEGAL_INTEGER);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_INTEGER);
 			goto bad_str;
 			}
 		break;
@@ -709,12 +709,12 @@
 		case V_ASN1_OBJECT:
 		if (format != ASN1_GEN_FORMAT_ASCII)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_OBJECT_NOT_ASCII_FORMAT);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_OBJECT_NOT_ASCII_FORMAT);
 			goto bad_form;
 			}
 		if (!(atmp->value.object = OBJ_txt2obj(str, 0)))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_ILLEGAL_OBJECT);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OBJECT);
 			goto bad_str;
 			}
 		break;
@@ -723,23 +723,23 @@
 		case V_ASN1_GENERALIZEDTIME:
 		if (format != ASN1_GEN_FORMAT_ASCII)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_TIME_NOT_ASCII_FORMAT);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_TIME_NOT_ASCII_FORMAT);
 			goto bad_form;
 			}
 		if (!(atmp->value.asn1_string = ASN1_STRING_new()))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			goto bad_str;
 			}
 		if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			goto bad_str;
 			}
 		atmp->value.asn1_string->type = utype;
 		if (!ASN1_TIME_check(atmp->value.asn1_string))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_ILLEGAL_TIME_VALUE);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_TIME_VALUE);
 			goto bad_str;
 			}
 
@@ -761,7 +761,7 @@
 			format = MBSTRING_UTF8;
 		else
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_ILLEGAL_FORMAT);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_FORMAT);
 			goto bad_form;
 			}
 
@@ -769,7 +769,7 @@
 		if (ASN1_mbstring_copy(&atmp->value.asn1_string, (unsigned char *)str,
 						-1, format, ASN1_tag2bit(utype)) <= 0)
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			goto bad_str;
 			}
 		
@@ -782,7 +782,7 @@
 
 		if (!(atmp->value.asn1_string = ASN1_STRING_new()))
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 			goto bad_form;
 			}
 
@@ -791,7 +791,7 @@
 
 			if (!(rdata = string_to_hex((char *)str, &rdlen)))
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_ILLEGAL_HEX);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_HEX);
 				goto bad_str;
 				}
 
@@ -806,7 +806,7 @@
 			{
 			if (!CONF_parse_list(str, ',', 1, bitstr_cb, atmp->value.bit_string))
 				{
-				OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_LIST_ERROR);
+				OPENSSL_PUT_ERROR(ASN1, ASN1_R_LIST_ERROR);
 				goto bad_str;
 				}
 			no_unused = 0;
@@ -814,7 +814,7 @@
 			}
 		else 
 			{
-			OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_ILLEGAL_BITSTRING_FORMAT);
+			OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT);
 			goto bad_form;
 			}
 
@@ -830,7 +830,7 @@
 		break;
 
 		default:
-		OPENSSL_PUT_ERROR(ASN1, asn1_str2type, ASN1_R_UNSUPPORTED_TYPE);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_TYPE);
 		goto bad_str;
 		break;
 		}
@@ -860,12 +860,12 @@
 		return 0;
 	if (bitnum < 0)
 		{
-		OPENSSL_PUT_ERROR(ASN1, bitstr_cb, ASN1_R_INVALID_NUMBER);
+		OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_NUMBER);
 		return 0;
 		}
 	if (!ASN1_BIT_STRING_set_bit(bitstr, bitnum, 1))
 		{
-		OPENSSL_PUT_ERROR(ASN1, bitstr_cb, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
 		return 0;
 		}
 	return 1;
diff --git a/src/crypto/x509/by_dir.c b/src/crypto/x509/by_dir.c
index 34bb1e4..3393dfa 100644
--- a/src/crypto/x509/by_dir.c
+++ b/src/crypto/x509/by_dir.c
@@ -139,7 +139,7 @@
 					X509_FILETYPE_PEM);
 			if (!ret)
 				{
-				OPENSSL_PUT_ERROR(X509, dir_ctrl, X509_R_LOADING_CERT_DIR);
+				OPENSSL_PUT_ERROR(X509, X509_R_LOADING_CERT_DIR);
 				}
 			}
 		else
@@ -208,7 +208,7 @@
 
 	if (dir == NULL || !*dir)
 	    {
-	    OPENSSL_PUT_ERROR(X509, add_cert_dir, X509_R_INVALID_DIRECTORY);
+	    OPENSSL_PUT_ERROR(X509, X509_R_INVALID_DIRECTORY);
 	    return 0;
 	    }
 
@@ -237,7 +237,7 @@
 				ctx->dirs = sk_BY_DIR_ENTRY_new_null();
 				if (!ctx->dirs)
 					{
-					OPENSSL_PUT_ERROR(X509, add_cert_dir, ERR_R_MALLOC_FAILURE);
+					OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 					return 0;
 					}
 				}
@@ -311,13 +311,13 @@
 		}
 	else
 		{
-		OPENSSL_PUT_ERROR(X509, get_cert_by_subject, X509_R_WRONG_LOOKUP_TYPE);
+		OPENSSL_PUT_ERROR(X509, X509_R_WRONG_LOOKUP_TYPE);
 		goto finish;
 		}
 
 	if ((b=BUF_MEM_new()) == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, get_cert_by_subject, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB);
 		goto finish;
 		}
 	
@@ -337,7 +337,7 @@
 			j=strlen(ent->dir)+1+8+6+1+1;
 			if (!BUF_MEM_grow(b,j))
 				{
-				OPENSSL_PUT_ERROR(X509, get_cert_by_subject, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 				goto finish;
 				}
 			if (type == X509_LU_CRL && ent->hashes)
diff --git a/src/crypto/x509/by_file.c b/src/crypto/x509/by_file.c
index 2fdbce4..f1d6194 100644
--- a/src/crypto/x509/by_file.c
+++ b/src/crypto/x509/by_file.c
@@ -109,7 +109,7 @@
 
 			if (!ok)
 				{
-				OPENSSL_PUT_ERROR(X509, by_file_ctrl, X509_R_LOADING_DEFAULTS);
+				OPENSSL_PUT_ERROR(X509, X509_R_LOADING_DEFAULTS);
 				}
 			}
 		else
@@ -137,7 +137,7 @@
 
 	if ((in == NULL) || (BIO_read_filename(in,file) <= 0))
 		{
-		OPENSSL_PUT_ERROR(X509, X509_load_cert_file, ERR_R_SYS_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_SYS_LIB);
 		goto err;
 		}
 
@@ -156,7 +156,7 @@
 					}
 				else
 					{
-					OPENSSL_PUT_ERROR(X509, X509_load_cert_file, ERR_R_PEM_LIB);
+					OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB);
 					goto err;
 					}
 				}
@@ -173,7 +173,7 @@
 		x=d2i_X509_bio(in,NULL);
 		if (x == NULL)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_load_cert_file, ERR_R_ASN1_LIB);
+			OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB);
 			goto err;
 			}
 		i=X509_STORE_add_cert(ctx->store_ctx,x);
@@ -182,7 +182,7 @@
 		}
 	else
 		{
-		OPENSSL_PUT_ERROR(X509, X509_load_cert_file, X509_R_BAD_X509_FILETYPE);
+		OPENSSL_PUT_ERROR(X509, X509_R_BAD_X509_FILETYPE);
 		goto err;
 		}
 err:
@@ -203,7 +203,7 @@
 
 	if ((in == NULL) || (BIO_read_filename(in,file) <= 0))
 		{
-		OPENSSL_PUT_ERROR(X509, X509_load_crl_file, ERR_R_SYS_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_SYS_LIB);
 		goto err;
 		}
 
@@ -222,7 +222,7 @@
 					}
 				else
 					{
-					OPENSSL_PUT_ERROR(X509, X509_load_crl_file, ERR_R_PEM_LIB);
+					OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB);
 					goto err;
 					}
 				}
@@ -239,7 +239,7 @@
 		x=d2i_X509_CRL_bio(in,NULL);
 		if (x == NULL)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_load_crl_file, ERR_R_ASN1_LIB);
+			OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB);
 			goto err;
 			}
 		i=X509_STORE_add_crl(ctx->store_ctx,x);
@@ -248,7 +248,7 @@
 		}
 	else
 		{
-		OPENSSL_PUT_ERROR(X509, X509_load_crl_file, X509_R_BAD_X509_FILETYPE);
+		OPENSSL_PUT_ERROR(X509, X509_R_BAD_X509_FILETYPE);
 		goto err;
 		}
 err:
@@ -268,13 +268,13 @@
 		return X509_load_cert_file(ctx, file, type);
 	in = BIO_new_file(file, "r");
 	if(!in) {
-		OPENSSL_PUT_ERROR(X509, X509_load_cert_crl_file, ERR_R_SYS_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_SYS_LIB);
 		return 0;
 	}
 	inf = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL);
 	BIO_free(in);
 	if(!inf) {
-		OPENSSL_PUT_ERROR(X509, X509_load_cert_crl_file, ERR_R_PEM_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB);
 		return 0;
 	}
 	for(i = 0; i < sk_X509_INFO_num(inf); i++) {
diff --git a/src/crypto/x509/i2d_pr.c b/src/crypto/x509/i2d_pr.c
index 443ca53..e7f4269 100644
--- a/src/crypto/x509/i2d_pr.c
+++ b/src/crypto/x509/i2d_pr.c
@@ -78,7 +78,7 @@
 	}
 	/* Although this file is in crypto/x509 for layering reasons, it emits
 	 * an error code from ASN1 for OpenSSL compatibility. */
-	OPENSSL_PUT_ERROR(ASN1, i2d_PrivateKey, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+	OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
 	return -1;
 	}
 
diff --git a/src/crypto/x509/pkcs7.c b/src/crypto/x509/pkcs7.c
index 99ee3da..2087f94 100644
--- a/src/crypto/x509/pkcs7.c
+++ b/src/crypto/x509/pkcs7.c
@@ -57,8 +57,7 @@
   }
 
   if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) {
-    OPENSSL_PUT_ERROR(X509, pkcs7_parse_header,
-                      X509_R_NOT_PKCS7_SIGNED_DATA);
+    OPENSSL_PUT_ERROR(X509, X509_R_NOT_PKCS7_SIGNED_DATA);
     goto err;
   }
 
@@ -73,8 +72,7 @@
   }
 
   if (version < 1) {
-    OPENSSL_PUT_ERROR(X509, pkcs7_parse_header,
-                      X509_R_BAD_PKCS7_VERSION);
+    OPENSSL_PUT_ERROR(X509, X509_R_BAD_PKCS7_VERSION);
     goto err;
   }
 
@@ -103,8 +101,7 @@
   /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
   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);
+    OPENSSL_PUT_ERROR(X509, X509_R_NO_CERTIFICATES_INCLUDED);
     goto err;
   }
 
@@ -171,8 +168,7 @@
 
   if (!CBS_get_asn1(&signed_data, &crls,
                     CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) {
-    OPENSSL_PUT_ERROR(X509, PKCS7_get_CRLs,
-                      X509_R_NO_CRLS_INCLUDED);
+    OPENSSL_PUT_ERROR(X509, X509_R_NO_CRLS_INCLUDED);
     goto err;
   }
 
diff --git a/src/crypto/x509/t_crl.c b/src/crypto/x509/t_crl.c
index 93a7afb..a2d8bc7 100644
--- a/src/crypto/x509/t_crl.c
+++ b/src/crypto/x509/t_crl.c
@@ -70,7 +70,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_CRL_print_fp, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,fp,BIO_NOCLOSE);
diff --git a/src/crypto/x509/t_req.c b/src/crypto/x509/t_req.c
new file mode 100644
index 0000000..39c836c
--- /dev/null
+++ b/src/crypto/x509/t_req.c
@@ -0,0 +1,246 @@
+/* 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 <stdio.h>
+
+#include <openssl/bn.h>
+#include <openssl/buffer.h>
+#include <openssl/err.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+int X509_REQ_print_fp(FILE *fp, X509_REQ *x) {
+  BIO *bio = BIO_new(BIO_s_file());
+  if (bio == NULL) {
+    OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB);
+    return 0;
+  }
+
+  BIO_set_fp(bio, fp, BIO_NOCLOSE);
+  int ret = X509_REQ_print(bio, x);
+  BIO_free(bio);
+  return ret;
+}
+
+int X509_REQ_print_ex(BIO *bio, X509_REQ *x, unsigned long nmflags,
+                      unsigned long cflag) {
+  long l;
+  EVP_PKEY *pkey;
+  STACK_OF(X509_ATTRIBUTE) * sk;
+  char mlch = ' ';
+
+  int nmindent = 0;
+
+  if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) {
+    mlch = '\n';
+    nmindent = 12;
+  }
+
+  if (nmflags == X509_FLAG_COMPAT) {
+    nmindent = 16;
+  }
+
+  X509_REQ_INFO *ri = x->req_info;
+  if (!(cflag & X509_FLAG_NO_HEADER)) {
+    if (BIO_write(bio, "Certificate Request:\n", 21) <= 0 ||
+        BIO_write(bio, "    Data:\n", 10) <= 0) {
+      goto err;
+    }
+  }
+  if (!(cflag & X509_FLAG_NO_VERSION)) {
+    l = X509_REQ_get_version(x);
+    if (BIO_printf(bio, "%8sVersion: %ld (0x%lx)\n", "", l + 1, l) <= 0) {
+      goto err;
+    }
+  }
+  if (!(cflag & X509_FLAG_NO_SUBJECT)) {
+    if (BIO_printf(bio, "        Subject:%c", mlch) <= 0 ||
+        X509_NAME_print_ex(bio, ri->subject, nmindent, nmflags) < 0 ||
+        BIO_write(bio, "\n", 1) <= 0) {
+      goto err;
+    }
+  }
+  if (!(cflag & X509_FLAG_NO_PUBKEY)) {
+    if (BIO_write(bio, "        Subject Public Key Info:\n", 33) <= 0 ||
+        BIO_printf(bio, "%12sPublic Key Algorithm: ", "") <= 0 ||
+        i2a_ASN1_OBJECT(bio, ri->pubkey->algor->algorithm) <= 0 ||
+        BIO_puts(bio, "\n") <= 0) {
+      goto err;
+    }
+
+    pkey = X509_REQ_get_pubkey(x);
+    if (pkey == NULL) {
+      BIO_printf(bio, "%12sUnable to load Public Key\n", "");
+      ERR_print_errors(bio);
+    } else {
+      EVP_PKEY_print_public(bio, pkey, 16, NULL);
+      EVP_PKEY_free(pkey);
+    }
+  }
+
+  if (!(cflag & X509_FLAG_NO_ATTRIBUTES)) {
+    if (BIO_printf(bio, "%8sAttributes:\n", "") <= 0) {
+      goto err;
+    }
+
+    sk = x->req_info->attributes;
+    if (sk_X509_ATTRIBUTE_num(sk) == 0) {
+      if (BIO_printf(bio, "%12sa0:00\n", "") <= 0) {
+        goto err;
+      }
+    } else {
+      size_t i;
+      for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
+        X509_ATTRIBUTE *a = sk_X509_ATTRIBUTE_value(sk, i);
+        ASN1_OBJECT *aobj = X509_ATTRIBUTE_get0_object(a);
+
+        if (X509_REQ_extension_nid(OBJ_obj2nid(aobj))) {
+          continue;
+        }
+
+        if (BIO_printf(bio, "%12s", "") <= 0) {
+          goto err;
+        }
+
+        const int num_attrs = X509_ATTRIBUTE_count(a);
+        const int obj_str_len = i2a_ASN1_OBJECT(bio, aobj);
+        if (obj_str_len <= 0) {
+          if (BIO_puts(bio, "(Unable to print attribute ID.)\n") < 0) {
+            goto err;
+          } else {
+            continue;
+          }
+        }
+
+        int j;
+        for (j = 0; j < num_attrs; j++) {
+          const ASN1_TYPE *at = X509_ATTRIBUTE_get0_type(a, j);
+          const int type = at->type;
+          ASN1_BIT_STRING *bs = at->value.asn1_string;
+
+          int k;
+          for (k = 25 - obj_str_len; k > 0; k--) {
+            if (BIO_write(bio, " ", 1) != 1) {
+              goto err;
+            }
+          }
+
+          if (BIO_puts(bio, ":") <= 0) {
+            goto err;
+          }
+
+          if (type == V_ASN1_PRINTABLESTRING ||
+              type == V_ASN1_UTF8STRING ||
+              type == V_ASN1_IA5STRING ||
+              type == V_ASN1_T61STRING) {
+            if (BIO_write(bio, (char *)bs->data, bs->length) != bs->length) {
+              goto err;
+            }
+            BIO_puts(bio, "\n");
+          } else {
+            BIO_puts(bio, "unable to print attribute\n");
+          }
+        }
+      }
+    }
+  }
+
+  if (!(cflag & X509_FLAG_NO_EXTENSIONS)) {
+    STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(x);
+    if (exts) {
+      BIO_printf(bio, "%8sRequested Extensions:\n", "");
+
+      size_t i;
+      for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
+        X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i);
+        if (BIO_printf(bio, "%12s", "") <= 0) {
+          goto err;
+        }
+        ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex);
+        i2a_ASN1_OBJECT(bio, obj);
+        const int is_critical = X509_EXTENSION_get_critical(ex);
+        if (BIO_printf(bio, ": %s\n", is_critical ? "critical" : "") <= 0) {
+          goto err;
+        }
+        if (!X509V3_EXT_print(bio, ex, cflag, 16)) {
+          BIO_printf(bio, "%16s", "");
+          ASN1_STRING_print(bio, X509_EXTENSION_get_data(ex));
+        }
+        if (BIO_write(bio, "\n", 1) <= 0) {
+          goto err;
+        }
+      }
+      sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+    }
+  }
+
+  if (!(cflag & X509_FLAG_NO_SIGDUMP) &&
+      !X509_signature_print(bio, x->sig_alg, x->signature)) {
+    goto err;
+  }
+
+  return 1;
+
+err:
+  OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB);
+  return 0;
+}
+
+int X509_REQ_print(BIO *bio, X509_REQ *req) {
+  return X509_REQ_print_ex(bio, req, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
+}
diff --git a/src/crypto/x509/t_x509.c b/src/crypto/x509/t_x509.c
index 2b9a421..7785ebf 100644
--- a/src/crypto/x509/t_x509.c
+++ b/src/crypto/x509/t_x509.c
@@ -74,7 +74,7 @@
 
         if ((b=BIO_new(BIO_s_file())) == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_print_ex_fp, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB);
                 return(0);
 		}
         BIO_set_fp(b,fp,BIO_NOCLOSE);
@@ -493,7 +493,7 @@
 	if (0)
 		{
 err:
-		OPENSSL_PUT_ERROR(X509, X509_NAME_print, ERR_R_BUF_LIB);
+		OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB);
 		}
 	OPENSSL_free(b);
 	return(ret);
diff --git a/src/crypto/x509/x509_att.c b/src/crypto/x509/x509_att.c
index 90e7810..1491484 100644
--- a/src/crypto/x509/x509_att.c
+++ b/src/crypto/x509/x509_att.c
@@ -124,7 +124,7 @@
 
 	if (x == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509at_add1_attr, ERR_R_PASSED_NULL_PARAMETER);
+		OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER);
 		goto err2;
 		} 
 
@@ -144,7 +144,7 @@
 		*x=sk;
 	return(sk);
 err:
-	OPENSSL_PUT_ERROR(X509, X509at_add1_attr, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 err2:
 	if (new_attr != NULL) X509_ATTRIBUTE_free(new_attr);
 	if (sk != NULL) sk_X509_ATTRIBUTE_free(sk);
@@ -214,7 +214,7 @@
 	obj=OBJ_nid2obj(nid);
 	if (obj == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_ATTRIBUTE_create_by_NID, X509_R_UNKNOWN_NID);
+		OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID);
 		return(NULL);
 		}
 	return X509_ATTRIBUTE_create_by_OBJ(attr,obj,atrtype,data,len);
@@ -229,7 +229,7 @@
 		{
 		if ((ret=X509_ATTRIBUTE_new()) == NULL)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_ATTRIBUTE_create_by_OBJ, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 			return(NULL);
 			}
 		}
@@ -258,7 +258,7 @@
 	obj=OBJ_txt2obj(atrname, 0);
 	if (obj == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_ATTRIBUTE_create_by_txt, X509_R_INVALID_FIELD_NAME);
+		OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_NAME);
 		ERR_add_error_data(2, "name=", atrname);
 		return(NULL);
 		}
@@ -286,7 +286,7 @@
 		stmp = ASN1_STRING_set_by_NID(NULL, data, len, attrtype,
 						OBJ_obj2nid(attr->object));
 		if(!stmp) {
-			OPENSSL_PUT_ERROR(X509, X509_ATTRIBUTE_set1_data, ERR_R_ASN1_LIB);
+			OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB);
 			return 0;
 		}
 		atype = stmp->type;
@@ -314,7 +314,7 @@
 	if(!sk_ASN1_TYPE_push(attr->value.set, ttmp)) goto err;
 	return 1;
 	err:
-	OPENSSL_PUT_ERROR(X509, X509_ATTRIBUTE_set1_data, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 	return 0;
 }
 
@@ -338,7 +338,7 @@
 	ttmp = X509_ATTRIBUTE_get0_type(attr, idx);
 	if(!ttmp) return NULL;
 	if(atrtype != ASN1_TYPE_get(ttmp)){
-		OPENSSL_PUT_ERROR(X509, X509_ATTRIBUTE_get0_data, X509_R_WRONG_TYPE);
+		OPENSSL_PUT_ERROR(X509, X509_R_WRONG_TYPE);
 		return NULL;
 	}
 	return ttmp->value.ptr;
diff --git a/src/crypto/x509/x509_cmp.c b/src/crypto/x509/x509_cmp.c
index 712e36b..0e35f3e 100644
--- a/src/crypto/x509/x509_cmp.c
+++ b/src/crypto/x509/x509_cmp.c
@@ -333,13 +333,13 @@
 	case 1:
 		break;
 	case 0:
-		OPENSSL_PUT_ERROR(X509, X509_check_private_key, X509_R_KEY_VALUES_MISMATCH);
+		OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH);
 		break;
 	case -1:
-		OPENSSL_PUT_ERROR(X509, X509_check_private_key, X509_R_KEY_TYPE_MISMATCH);
+		OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH);
 		break;
 	case -2:
-	        OPENSSL_PUT_ERROR(X509, X509_check_private_key, X509_R_UNKNOWN_KEY_TYPE);
+	        OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE);
 		}
 	if (xk)
 		EVP_PKEY_free(xk);
diff --git a/src/crypto/x509/x509_lu.c b/src/crypto/x509/x509_lu.c
index a662305..6d7bc26 100644
--- a/src/crypto/x509/x509_lu.c
+++ b/src/crypto/x509/x509_lu.c
@@ -345,7 +345,7 @@
 	obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT));
 	if (obj == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_STORE_add_cert, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return 0;
 		}
 	obj->type=X509_LU_X509;
@@ -359,7 +359,7 @@
 		{
 		X509_OBJECT_free_contents(obj);
 		OPENSSL_free(obj);
-		OPENSSL_PUT_ERROR(X509, X509_STORE_add_cert, X509_R_CERT_ALREADY_IN_HASH_TABLE);
+		OPENSSL_PUT_ERROR(X509, X509_R_CERT_ALREADY_IN_HASH_TABLE);
 		ret=0;
 		} 
 	else sk_X509_OBJECT_push(ctx->objs, obj);
@@ -378,7 +378,7 @@
 	obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT));
 	if (obj == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_STORE_add_crl, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return 0;
 		}
 	obj->type=X509_LU_CRL;
@@ -392,7 +392,7 @@
 		{
 		X509_OBJECT_free_contents(obj);
 		OPENSSL_free(obj);
-		OPENSSL_PUT_ERROR(X509, X509_STORE_add_crl, X509_R_CERT_ALREADY_IN_HASH_TABLE);
+		OPENSSL_PUT_ERROR(X509, X509_R_CERT_ALREADY_IN_HASH_TABLE);
 		ret=0;
 		}
 	else sk_X509_OBJECT_push(ctx->objs, obj);
@@ -410,7 +410,7 @@
 		X509_up_ref(a->data.x509);
 		break;
 	case X509_LU_CRL:
-		CRYPTO_refcount_inc(&a->data.crl->references);
+		X509_CRL_up_ref(a->data.crl);
 		break;
 		}
 	}
@@ -572,7 +572,7 @@
 		{
 		obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx);
 		x = obj->data.crl;
-		CRYPTO_refcount_inc(&x->references);
+		X509_CRL_up_ref(x);
 		if (!sk_X509_CRL_push(sk, x))
 			{
 			CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock);
@@ -641,7 +641,7 @@
 		if (ok == X509_LU_RETRY)
 			{
 			X509_OBJECT_free_contents(&obj);
-			OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_get1_issuer, X509_R_SHOULD_RETRY);
+			OPENSSL_PUT_ERROR(X509, X509_R_SHOULD_RETRY);
 			return -1;
 			}
 		else if (ok != X509_LU_FAIL)
diff --git a/src/crypto/x509/x509_obj.c b/src/crypto/x509/x509_obj.c
index 914e0de..b6f0816 100644
--- a/src/crypto/x509/x509_obj.c
+++ b/src/crypto/x509/x509_obj.c
@@ -184,7 +184,7 @@
 		*p = '\0';
 	return(p);
 err:
-	OPENSSL_PUT_ERROR(X509, X509_NAME_oneline, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 	if (b != NULL) BUF_MEM_free(b);
 	return(NULL);
 	}
diff --git a/src/crypto/x509/x509_r2x.c b/src/crypto/x509/x509_r2x.c
index 3c8e9c0..85979ac 100644
--- a/src/crypto/x509/x509_r2x.c
+++ b/src/crypto/x509/x509_r2x.c
@@ -72,7 +72,7 @@
 
 	if ((ret=X509_new()) == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_REQ_to_X509, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 
diff --git a/src/crypto/x509/x509_req.c b/src/crypto/x509/x509_req.c
index 2732d6e..01c5113 100644
--- a/src/crypto/x509/x509_req.c
+++ b/src/crypto/x509/x509_req.c
@@ -77,7 +77,7 @@
 	ret=X509_REQ_new();
 	if (ret == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_to_X509_REQ, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 
@@ -128,24 +128,24 @@
 		ok=1;
 		break;
 	case 0:
-		OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_KEY_VALUES_MISMATCH);
+		OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH);
 		break;
 	case -1:
-		OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_KEY_TYPE_MISMATCH);
+		OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH);
 		break;
 	case -2:
 		if (k->type == EVP_PKEY_EC)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, ERR_R_EC_LIB);
+			OPENSSL_PUT_ERROR(X509, ERR_R_EC_LIB);
 			break;
 			}
 		if (k->type == EVP_PKEY_DH)
 			{
 			/* No idea */
-			OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_CANT_CHECK_DH_KEY);
+			OPENSSL_PUT_ERROR(X509, X509_R_CANT_CHECK_DH_KEY);
 			break;
 			}
-	        OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_UNKNOWN_KEY_TYPE);
+	        OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE);
 		}
 
 	EVP_PKEY_free(xk);
diff --git a/src/crypto/x509/x509_trs.c b/src/crypto/x509/x509_trs.c
index 9b7cc9c..820e605 100644
--- a/src/crypto/x509/x509_trs.c
+++ b/src/crypto/x509/x509_trs.c
@@ -156,7 +156,7 @@
 int X509_TRUST_set(int *t, int trust)
 {
 	if(X509_TRUST_get_by_id(trust) == -1) {
-		OPENSSL_PUT_ERROR(X509, X509_TRUST_set, X509_R_INVALID_TRUST);
+		OPENSSL_PUT_ERROR(X509, X509_R_INVALID_TRUST);
 		return 0;
 	}
 	*t = trust;
@@ -179,7 +179,7 @@
 	/* Need a new entry */
 	if(idx == -1) {
 		if(!(trtmp = OPENSSL_malloc(sizeof(X509_TRUST)))) {
-			OPENSSL_PUT_ERROR(X509, X509_TRUST_add, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 			return 0;
 		}
 		trtmp->flags = X509_TRUST_DYNAMIC;
@@ -188,7 +188,7 @@
 	/* Duplicate the supplied name. */
 	name_dup = BUF_strdup(name);
 	if (name_dup == NULL) {
-		OPENSSL_PUT_ERROR(X509, X509_TRUST_add, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		if (idx == -1)
 			OPENSSL_free(trtmp);
 		return 0;
@@ -210,12 +210,12 @@
 	/* If its a new entry manage the dynamic table */
 	if(idx == -1) {
 		if(!trtable && !(trtable = sk_X509_TRUST_new(tr_cmp))) {
-			OPENSSL_PUT_ERROR(X509, X509_TRUST_add, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 			trtable_free(trtmp);
 			return 0;
 		}
 		if (!sk_X509_TRUST_push(trtable, trtmp)) {
-			OPENSSL_PUT_ERROR(X509, X509_TRUST_add, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 			trtable_free(trtmp);
 			return 0;
 		}
diff --git a/src/crypto/x509/x509_v3.c b/src/crypto/x509/x509_v3.c
index 0fc9a9a..b042985 100644
--- a/src/crypto/x509/x509_v3.c
+++ b/src/crypto/x509/x509_v3.c
@@ -147,7 +147,7 @@
 
 	if (x == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509v3_add_ext, ERR_R_PASSED_NULL_PARAMETER);
+		OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER);
 		goto err2;
 		}
 
@@ -171,7 +171,7 @@
 		*x=sk;
 	return(sk);
 err:
-	OPENSSL_PUT_ERROR(X509, X509v3_add_ext, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 err2:
 	if (new_ex != NULL) X509_EXTENSION_free(new_ex);
 	if (sk != NULL) sk_X509_EXTENSION_free(sk);
@@ -187,7 +187,7 @@
 	obj=OBJ_nid2obj(nid);
 	if (obj == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_EXTENSION_create_by_NID, X509_R_UNKNOWN_NID);
+		OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID);
 		return(NULL);
 		}
 	ret=X509_EXTENSION_create_by_OBJ(ex,obj,crit,data);
@@ -203,7 +203,7 @@
 		{
 		if ((ret=X509_EXTENSION_new()) == NULL)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_EXTENSION_create_by_OBJ, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 			return(NULL);
 			}
 		}
diff --git a/src/crypto/x509/x509_vfy.c b/src/crypto/x509/x509_vfy.c
index f53f279..5d856f0 100644
--- a/src/crypto/x509/x509_vfy.c
+++ b/src/crypto/x509/x509_vfy.c
@@ -72,7 +72,8 @@
 #include "../internal.h"
 
 
-static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT;
+static CRYPTO_EX_DATA_CLASS g_ex_data_class =
+	CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA;
 
 /* CRL score values */
 
@@ -201,7 +202,7 @@
 	STACK_OF(X509) *sktmp=NULL;
 	if (ctx->cert == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_verify_cert, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
+		OPENSSL_PUT_ERROR(X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
 		return -1;
 		}
 
@@ -214,7 +215,7 @@
 		if (	((ctx->chain=sk_X509_new_null()) == NULL) ||
 			(!sk_X509_push(ctx->chain,ctx->cert)))
 			{
-			OPENSSL_PUT_ERROR(X509, X509_verify_cert, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 			goto end;
 			}
 		X509_up_ref(ctx->cert);
@@ -225,7 +226,7 @@
 	if (ctx->untrusted != NULL
 	    && (sktmp=sk_X509_dup(ctx->untrusted)) == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_verify_cert, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		goto end;
 		}
 
@@ -251,7 +252,7 @@
 			{
 			ok = ctx->get_issuer(&xtmp, ctx, x);
 			if (ok < 0)
-				return ok;
+				goto end;
 			/* If successful for now free up cert so it
 			 * will be picked up again later.
 			 */
@@ -270,10 +271,10 @@
 				{
 				if (!sk_X509_push(ctx->chain,xtmp))
 					{
-					OPENSSL_PUT_ERROR(X509, X509_verify_cert, ERR_R_MALLOC_FAILURE);
+					OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 					goto end;
 					}
-				CRYPTO_refcount_inc(&xtmp->references);
+				X509_up_ref(xtmp);
 				(void)sk_X509_delete_ptr(sktmp,xtmp);
 				ctx->last_untrusted++;
 				x=xtmp;
@@ -349,15 +350,16 @@
 
 		ok = ctx->get_issuer(&xtmp, ctx, x);
 
-		if (ok < 0) return ok;
+		if (ok < 0) goto end;
 		if (ok == 0) break;
 
 		x = xtmp;
 		if (!sk_X509_push(ctx->chain,x))
 			{
 			X509_free(xtmp);
-			OPENSSL_PUT_ERROR(X509, X509_verify_cert, ERR_R_MALLOC_FAILURE);
-			return 0;
+			OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+			ok = 0;
+			goto end;
 			}
 		num++;
 		}
@@ -990,7 +992,7 @@
 		*pissuer = best_crl_issuer;
 		*pscore = best_score;
 		*preasons = best_reasons;
-		CRYPTO_refcount_inc(&best_crl->references);
+		X509_CRL_up_ref(best_crl);
 		if (*pdcrl)
 			{
 			X509_CRL_free(*pdcrl);
@@ -1097,7 +1099,7 @@
 			{
 			if (check_crl_time(ctx, delta, 0))
 				*pscore |= CRL_SCORE_TIME_DELTA;
-			CRYPTO_refcount_inc(&delta->references);
+			X509_CRL_up_ref(delta);
 			*dcrl = delta;
 			return;
 			}
@@ -1634,7 +1636,7 @@
 				ctx->param->policies, ctx->param->flags);
 	if (ret == 0)
 		{
-		OPENSSL_PUT_ERROR(X509, check_policy, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return 0;
 		}
 	/* Invalid or inconsistent extensions */
@@ -1983,44 +1985,44 @@
 	/* CRLs can't be delta already */
 	if (base->base_crl_number || newer->base_crl_number)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_CRL_diff, X509_R_CRL_ALREADY_DELTA);
+			OPENSSL_PUT_ERROR(X509, X509_R_CRL_ALREADY_DELTA);
 			return NULL;
 			}
 	/* Base and new CRL must have a CRL number */
 	if (!base->crl_number || !newer->crl_number)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_CRL_diff, X509_R_NO_CRL_NUMBER);
+			OPENSSL_PUT_ERROR(X509, X509_R_NO_CRL_NUMBER);
 			return NULL;
 			}
 	/* Issuer names must match */
 	if (X509_NAME_cmp(X509_CRL_get_issuer(base),
 				X509_CRL_get_issuer(newer)))
 			{
-			OPENSSL_PUT_ERROR(X509, X509_CRL_diff, X509_R_ISSUER_MISMATCH);
+			OPENSSL_PUT_ERROR(X509, X509_R_ISSUER_MISMATCH);
 			return NULL;
 			}
 	/* AKID and IDP must match */
 	if (!crl_extension_match(base, newer, NID_authority_key_identifier))
 			{
-			OPENSSL_PUT_ERROR(X509, X509_CRL_diff, X509_R_AKID_MISMATCH);
+			OPENSSL_PUT_ERROR(X509, X509_R_AKID_MISMATCH);
 			return NULL;
 			}
 	if (!crl_extension_match(base, newer, NID_issuing_distribution_point))
 			{
-			OPENSSL_PUT_ERROR(X509, X509_CRL_diff, X509_R_IDP_MISMATCH);
+			OPENSSL_PUT_ERROR(X509, X509_R_IDP_MISMATCH);
 			return NULL;
 			}
 	/* Newer CRL number must exceed full CRL number */
 	if (ASN1_INTEGER_cmp(newer->crl_number, base->crl_number) <= 0)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_CRL_diff, X509_R_NEWER_CRL_NOT_NEWER);
+			OPENSSL_PUT_ERROR(X509, X509_R_NEWER_CRL_NOT_NEWER);
 			return NULL;
 			}
 	/* CRLs must verify */
 	if (skey && (X509_CRL_verify(base, skey) <= 0 ||
 			X509_CRL_verify(newer, skey) <= 0))
 		{
-		OPENSSL_PUT_ERROR(X509, X509_CRL_diff, X509_R_CRL_VERIFY_FAILURE);
+		OPENSSL_PUT_ERROR(X509, X509_R_CRL_VERIFY_FAILURE);
 		return NULL;
 		}
 	/* Create new CRL */
@@ -2085,7 +2087,7 @@
 	return crl;
 
 	memerr:
-	OPENSSL_PUT_ERROR(X509, X509_CRL_diff, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 	if (crl)
 		X509_CRL_free(crl);
 	return NULL;
@@ -2210,7 +2212,7 @@
 		idx = X509_PURPOSE_get_by_id(purpose);
 		if (idx == -1)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_purpose_inherit, X509_R_UNKNOWN_PURPOSE_ID);
+			OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_PURPOSE_ID);
 			return 0;
 			}
 		ptmp = X509_PURPOSE_get0(idx);
@@ -2219,7 +2221,7 @@
 			idx = X509_PURPOSE_get_by_id(def_purpose);
 			if (idx == -1)
 				{
-				OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_purpose_inherit, X509_R_UNKNOWN_PURPOSE_ID);
+				OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_PURPOSE_ID);
 				return 0;
 				}
 			ptmp = X509_PURPOSE_get0(idx);
@@ -2232,7 +2234,7 @@
 		idx = X509_TRUST_get_by_id(trust);
 		if (idx == -1)
 			{
-			OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_purpose_inherit, X509_R_UNKNOWN_TRUST_ID);
+			OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_TRUST_ID);
 			return 0;
 			}
 		}
@@ -2248,7 +2250,7 @@
 	ctx = (X509_STORE_CTX *)OPENSSL_malloc(sizeof(X509_STORE_CTX));
 	if (!ctx)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_new, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return NULL;
 		}
 	memset(ctx, 0, sizeof(X509_STORE_CTX));
@@ -2371,7 +2373,7 @@
 		}
 
 	memset(ctx, 0, sizeof(X509_STORE_CTX));
-	OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_init, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 	return 0;
 	}
 
diff --git a/src/crypto/x509/x509cset.c b/src/crypto/x509/x509cset.c
index b526c69..82d61d0 100644
--- a/src/crypto/x509/x509cset.c
+++ b/src/crypto/x509/x509cset.c
@@ -57,6 +57,8 @@
 #include <openssl/obj.h>
 #include <openssl/x509.h>
 
+#include "../internal.h"
+
 
 int X509_CRL_set_version(X509_CRL *x, long version)
 	{
@@ -128,6 +130,11 @@
 	return 1;
 	}
 
+void X509_CRL_up_ref(X509_CRL *crl)
+	{
+	CRYPTO_refcount_inc(&crl->references);
+	}
+
 int X509_REVOKED_set_revocationDate(X509_REVOKED *x, ASN1_TIME *tm)
 	{
 	ASN1_TIME *in;
diff --git a/src/crypto/x509/x509name.c b/src/crypto/x509/x509name.c
index 042d18b..7bb3aa1 100644
--- a/src/crypto/x509/x509name.c
+++ b/src/crypto/x509/x509name.c
@@ -254,7 +254,7 @@
 	new_name->set=set;
 	if (!sk_X509_NAME_ENTRY_insert(sk,new_name,loc))
 		{
-		OPENSSL_PUT_ERROR(X509, X509_NAME_add_entry, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 	if (inc)
@@ -279,7 +279,7 @@
 	obj=OBJ_txt2obj(field, 0);
 	if (obj == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_NAME_ENTRY_create_by_txt, X509_R_INVALID_FIELD_NAME);
+		OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_NAME);
 		ERR_add_error_data(2, "name=", field);
 		return(NULL);
 		}
@@ -297,7 +297,7 @@
 	obj=OBJ_nid2obj(nid);
 	if (obj == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_NAME_ENTRY_create_by_NID, X509_R_UNKNOWN_NID);
+		OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID);
 		return(NULL);
 		}
 	nentry = X509_NAME_ENTRY_create_by_OBJ(ne,obj,type,bytes,len);
@@ -336,7 +336,7 @@
 	{
 	if ((ne == NULL) || (obj == NULL))
 		{
-		OPENSSL_PUT_ERROR(X509, X509_NAME_ENTRY_set_object, ERR_R_PASSED_NULL_PARAMETER);
+		OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER);
 		return(0);
 		}
 	ASN1_OBJECT_free(ne->object);
diff --git a/src/crypto/x509/x509spki.c b/src/crypto/x509/x509spki.c
index 9bab957..ccf93e0 100644
--- a/src/crypto/x509/x509spki.c
+++ b/src/crypto/x509/x509spki.c
@@ -84,15 +84,15 @@
 	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);
+		OPENSSL_PUT_ERROR(X509, 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);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	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_PUT_ERROR(X509, X509_R_BASE64_DECODE_ERROR);
 		OPENSSL_free(spki_der);
 		return NULL;
 	}
@@ -113,18 +113,18 @@
 	der_len = i2d_NETSCAPE_SPKI(spki, NULL);
 	if (!EVP_EncodedLength(&b64_len, der_len))
 		{
-		OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_encode, ERR_R_OVERFLOW);
+		OPENSSL_PUT_ERROR(X509, ERR_R_OVERFLOW);
 		return NULL;
 		}
 	der_spki = OPENSSL_malloc(der_len);
 	if (der_spki == NULL) {
-		OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_encode, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	b64_str = OPENSSL_malloc(b64_len);
 	if (b64_str == NULL) {
 		OPENSSL_free(der_spki);
-		OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_encode, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	p = der_spki;
diff --git a/src/crypto/x509/x_all.c b/src/crypto/x509/x_all.c
index 785fd1e..d7f2d29 100644
--- a/src/crypto/x509/x_all.c
+++ b/src/crypto/x509/x_all.c
@@ -64,9 +64,6 @@
 #include <openssl/x509.h>
 
 
-extern const ASN1_ITEM RSAPrivateKey_it;
-extern const ASN1_ITEM RSAPublicKey_it;
-
 int X509_verify(X509 *a, EVP_PKEY *r)
 	{
 	if (X509_ALGOR_cmp(a->sig_alg, a->cert_info->signature))
@@ -144,6 +141,12 @@
 		x->signature, x->spkac,pkey,md));
 	}
 
+int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *x, EVP_PKEY *pkey)
+	{
+	return (ASN1_item_verify(ASN1_ITEM_rptr(NETSCAPE_SPKAC), x->sig_algor,
+		x->signature, x->spkac, pkey));
+	}
+
 #ifndef OPENSSL_NO_FP_API
 X509 *d2i_X509_fp(FILE *fp, X509 **x509)
 	{
@@ -239,17 +242,17 @@
 #ifndef OPENSSL_NO_FP_API
 RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa)
 	{
-	return ASN1_item_d2i_fp(ASN1_ITEM_rptr(RSAPrivateKey), fp, rsa);
+	return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPrivateKey, fp, rsa);
 	}
 
 int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa)
 	{
-	return ASN1_item_i2d_fp(ASN1_ITEM_rptr(RSAPrivateKey), fp, rsa);
+	return ASN1_i2d_fp_of_const(RSA, i2d_RSAPrivateKey, fp, rsa);
 	}
 
 RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa)
 	{
-	return ASN1_item_d2i_fp(ASN1_ITEM_rptr(RSAPublicKey), fp, rsa);
+	return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPublicKey, fp, rsa);
 	}
 
 RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa)
@@ -261,7 +264,7 @@
 
 int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa)
 	{
-	return ASN1_item_i2d_fp(ASN1_ITEM_rptr(RSAPublicKey), fp, rsa);
+	return ASN1_i2d_fp_of_const(RSA, i2d_RSAPublicKey, fp, rsa);
 	}
 
 int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa)
@@ -272,17 +275,17 @@
 
 RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa)
 	{
-	return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);
+	return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPrivateKey, bp, rsa);
 	}
 
 int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa)
 	{
-	return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);
+	return ASN1_i2d_bio_of_const(RSA, i2d_RSAPrivateKey, bp, rsa);
 	}
 
 RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa)
 	{
-	return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa);
+	return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPublicKey, bp, rsa);
 	}
 
 
@@ -293,7 +296,7 @@
 
 int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa)
 	{
-	return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa);
+	return ASN1_i2d_bio_of_const(RSA, i2d_RSAPublicKey, bp, rsa);
 	}
 
 int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa)
diff --git a/src/crypto/x509/x_crl.c b/src/crypto/x509/x_crl.c
index 2f41bb1..d516872 100644
--- a/src/crypto/x509/x_crl.c
+++ b/src/crypto/x509/x_crl.c
@@ -400,7 +400,7 @@
 	if(!inf->revoked)
 		inf->revoked = sk_X509_REVOKED_new(X509_REVOKED_cmp);
 	if(!inf->revoked || !sk_X509_REVOKED_push(inf->revoked, rev)) {
-		OPENSSL_PUT_ERROR(X509, X509_CRL_add0_revoked, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return 0;
 	}
 	inf->enc.modified = 1;
diff --git a/src/crypto/x509/x_info.c b/src/crypto/x509/x_info.c
index f9e9ab8..be579d7 100644
--- a/src/crypto/x509/x_info.c
+++ b/src/crypto/x509/x_info.c
@@ -69,7 +69,7 @@
 	ret=(X509_INFO *)OPENSSL_malloc(sizeof(X509_INFO));
 	if (ret == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_INFO_new, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return(NULL);
 		}
  
diff --git a/src/crypto/x509/x_name.c b/src/crypto/x509/x_name.c
index 5cfb3ae..762756b 100644
--- a/src/crypto/x509/x_name.c
+++ b/src/crypto/x509/x_name.c
@@ -150,7 +150,7 @@
 	return 1;
 
  memerr:
-	OPENSSL_PUT_ERROR(X509, x509_name_ex_new, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 	if (ret)
 		{
 		if (ret->entries)
@@ -239,7 +239,7 @@
 err:
         if (nm.x != NULL)
 		X509_NAME_free(nm.x);
-	OPENSSL_PUT_ERROR(X509, x509_name_ex_d2i, ERR_R_ASN1_LIB);
+	OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB);
 	return 0;
 }
 
@@ -300,7 +300,7 @@
 memerr:
 	sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s,
 					     local_sk_X509_NAME_ENTRY_free);
-	OPENSSL_PUT_ERROR(X509, x509_name_encode, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 	return -1;
 }
 
diff --git a/src/crypto/x509/x_pkey.c b/src/crypto/x509/x_pkey.c
index 5bc6415..f5e98b8 100644
--- a/src/crypto/x509/x_pkey.c
+++ b/src/crypto/x509/x_pkey.c
@@ -69,7 +69,7 @@
 	X509_PKEY *ret = OPENSSL_malloc(sizeof(X509_PKEY));
 	if (ret == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_PKEY_new, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 	memset(ret, 0, sizeof(X509_PKEY));
diff --git a/src/crypto/x509/x_pubkey.c b/src/crypto/x509/x_pubkey.c
index c2e0863..a16edca 100644
--- a/src/crypto/x509/x_pubkey.c
+++ b/src/crypto/x509/x_pubkey.c
@@ -100,19 +100,19 @@
 			{
 			if (!pkey->ameth->pub_encode(pk, pkey))
 				{
-				OPENSSL_PUT_ERROR(X509, X509_PUBKEY_set, X509_R_PUBLIC_KEY_ENCODE_ERROR);
+				OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_ENCODE_ERROR);
 				goto error;
 				}
 			}
 		else
 			{
-			OPENSSL_PUT_ERROR(X509, X509_PUBKEY_set, X509_R_METHOD_NOT_SUPPORTED);
+			OPENSSL_PUT_ERROR(X509, X509_R_METHOD_NOT_SUPPORTED);
 			goto error;
 			}
 		}
 	else
 		{
-		OPENSSL_PUT_ERROR(X509, X509_PUBKEY_set, X509_R_UNSUPPORTED_ALGORITHM);
+		OPENSSL_PUT_ERROR(X509, X509_R_UNSUPPORTED_ALGORITHM);
 		goto error;
 		}
 
@@ -151,13 +151,13 @@
 
 	if ((ret = EVP_PKEY_new()) == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		goto error;
 		}
 
 	if (!EVP_PKEY_set_type(ret, OBJ_obj2nid(key->algor->algorithm)))
 		{
-		OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, X509_R_UNSUPPORTED_ALGORITHM);
+		OPENSSL_PUT_ERROR(X509, X509_R_UNSUPPORTED_ALGORITHM);
 		goto error;
 		}
 
@@ -165,13 +165,13 @@
 		{
 		if (!ret->ameth->pub_decode(ret, key))
 			{
-			OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, X509_R_PUBLIC_KEY_DECODE_ERROR);
+			OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_DECODE_ERROR);
 			goto error;
 			}
 		}
 	else
 		{
-		OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, X509_R_METHOD_NOT_SUPPORTED);
+		OPENSSL_PUT_ERROR(X509, X509_R_METHOD_NOT_SUPPORTED);
 		goto error;
 		}
 
@@ -262,7 +262,7 @@
 	pktmp = EVP_PKEY_new();
 	if (!pktmp)
 		{
-		OPENSSL_PUT_ERROR(X509, i2d_RSA_PUBKEY, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return 0;
 		}
 	EVP_PKEY_set1_RSA(pktmp, (RSA*) a);
@@ -301,7 +301,7 @@
 	pktmp = EVP_PKEY_new();
 	if(!pktmp)
 		{
-		OPENSSL_PUT_ERROR(X509, i2d_DSA_PUBKEY,  ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return 0;
 		}
 	EVP_PKEY_set1_DSA(pktmp, (DSA*) a);
@@ -338,7 +338,7 @@
 	if (!a)	return(0);
 	if ((pktmp = EVP_PKEY_new()) == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509, i2d_EC_PUBKEY,  ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
 		return(0);
 		}
 	EVP_PKEY_set1_EC_KEY(pktmp, (EC_KEY*) a);
diff --git a/src/crypto/x509/x_x509a.c b/src/crypto/x509/x_x509a.c
index e13204b..fb7172b 100644
--- a/src/crypto/x509/x_x509a.c
+++ b/src/crypto/x509/x_x509a.c
@@ -133,24 +133,44 @@
 
 int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj)
 {
-	X509_CERT_AUX *aux;
-	ASN1_OBJECT *objtmp;
-	if(!(objtmp = OBJ_dup(obj))) return 0;
-	if(!(aux = aux_get(x))) return 0;
-	if(!aux->trust
-		&& !(aux->trust = sk_ASN1_OBJECT_new_null())) return 0;
-	return sk_ASN1_OBJECT_push(aux->trust, objtmp);
+	ASN1_OBJECT *objtmp = OBJ_dup(obj);
+	if (objtmp == NULL)
+		goto err;
+	X509_CERT_AUX *aux = aux_get(x);
+	if (aux->trust == NULL)
+		{
+		aux->trust = sk_ASN1_OBJECT_new_null();
+		if (aux->trust == NULL)
+			goto err;
+		}
+	if (!sk_ASN1_OBJECT_push(aux->trust, objtmp))
+		goto err;
+	return 1;
+
+err:
+	ASN1_OBJECT_free(objtmp);
+	return 0;
 }
 
 int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj)
 {
-	X509_CERT_AUX *aux;
-	ASN1_OBJECT *objtmp;
-	if(!(objtmp = OBJ_dup(obj))) return 0;
-	if(!(aux = aux_get(x))) return 0;
-	if(!aux->reject
-		&& !(aux->reject = sk_ASN1_OBJECT_new_null())) return 0;
-	return sk_ASN1_OBJECT_push(aux->reject, objtmp);
+	ASN1_OBJECT *objtmp = OBJ_dup(obj);
+	if (objtmp == NULL)
+		goto err;
+	X509_CERT_AUX *aux = aux_get(x);
+	if (aux->reject == NULL)
+		{
+		aux->reject = sk_ASN1_OBJECT_new_null();
+		if (aux->reject == NULL)
+			goto err;
+		}
+	if (!sk_ASN1_OBJECT_push(aux->reject, objtmp))
+		goto err;
+	return 1;
+
+err:
+	ASN1_OBJECT_free(objtmp);
+	return 0;
 }
 
 void X509_trust_clear(X509 *x)
diff --git a/src/crypto/x509v3/CMakeLists.txt b/src/crypto/x509v3/CMakeLists.txt
index c7e6054..5cc1b49 100644
--- a/src/crypto/x509v3/CMakeLists.txt
+++ b/src/crypto/x509v3/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
 
 add_library(
   x509v3
@@ -46,7 +46,7 @@
 add_executable(
   v3name_test
 
-  v3nametest.c
+  v3name_test.c
 
   $<TARGET_OBJECTS:test_support>
 )
@@ -56,7 +56,7 @@
 add_executable(
   tab_test
 
-  tabtest.c
+  tab_test.c
 
   $<TARGET_OBJECTS:test_support>
 )
diff --git a/src/crypto/x509v3/tabtest.c b/src/crypto/x509v3/tab_test.c
similarity index 100%
rename from src/crypto/x509v3/tabtest.c
rename to src/crypto/x509v3/tab_test.c
diff --git a/src/crypto/x509v3/v3_akey.c b/src/crypto/x509v3/v3_akey.c
index f6e6b69..9578a57 100644
--- a/src/crypto/x509v3/v3_akey.c
+++ b/src/crypto/x509v3/v3_akey.c
@@ -144,7 +144,7 @@
 			}
 		else
 			{
-			OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_KEYID, X509V3_R_UNKNOWN_OPTION);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_OPTION);
 			ERR_add_error_data(2, "name=", cnf->name);
 			return NULL;
 			}
@@ -154,7 +154,7 @@
 		{
 		if(ctx && (ctx->flags==CTX_TEST))
 			return AUTHORITY_KEYID_new();
-		OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_KEYID, X509V3_R_NO_ISSUER_CERTIFICATE);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_ISSUER_CERTIFICATE);
 		return NULL;
 		}
 
@@ -167,7 +167,7 @@
 			ikeyid = X509V3_EXT_d2i(ext);
 		if(keyid==2 && !ikeyid)
 			{
-			OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_KEYID, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID);
 			return NULL;
 			}
 		}
@@ -178,7 +178,7 @@
 		serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(cert));
 		if(!isname || !serial)
 			{
-			OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_KEYID, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS);
 			goto err;
 			}
 		}
@@ -191,7 +191,7 @@
 			|| !(gen = GENERAL_NAME_new())
 			|| !sk_GENERAL_NAME_push(gens, gen))
 			{
-			OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_KEYID, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			goto err;
 			}
 		gen->type = GEN_DIRNAME;
diff --git a/src/crypto/x509v3/v3_alt.c b/src/crypto/x509v3/v3_alt.c
index f547316..e639f45 100644
--- a/src/crypto/x509v3/v3_alt.c
+++ b/src/crypto/x509v3/v3_alt.c
@@ -250,7 +250,7 @@
 	CONF_VALUE *cnf;
 	size_t i;
 	if(!(gens = sk_GENERAL_NAME_new_null())) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_issuer_alt, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
@@ -282,21 +282,21 @@
 	size_t j;
 	if(ctx && (ctx->flags == CTX_TEST)) return 1;
 	if(!ctx || !ctx->issuer_cert) {
-		OPENSSL_PUT_ERROR(X509V3, copy_issuer, X509V3_R_NO_ISSUER_DETAILS);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_ISSUER_DETAILS);
 		goto err;
 	}
         i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1);
 	if(i < 0) return 1;
         if(!(ext = X509_get_ext(ctx->issuer_cert, i)) ||
                         !(ialt = X509V3_EXT_d2i(ext)) ) {
-		OPENSSL_PUT_ERROR(X509V3, copy_issuer, X509V3_R_ISSUER_DECODE_ERROR);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_ISSUER_DECODE_ERROR);
 		goto err;
 	}
 
 	for(j = 0; j < sk_GENERAL_NAME_num(ialt); j++) {
 		gen = sk_GENERAL_NAME_value(ialt, j);
 		if(!sk_GENERAL_NAME_push(gens, gen)) {
-			OPENSSL_PUT_ERROR(X509V3, copy_issuer, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			goto err;
 		}
 	}
@@ -316,7 +316,7 @@
 	CONF_VALUE *cnf;
 	size_t i;
 	if(!(gens = sk_GENERAL_NAME_new_null())) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_subject_alt, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
@@ -354,7 +354,7 @@
 	if(ctx != NULL && ctx->flags == CTX_TEST)
 		return 1;
 	if(!ctx || (!ctx->subject_cert && !ctx->subject_req)) {
-		OPENSSL_PUT_ERROR(X509V3, copy_email, X509V3_R_NO_SUBJECT_DETAILS);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_SUBJECT_DETAILS);
 		goto err;
 	}
 	/* Find the subject name */
@@ -374,14 +374,14 @@
                         i--;
                         }
 		if(!email || !(gen = GENERAL_NAME_new())) {
-			OPENSSL_PUT_ERROR(X509V3, copy_email, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			goto err;
 		}
 		gen->d.ia5 = email;
 		email = NULL;
 		gen->type = GEN_EMAIL;
 		if(!sk_GENERAL_NAME_push(gens, gen)) {
-			OPENSSL_PUT_ERROR(X509V3, copy_email, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			goto err;
 		}
 		gen = NULL;
@@ -405,7 +405,7 @@
 	CONF_VALUE *cnf;
 	size_t i;
 	if(!(gens = sk_GENERAL_NAME_new_null())) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_GENERAL_NAMES, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
@@ -434,7 +434,7 @@
 
 	if(!value)
 		{
-		OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_MISSING_VALUE);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE);
 		return NULL;
 		}
 
@@ -445,7 +445,7 @@
 		gen = GENERAL_NAME_new();
 		if(gen == NULL)
 			{
-			OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			return NULL;
 			}
 		}
@@ -463,7 +463,7 @@
 		ASN1_OBJECT *obj;
 		if(!(obj = OBJ_txt2obj(value,0)))
 			{
-			OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_BAD_OBJECT);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_OBJECT);
 			ERR_add_error_data(2, "value=", value);
 			goto err;
 			}
@@ -478,7 +478,7 @@
 			gen->d.ip = a2i_IPADDRESS(value);
 		if(gen->d.ip == NULL)
 			{
-			OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_BAD_IP_ADDRESS);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_IP_ADDRESS);
 			ERR_add_error_data(2, "value=", value);
 			goto err;
 			}
@@ -487,7 +487,7 @@
 		case GEN_DIRNAME:
 		if (!do_dirname(gen, value, ctx))
 			{
-			OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_DIRNAME_ERROR);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_DIRNAME_ERROR);
 			goto err;
 			}
 		break;
@@ -495,12 +495,12 @@
 		case GEN_OTHERNAME:
 		if (!do_othername(gen, value, ctx))
 			{
-			OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_OTHERNAME_ERROR);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_OTHERNAME_ERROR);
 			goto err;
 			}
 		break;
 		default:
-		OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_UNSUPPORTED_TYPE);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNSUPPORTED_TYPE);
 		goto err;
 		}
 
@@ -510,7 +510,7 @@
 			      !ASN1_STRING_set(gen->d.ia5, (unsigned char*)value,
 					       strlen(value)))
 			{
-			OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			goto err;
 			}
 		}
@@ -538,7 +538,7 @@
 
 	if(!value)
 		{
-		OPENSSL_PUT_ERROR(X509V3, v2i_GENERAL_NAME_ex, X509V3_R_MISSING_VALUE);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE);
 		return NULL;
 		}
 
@@ -558,7 +558,7 @@
 		type = GEN_OTHERNAME;
 	else
 		{
-		OPENSSL_PUT_ERROR(X509V3, v2i_GENERAL_NAME_ex, X509V3_R_UNSUPPORTED_OPTION);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNSUPPORTED_OPTION);
 		ERR_add_error_data(2, "name=", name);
 		return NULL;
 		}
@@ -604,7 +604,7 @@
 	sk = X509V3_get_section(ctx, value);
 	if (!sk)
 		{
-		OPENSSL_PUT_ERROR(X509V3, do_dirname, X509V3_R_SECTION_NOT_FOUND);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND);
 		ERR_add_error_data(2, "section=", value);
 		X509_NAME_free(nm);
 		return 0;
diff --git a/src/crypto/x509v3/v3_bcons.c b/src/crypto/x509v3/v3_bcons.c
index a1381b4..73ef21e 100644
--- a/src/crypto/x509v3/v3_bcons.c
+++ b/src/crypto/x509v3/v3_bcons.c
@@ -103,7 +103,7 @@
 	CONF_VALUE *val;
 	size_t i;
 	if(!(bcons = BASIC_CONSTRAINTS_new())) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_BASIC_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	for(i = 0; i < sk_CONF_VALUE_num(values); i++) {
@@ -113,7 +113,7 @@
 		} else if(!strcmp(val->name, "pathlen")) {
 			if(!X509V3_get_value_int(val, &bcons->pathlen)) goto err;
 		} else {
-			OPENSSL_PUT_ERROR(X509V3, v2i_BASIC_CONSTRAINTS, X509V3_R_INVALID_NAME);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NAME);
 			X509V3_conf_err(val);
 			goto err;
 		}
diff --git a/src/crypto/x509v3/v3_bitst.c b/src/crypto/x509v3/v3_bitst.c
index 15e9859..e1e2087 100644
--- a/src/crypto/x509v3/v3_bitst.c
+++ b/src/crypto/x509v3/v3_bitst.c
@@ -112,7 +112,7 @@
 	size_t i;
 	const BIT_STRING_BITNAME *bnam;
 	if(!(bs = M_ASN1_BIT_STRING_new())) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_ASN1_BIT_STRING, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
@@ -121,7 +121,7 @@
 			if(!strcmp(bnam->sname, val->name) ||
 				!strcmp(bnam->lname, val->name) ) {
 				if(!ASN1_BIT_STRING_set_bit(bs, bnam->bitnum, 1)) {
-					OPENSSL_PUT_ERROR(X509V3, v2i_ASN1_BIT_STRING, ERR_R_MALLOC_FAILURE);
+					OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 					M_ASN1_BIT_STRING_free(bs);
 					return NULL;
 				}
@@ -129,7 +129,7 @@
 			}
 		}
 		if(!bnam->lname) {
-			OPENSSL_PUT_ERROR(X509V3, v2i_ASN1_BIT_STRING, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT);
 			X509V3_conf_err(val);
 			M_ASN1_BIT_STRING_free(bs);
 			return NULL;
diff --git a/src/crypto/x509v3/v3_conf.c b/src/crypto/x509v3/v3_conf.c
index cb6569f..fe71566 100644
--- a/src/crypto/x509v3/v3_conf.c
+++ b/src/crypto/x509v3/v3_conf.c
@@ -92,7 +92,7 @@
 	ret = do_ext_nconf(conf, ctx, OBJ_sn2nid(name), crit, value);
 	if (!ret)
 		{
-		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_nconf, X509V3_R_ERROR_IN_EXTENSION);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_IN_EXTENSION);
 		ERR_add_error_data(4,"name=", name, ", value=", value);
 		}
 	return ret;
@@ -123,12 +123,12 @@
 	void *ext_struc;
 	if (ext_nid == NID_undef)
 		{
-		OPENSSL_PUT_ERROR(X509V3, do_ext_nconf, X509V3_R_UNKNOWN_EXTENSION_NAME);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION_NAME);
 		return NULL;
 		}
 	if (!(method = X509V3_EXT_get_nid(ext_nid)))
 		{
-		OPENSSL_PUT_ERROR(X509V3, do_ext_nconf, X509V3_R_UNKNOWN_EXTENSION);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION);
 		return NULL;
 		}
 	/* Now get internal extension representation based on type */
@@ -138,7 +138,7 @@
 		else nval = X509V3_parse_list(value);
 		if(sk_CONF_VALUE_num(nval) <= 0)
 			{
-			OPENSSL_PUT_ERROR(X509V3, do_ext_nconf, X509V3_R_INVALID_EXTENSION_STRING);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_EXTENSION_STRING);
 			ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=", value);
 			return NULL;
 			}
@@ -155,14 +155,14 @@
 		{
 		if(!ctx->db || !ctx->db_meth)
 			{
-			OPENSSL_PUT_ERROR(X509V3, do_ext_nconf, X509V3_R_NO_CONFIG_DATABASE);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_CONFIG_DATABASE);
 			return NULL;
 			}
 		if(!(ext_struc = method->r2i(method, ctx, value))) return NULL;
 		}
 	else
 		{
-		OPENSSL_PUT_ERROR(X509V3, do_ext_nconf, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED);
 		ERR_add_error_data(2, "name=", OBJ_nid2sn(ext_nid));
 		return NULL;
 		}
@@ -207,7 +207,7 @@
 	return ext;
 
 	merr:
-	OPENSSL_PUT_ERROR(X509V3, do_ext_i2d, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	return NULL;
 
 	}
@@ -218,7 +218,7 @@
 	{
 	const X509V3_EXT_METHOD *method;
 	if (!(method = X509V3_EXT_get_nid(ext_nid))) {
-		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_i2d, X509V3_R_UNKNOWN_EXTENSION);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION);
 		return NULL;
 	}
 	return do_ext_i2d(method, ext_nid, crit, ext_struc);
@@ -271,7 +271,7 @@
 	X509_EXTENSION *extension=NULL;
 	if (!(obj = OBJ_txt2obj(ext, 0)))
 		{
-		OPENSSL_PUT_ERROR(X509V3, v3_generic_extension, X509V3_R_EXTENSION_NAME_ERROR);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_NAME_ERROR);
 		ERR_add_error_data(2, "name=", ext);
 		goto err;
 		}
@@ -283,14 +283,14 @@
 
 	if (ext_der == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509V3, v3_generic_extension, X509V3_R_EXTENSION_VALUE_ERROR);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
 		ERR_add_error_data(2, "value=", value);
 		goto err;
 		}
 
 	if (!(oct = M_ASN1_OCTET_STRING_new()))
 		{
-		OPENSSL_PUT_ERROR(X509V3, v3_generic_extension, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 
@@ -389,7 +389,7 @@
 	{
 	if(!ctx->db || !ctx->db_meth || !ctx->db_meth->get_string)
 		{
-		OPENSSL_PUT_ERROR(X509V3, X509V3_get_string, X509V3_R_OPERATION_NOT_DEFINED);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_OPERATION_NOT_DEFINED);
 		return NULL;
 		}
 	if (ctx->db_meth->get_string)
@@ -401,7 +401,7 @@
 	{
 	if(!ctx->db || !ctx->db_meth || !ctx->db_meth->get_section)
 		{
-		OPENSSL_PUT_ERROR(X509V3, X509V3_get_section, X509V3_R_OPERATION_NOT_DEFINED);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_OPERATION_NOT_DEFINED);
 		return NULL;
 		}
 	if (ctx->db_meth->get_section)
diff --git a/src/crypto/x509v3/v3_cpols.c b/src/crypto/x509v3/v3_cpols.c
index cbe596b..0b58676 100644
--- a/src/crypto/x509v3/v3_cpols.c
+++ b/src/crypto/x509v3/v3_cpols.c
@@ -146,19 +146,19 @@
 	int ia5org;
 	pols = sk_POLICYINFO_new_null();
 	if (pols == NULL) {
-		OPENSSL_PUT_ERROR(X509V3, r2i_certpol, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	vals =  X509V3_parse_list(value);
 	if (vals == NULL) {
-		OPENSSL_PUT_ERROR(X509V3, r2i_certpol, ERR_R_X509V3_LIB);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_X509V3_LIB);
 		goto err;
 	}
 	ia5org = 0;
 	for(i = 0; i < sk_CONF_VALUE_num(vals); i++) {
 		cnf = sk_CONF_VALUE_value(vals, i);
 		if(cnf->value || !cnf->name ) {
-			OPENSSL_PUT_ERROR(X509V3, r2i_certpol, X509V3_R_INVALID_POLICY_IDENTIFIER);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_POLICY_IDENTIFIER);
 			X509V3_conf_err(cnf);
 			goto err;
 		}
@@ -170,7 +170,7 @@
 			STACK_OF(CONF_VALUE) *polsect;
 			polsect = X509V3_get_section(ctx, pstr + 1);
 			if(!polsect) {
-				OPENSSL_PUT_ERROR(X509V3, r2i_certpol, X509V3_R_INVALID_SECTION);
+				OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION);
 
 				X509V3_conf_err(cnf);
 				goto err;
@@ -180,7 +180,7 @@
 			if(!pol) goto err;
 		} else {
 			if(!(pobj = OBJ_txt2obj(cnf->name, 0))) {
-				OPENSSL_PUT_ERROR(X509V3, r2i_certpol, X509V3_R_INVALID_OBJECT_IDENTIFIER);
+				OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
 				X509V3_conf_err(cnf);
 				goto err;
 			}
@@ -189,7 +189,7 @@
 		}
 		if (!sk_POLICYINFO_push(pols, pol)){
 			POLICYINFO_free(pol);
-			OPENSSL_PUT_ERROR(X509V3, r2i_certpol, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			goto err;
 		}
 	}
@@ -214,7 +214,7 @@
 		if(!strcmp(cnf->name, "policyIdentifier")) {
 			ASN1_OBJECT *pobj;
 			if(!(pobj = OBJ_txt2obj(cnf->value, 0))) {
-				OPENSSL_PUT_ERROR(X509V3, policy_section, X509V3_R_INVALID_OBJECT_IDENTIFIER);
+				OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
 				X509V3_conf_err(cnf);
 				goto err;
 			}
@@ -229,7 +229,7 @@
                         /* TODO(fork): const correctness */
 			qual->pqualid = (ASN1_OBJECT*) OBJ_nid2obj(NID_id_qt_cps);
 			if (qual->pqualid == NULL) {
-				OPENSSL_PUT_ERROR(X509V3, policy_section, ERR_R_INTERNAL_ERROR);
+				OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR);
 				goto err;
 			}
 			qual->d.cpsuri = M_ASN1_IA5STRING_new();
@@ -241,13 +241,13 @@
 		} else if(!name_cmp(cnf->name, "userNotice")) {
 			STACK_OF(CONF_VALUE) *unot;
 			if(*cnf->value != '@') {
-				OPENSSL_PUT_ERROR(X509V3, policy_section, X509V3_R_EXPECTED_A_SECTION_NAME);
+				OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXPECTED_A_SECTION_NAME);
 				X509V3_conf_err(cnf);
 				goto err;
 			}
 			unot = X509V3_get_section(ctx, cnf->value + 1);
 			if(!unot) {
-				OPENSSL_PUT_ERROR(X509V3, policy_section, X509V3_R_INVALID_SECTION);
+				OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION);
 
 				X509V3_conf_err(cnf);
 				goto err;
@@ -260,21 +260,21 @@
 			if(!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
 								 goto merr;
 		} else {
-			OPENSSL_PUT_ERROR(X509V3, policy_section, X509V3_R_INVALID_OPTION);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OPTION);
 
 			X509V3_conf_err(cnf);
 			goto err;
 		}
 	}
 	if(!pol->policyid) {
-		OPENSSL_PUT_ERROR(X509V3, policy_section, X509V3_R_NO_POLICY_IDENTIFIER);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_POLICY_IDENTIFIER);
 		goto err;
 	}
 
 	return pol;
 
 	merr:
-	OPENSSL_PUT_ERROR(X509V3, policy_section, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 
 	err:
 	POLICYINFO_free(pol);
@@ -296,7 +296,7 @@
 	qual->pqualid = (ASN1_OBJECT *) OBJ_nid2obj(NID_id_qt_unotice);
 	if (qual->pqualid == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509V3, notice_section, ERR_R_INTERNAL_ERROR);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR);
 		goto err;
 		}
 	if(!(not = USERNOTICE_new())) goto merr;
@@ -328,7 +328,7 @@
 			} else nref = not->noticeref;
 			nos = X509V3_parse_list(cnf->value);
 			if(!nos || !sk_CONF_VALUE_num(nos)) {
-				OPENSSL_PUT_ERROR(X509V3, notice_section, X509V3_R_INVALID_NUMBERS);
+				OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NUMBERS);
 				X509V3_conf_err(cnf);
 				goto err;
 			}
@@ -337,7 +337,7 @@
 			if (!ret)
 				goto err;
 		} else {
-			OPENSSL_PUT_ERROR(X509V3, notice_section, X509V3_R_INVALID_OPTION);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OPTION);
 			X509V3_conf_err(cnf);
 			goto err;
 		}
@@ -345,14 +345,14 @@
 
 	if(not->noticeref && 
 	      (!not->noticeref->noticenos || !not->noticeref->organization)) {
-			OPENSSL_PUT_ERROR(X509V3, notice_section, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS);
 			goto err;
 	}
 
 	return qual;
 
 	merr:
-	OPENSSL_PUT_ERROR(X509V3, notice_section, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 
 	err:
 	POLICYQUALINFO_free(qual);
@@ -369,7 +369,7 @@
 	for(i = 0; i < sk_CONF_VALUE_num(nos); i++) {
 		cnf = sk_CONF_VALUE_value(nos, i);
 		if(!(aint = s2i_ASN1_INTEGER(NULL, cnf->name))) {
-			OPENSSL_PUT_ERROR(X509V3, nref_nos, X509V3_R_INVALID_NUMBER);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NUMBER);
 			goto err;
 		}
 		if(!sk_ASN1_INTEGER_push(nnums, aint)) goto merr;
@@ -377,7 +377,7 @@
 	return 1;
 
 	merr:
-	OPENSSL_PUT_ERROR(X509V3, nref_nos, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 
 	err:
 	sk_ASN1_INTEGER_pop_free(nnums, ASN1_STRING_free);
diff --git a/src/crypto/x509v3/v3_crld.c b/src/crypto/x509v3/v3_crld.c
index e41dd65..3984c31 100644
--- a/src/crypto/x509v3/v3_crld.c
+++ b/src/crypto/x509v3/v3_crld.c
@@ -103,7 +103,7 @@
 		gnsect = X509V3_parse_list(sect);
 	if (!gnsect)
 		{
-		OPENSSL_PUT_ERROR(X509V3, gnames_from_sectname, X509V3_R_SECTION_NOT_FOUND);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND);
 		return NULL;
 		}
 	gens = v2i_GENERAL_NAMES(NULL, ctx, gnsect);
@@ -136,7 +136,7 @@
 		dnsect = X509V3_get_section(ctx, cnf->value);
 		if (!dnsect)
 			{
-			OPENSSL_PUT_ERROR(X509V3, set_dist_point_name, X509V3_R_SECTION_NOT_FOUND);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND);
 			return -1;
 			}
 		ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC);
@@ -152,7 +152,7 @@
 		if (sk_X509_NAME_ENTRY_value(rnm,
 				sk_X509_NAME_ENTRY_num(rnm) - 1)->set)
 			{
-			OPENSSL_PUT_ERROR(X509V3, set_dist_point_name, X509V3_R_INVALID_MULTIPLE_RDNS);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_MULTIPLE_RDNS);
 			goto err;
 			}
 		}
@@ -161,7 +161,7 @@
 
 	if (*pdp)
 		{
-		OPENSSL_PUT_ERROR(X509V3, set_dist_point_name, X509V3_R_DISTPOINT_ALREADY_SET);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_DISTPOINT_ALREADY_SET);
 		goto err;
 		}
 
@@ -362,7 +362,7 @@
 	return crld;
 
 	merr:
-	OPENSSL_PUT_ERROR(X509V3, v2i_crld, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	err:
 	GENERAL_NAME_free(gen);
 	GENERAL_NAMES_free(gens);
@@ -490,7 +490,7 @@
 			}
 		else
 			{
-                        OPENSSL_PUT_ERROR(X509V3, v2i_idp, X509V3_R_INVALID_NAME);
+                        OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NAME);
                         X509V3_conf_err(cnf);
                         goto err;
 			}
@@ -498,7 +498,7 @@
 	return idp;
 
 	merr:
-	OPENSSL_PUT_ERROR(X509V3, v2i_idp, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	err:
 	ISSUING_DIST_POINT_free(idp);
 	return NULL;
diff --git a/src/crypto/x509v3/v3_extku.c b/src/crypto/x509v3/v3_extku.c
index f4b8af8..d64eb9c 100644
--- a/src/crypto/x509v3/v3_extku.c
+++ b/src/crypto/x509v3/v3_extku.c
@@ -125,7 +125,7 @@
 	size_t i;
 
 	if(!(extku = sk_ASN1_OBJECT_new_null())) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_EXTENDED_KEY_USAGE, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 
@@ -135,7 +135,7 @@
 		else extval = val->name;
 		if(!(objtmp = OBJ_txt2obj(extval, 0))) {
 			sk_ASN1_OBJECT_pop_free(extku, ASN1_OBJECT_free);
-			OPENSSL_PUT_ERROR(X509V3, v2i_EXTENDED_KEY_USAGE, X509V3_R_INVALID_OBJECT_IDENTIFIER);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
 			X509V3_conf_err(val);
 			return NULL;
 		}
diff --git a/src/crypto/x509v3/v3_ia5.c b/src/crypto/x509v3/v3_ia5.c
index ec57e9b..5a27233 100644
--- a/src/crypto/x509v3/v3_ia5.c
+++ b/src/crypto/x509v3/v3_ia5.c
@@ -87,7 +87,7 @@
 	char *tmp;
 	if(!ia5 || !ia5->length) return NULL;
 	if(!(tmp = OPENSSL_malloc(ia5->length + 1))) {
-		OPENSSL_PUT_ERROR(X509V3, i2s_ASN1_IA5STRING, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	memcpy(tmp, ia5->data, ia5->length);
@@ -100,7 +100,7 @@
 {
 	ASN1_IA5STRING *ia5;
 	if(!str) {
-		OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_IA5STRING, X509V3_R_INVALID_NULL_ARGUMENT);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_ARGUMENT);
 		return NULL;
 	}
 	if(!(ia5 = M_ASN1_IA5STRING_new())) goto err;
@@ -111,7 +111,7 @@
 	}
 	return ia5;
 	err:
-	OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_IA5STRING, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	return NULL;
 }
 
diff --git a/src/crypto/x509v3/v3_info.c b/src/crypto/x509v3/v3_info.c
index 7558b2d..475c56f 100644
--- a/src/crypto/x509v3/v3_info.c
+++ b/src/crypto/x509v3/v3_info.c
@@ -124,7 +124,7 @@
 		nlen = strlen(objtmp) + strlen(vtmp->name) + 5;
 		ntmp = OPENSSL_malloc(nlen);
 		if(!ntmp) {
-			OPENSSL_PUT_ERROR(X509V3, i2v_AUTHORITY_INFO_ACCESS, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			return NULL;
 		}
 		BUF_strlcpy(ntmp, objtmp, nlen);
@@ -148,19 +148,19 @@
 	int objlen;
 	char *objtmp, *ptmp;
 	if(!(ainfo = sk_ACCESS_DESCRIPTION_new_null())) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_INFO_ACCESS, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
 		cnf = sk_CONF_VALUE_value(nval, i);
 		if(!(acc = ACCESS_DESCRIPTION_new())
 			|| !sk_ACCESS_DESCRIPTION_push(ainfo, acc)) {
-			OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_INFO_ACCESS, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			goto err;
 		}
 		ptmp = strchr(cnf->name, ';');
 		if(!ptmp) {
-			OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_INFO_ACCESS, X509V3_R_INVALID_SYNTAX);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SYNTAX);
 			goto err;
 		}
 		objlen = ptmp - cnf->name;
@@ -169,14 +169,14 @@
 		if(!v2i_GENERAL_NAME_ex(acc->location, method, ctx, &ctmp, 0))
 								 goto err; 
 		if(!(objtmp = OPENSSL_malloc(objlen + 1))) {
-			OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_INFO_ACCESS, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			goto err;
 		}
 		strncpy(objtmp, cnf->name, objlen);
 		objtmp[objlen] = 0;
 		acc->method = OBJ_txt2obj(objtmp, 0);
 		if(!acc->method) {
-			OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_INFO_ACCESS, X509V3_R_BAD_OBJECT);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_OBJECT);
 			ERR_add_error_data(2, "value=", objtmp);
 			OPENSSL_free(objtmp);
 			goto err;
diff --git a/src/crypto/x509v3/v3_lib.c b/src/crypto/x509v3/v3_lib.c
index d4e4e78..f8e5531 100644
--- a/src/crypto/x509v3/v3_lib.c
+++ b/src/crypto/x509v3/v3_lib.c
@@ -78,12 +78,12 @@
 int X509V3_EXT_add(X509V3_EXT_METHOD *ext)
 {
 	if(!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_stack_cmp))) {
-		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_add, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		ext_list_free(ext);
 		return 0;
 	}
 	if(!sk_X509V3_EXT_METHOD_push(ext_list, ext)) {
-		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_add, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		ext_list_free(ext);
 		return 0;
 	}
@@ -127,7 +127,7 @@
 	    const X509V3_EXT_METHOD *ext_method = X509V3_EXT_get_nid(nid);
 	    if (ext_method == NULL)
 	    {
-		    OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_free, X509V3_R_CANNOT_FIND_FREE_FUNCTION);
+		    OPENSSL_PUT_ERROR(X509V3, X509V3_R_CANNOT_FIND_FREE_FUNCTION);
 		    return 0;
 	    }
 
@@ -137,7 +137,7 @@
 		    ext_method->ext_free(ext_data);
 	    else
 	    {
-		    OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_free, X509V3_R_CANNOT_FIND_FREE_FUNCTION);
+		    OPENSSL_PUT_ERROR(X509V3, X509V3_R_CANNOT_FIND_FREE_FUNCTION);
 		    return 0;
 	    }
 
@@ -157,11 +157,11 @@
 	X509V3_EXT_METHOD *tmpext;
 
 	if(!(ext = X509V3_EXT_get_nid(nid_from))) {
-		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_add_alias, X509V3_R_EXTENSION_NOT_FOUND);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_NOT_FOUND);
 		return 0;
 	}
 	if(!(tmpext = (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)))) {
-		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_add_alias, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return 0;
 	}
 	*tmpext = *ext;
@@ -311,7 +311,7 @@
 	ext = X509V3_EXT_i2d(nid, crit, value);
 
 	if(!ext) {
-		OPENSSL_PUT_ERROR(X509V3, X509V3_add1_i2d, X509V3_R_ERROR_CREATING_EXTENSION);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CREATING_EXTENSION);
 		return 0;
 	}
 
@@ -330,6 +330,6 @@
 
 	err:
 	if(!(flags & X509V3_ADD_SILENT))
-		OPENSSL_PUT_ERROR(X509V3, X509V3_add1_i2d, errcode);
+		OPENSSL_PUT_ERROR(X509V3, errcode);
 	return 0;
 }
diff --git a/src/crypto/x509v3/v3_ncons.c b/src/crypto/x509v3/v3_ncons.c
index c42a665..19f5e94 100644
--- a/src/crypto/x509v3/v3_ncons.c
+++ b/src/crypto/x509v3/v3_ncons.c
@@ -135,7 +135,7 @@
 			}
 		else
 			{
-			OPENSSL_PUT_ERROR(X509V3, v2i_NAME_CONSTRAINTS, X509V3_R_INVALID_SYNTAX);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SYNTAX);
 			goto err;
 			}
 		tval.value = val->value;
@@ -152,7 +152,7 @@
 	return ncons;
 
 	memerr:
-	OPENSSL_PUT_ERROR(X509V3, v2i_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	err:
 	if (ncons)
 		NAME_CONSTRAINTS_free(ncons);
diff --git a/src/crypto/x509v3/v3_pci.c b/src/crypto/x509v3/v3_pci.c
index aa93891..f19a37a 100644
--- a/src/crypto/x509v3/v3_pci.c
+++ b/src/crypto/x509v3/v3_pci.c
@@ -87,13 +87,13 @@
 		{
 		if (*language)
 			{
-			OPENSSL_PUT_ERROR(X509V3, process_pci_value, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED);
 			X509V3_conf_err(val);
 			return 0;
 			}
 		if (!(*language = OBJ_txt2obj(val->value, 0)))
 			{
-			OPENSSL_PUT_ERROR(X509V3, process_pci_value, X509V3_R_INVALID_OBJECT_IDENTIFIER);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
 			X509V3_conf_err(val);
 			return 0;
 			}
@@ -102,13 +102,13 @@
 		{
 		if (*pathlen)
 			{
-			OPENSSL_PUT_ERROR(X509V3, process_pci_value, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED);
 			X509V3_conf_err(val);
 			return 0;
 			}
 		if (!X509V3_get_value_int(val, pathlen))
 			{
-			OPENSSL_PUT_ERROR(X509V3, process_pci_value, X509V3_R_POLICY_PATH_LENGTH);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_POLICY_PATH_LENGTH);
 			X509V3_conf_err(val);
 			return 0;
 			}
@@ -122,7 +122,7 @@
 			*policy = ASN1_OCTET_STRING_new();
 			if (!*policy)
 				{
-				OPENSSL_PUT_ERROR(X509V3, process_pci_value, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 				X509V3_conf_err(val);
 				return 0;
 				}
@@ -135,7 +135,7 @@
 
 			if (!tmp_data2) 
 				{
-				OPENSSL_PUT_ERROR(X509V3, process_pci_value, X509V3_R_ILLEGAL_HEX_DIGIT);
+				OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_HEX_DIGIT);
 				X509V3_conf_err(val);
 				goto err;
 				}
@@ -156,7 +156,7 @@
 				/* realloc failure implies the original data space is b0rked too! */
 				(*policy)->data = NULL;
 				(*policy)->length = 0;
-				OPENSSL_PUT_ERROR(X509V3, process_pci_value, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 				X509V3_conf_err(val);
 				goto err;
 				}
@@ -169,7 +169,7 @@
 			BIO *b = BIO_new_file(val->value + 5, "r");
 			if (!b)
 				{
-				OPENSSL_PUT_ERROR(X509V3, process_pci_value, ERR_R_BIO_LIB);
+				OPENSSL_PUT_ERROR(X509V3, ERR_R_BIO_LIB);
 				X509V3_conf_err(val);
 				goto err;
 				}
@@ -194,7 +194,7 @@
 
 			if (n < 0)
 				{
-				OPENSSL_PUT_ERROR(X509V3, process_pci_value, ERR_R_BIO_LIB);
+				OPENSSL_PUT_ERROR(X509V3, ERR_R_BIO_LIB);
 				X509V3_conf_err(val);
 				goto err;
 				}
@@ -217,20 +217,20 @@
 				/* realloc failure implies the original data space is b0rked too! */
 				(*policy)->data = NULL;
 				(*policy)->length = 0;
-				OPENSSL_PUT_ERROR(X509V3, process_pci_value, ERR_R_MALLOC_FAILURE);
+				OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 				X509V3_conf_err(val);
 				goto err;
 				}
 			}
 		else
 			{
-			OPENSSL_PUT_ERROR(X509V3, process_pci_value, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG);
 			X509V3_conf_err(val);
 			goto err;
 			}
 		if (!tmp_data)
 			{
-			OPENSSL_PUT_ERROR(X509V3, process_pci_value, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			X509V3_conf_err(val);
 			goto err;
 			}
@@ -262,7 +262,7 @@
 		CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i);
 		if (!cnf->name || (*cnf->name != '@' && !cnf->value))
 			{
-			OPENSSL_PUT_ERROR(X509V3, r2i_pci, X509V3_R_INVALID_PROXY_POLICY_SETTING);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_PROXY_POLICY_SETTING);
 			X509V3_conf_err(cnf);
 			goto err;
 			}
@@ -274,7 +274,7 @@
 			sect = X509V3_get_section(ctx, cnf->name + 1);
 			if (!sect)
 				{
-				OPENSSL_PUT_ERROR(X509V3, r2i_pci, X509V3_R_INVALID_SECTION);
+				OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION);
 				X509V3_conf_err(cnf);
 				goto err;
 				}
@@ -302,20 +302,21 @@
 	/* Language is mandatory */
 	if (!language)
 		{
-		OPENSSL_PUT_ERROR(X509V3, r2i_pci, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED);
 		goto err;
 		}
 	nid = OBJ_obj2nid(language);
 	if ((nid == NID_Independent || nid == NID_id_ppl_inheritAll) && policy)
 		{
-		OPENSSL_PUT_ERROR(X509V3, r2i_pci, X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY);
+		OPENSSL_PUT_ERROR(X509V3,
+			X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY);
 		goto err;
 		}
 
 	pci = PROXY_CERT_INFO_EXTENSION_new();
 	if (!pci)
 		{
-		OPENSSL_PUT_ERROR(X509V3, r2i_pci, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 
diff --git a/src/crypto/x509v3/v3_pcons.c b/src/crypto/x509v3/v3_pcons.c
index f87c6a0..b752290 100644
--- a/src/crypto/x509v3/v3_pcons.c
+++ b/src/crypto/x509v3/v3_pcons.c
@@ -112,7 +112,7 @@
 	CONF_VALUE *val;
 	size_t i;
 	if(!(pcons = POLICY_CONSTRAINTS_new())) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	for(i = 0; i < sk_CONF_VALUE_num(values); i++) {
@@ -124,13 +124,13 @@
 			if(!X509V3_get_value_int(val,
 				&pcons->inhibitPolicyMapping)) goto err;
 		} else {
-			OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_CONSTRAINTS, X509V3_R_INVALID_NAME);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NAME);
 			X509V3_conf_err(val);
 			goto err;
 		}
 	}
 	if (!pcons->inhibitPolicyMapping && !pcons->requireExplicitPolicy) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_CONSTRAINTS, X509V3_R_ILLEGAL_EMPTY_EXTENSION);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_EMPTY_EXTENSION);
 		goto err;
 	}
 
diff --git a/src/crypto/x509v3/v3_pmaps.c b/src/crypto/x509v3/v3_pmaps.c
index fbc169d..5b90977 100644
--- a/src/crypto/x509v3/v3_pmaps.c
+++ b/src/crypto/x509v3/v3_pmaps.c
@@ -122,7 +122,7 @@
 	size_t i;
 
 	if(!(pmaps = sk_POLICY_MAPPING_new_null())) {
-		OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_MAPPINGS, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 
@@ -130,7 +130,7 @@
 		val = sk_CONF_VALUE_value(nval, i);
 		if(!val->value || !val->name) {
 			sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free);
-			OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_MAPPINGS, X509V3_R_INVALID_OBJECT_IDENTIFIER);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
 			X509V3_conf_err(val);
 			return NULL;
 		}
@@ -138,14 +138,14 @@
 		obj2 = OBJ_txt2obj(val->value, 0);
 		if(!obj1 || !obj2) {
 			sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free);
-			OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_MAPPINGS, X509V3_R_INVALID_OBJECT_IDENTIFIER);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
 			X509V3_conf_err(val);
 			return NULL;
 		}
 		pmap = POLICY_MAPPING_new();
 		if (!pmap) {
 			sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free);
-			OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_MAPPINGS, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			return NULL;
 		}
 		pmap->issuerDomainPolicy = obj1;
diff --git a/src/crypto/x509v3/v3_purp.c b/src/crypto/x509v3/v3_purp.c
index 8ae8a06..f53c0f1 100644
--- a/src/crypto/x509v3/v3_purp.c
+++ b/src/crypto/x509v3/v3_purp.c
@@ -128,7 +128,7 @@
 int X509_PURPOSE_set(int *p, int purpose)
 {
 	if(X509_PURPOSE_get_by_id(purpose) == -1) {
-		OPENSSL_PUT_ERROR(X509V3, X509_PURPOSE_set, X509V3_R_INVALID_PURPOSE);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_PURPOSE);
 		return 0;
 	}
 	*p = purpose;
@@ -191,7 +191,7 @@
 	/* Need a new entry */
 	if(idx == -1) {
 		if(!(ptmp = OPENSSL_malloc(sizeof(X509_PURPOSE)))) {
-			OPENSSL_PUT_ERROR(X509V3, X509_PURPOSE_add, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			return 0;
 		}
 		ptmp->flags = X509_PURPOSE_DYNAMIC;
@@ -201,7 +201,7 @@
 	name_dup = BUF_strdup(name);
 	sname_dup = BUF_strdup(sname);
 	if (name_dup == NULL || sname_dup == NULL) {
-		OPENSSL_PUT_ERROR(X509V3, X509_PURPOSE_add, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		if (name_dup != NULL)
 			OPENSSL_free(name_dup);
 		if (sname_dup != NULL)
@@ -232,12 +232,12 @@
 	/* If its a new entry manage the dynamic table */
 	if(idx == -1) {
 		if(!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) {
-			OPENSSL_PUT_ERROR(X509V3, X509_PURPOSE_add, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			xptable_free(ptmp);
 			return 0;
 		}
 		if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
-			OPENSSL_PUT_ERROR(X509V3, X509_PURPOSE_add, ERR_R_MALLOC_FAILURE);
+			OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 			xptable_free(ptmp);
 			return 0;
 		}
diff --git a/src/crypto/x509v3/v3_skey.c b/src/crypto/x509v3/v3_skey.c
index 471a1ab..e396f05 100644
--- a/src/crypto/x509v3/v3_skey.c
+++ b/src/crypto/x509v3/v3_skey.c
@@ -86,7 +86,7 @@
 	long length;
 
 	if(!(oct = M_ASN1_OCTET_STRING_new())) {
-		OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_OCTET_STRING, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 
@@ -112,14 +112,14 @@
 	if(strcmp(str, "hash")) return s2i_ASN1_OCTET_STRING(method, ctx, str);
 
 	if(!(oct = M_ASN1_OCTET_STRING_new())) {
-		OPENSSL_PUT_ERROR(X509V3, s2i_skey_id, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 
 	if(ctx && (ctx->flags == CTX_TEST)) return oct;
 
 	if(!ctx || (!ctx->subject_req && !ctx->subject_cert)) {
-		OPENSSL_PUT_ERROR(X509V3, s2i_skey_id, X509V3_R_NO_PUBLIC_KEY);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_PUBLIC_KEY);
 		goto err;
 	}
 
@@ -128,7 +128,7 @@
 	else pk = ctx->subject_cert->cert_info->key->public_key;
 
 	if(!pk) {
-		OPENSSL_PUT_ERROR(X509V3, s2i_skey_id, X509V3_R_NO_PUBLIC_KEY);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_PUBLIC_KEY);
 		goto err;
 	}
 
@@ -136,7 +136,7 @@
 		goto err;
 
 	if(!M_ASN1_OCTET_STRING_set(oct, pkey_dig, diglen)) {
-		OPENSSL_PUT_ERROR(X509V3, s2i_skey_id, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		goto err;
 	}
 
diff --git a/src/crypto/x509v3/v3_sxnet.c b/src/crypto/x509v3/v3_sxnet.c
index bb5e214..4dd5bfc 100644
--- a/src/crypto/x509v3/v3_sxnet.c
+++ b/src/crypto/x509v3/v3_sxnet.c
@@ -159,7 +159,7 @@
 {
 	ASN1_INTEGER *izone = NULL;
 	if(!(izone = s2i_ASN1_INTEGER(NULL, zone))) {
-		OPENSSL_PUT_ERROR(X509V3, SXNET_add_id_asc, X509V3_R_ERROR_CONVERTING_ZONE);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CONVERTING_ZONE);
 		return 0;
 	}
 	return SXNET_add_id_INTEGER(psx, izone, user, userlen);
@@ -172,7 +172,7 @@
 {
 	ASN1_INTEGER *izone = NULL;
 	if(!(izone = M_ASN1_INTEGER_new()) || !ASN1_INTEGER_set(izone, lzone)) {
-		OPENSSL_PUT_ERROR(X509V3, SXNET_add_id_ulong, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		M_ASN1_INTEGER_free(izone);
 		return 0;
 	}
@@ -191,12 +191,12 @@
 	SXNET *sx = NULL;
 	SXNETID *id = NULL;
 	if(!psx || !zone || !user) {
-		OPENSSL_PUT_ERROR(X509V3, SXNET_add_id_INTEGER, X509V3_R_INVALID_NULL_ARGUMENT);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_ARGUMENT);
 		return 0;
 	}
 	if(userlen == -1) userlen = strlen(user);
 	if(userlen > 64) {
-		OPENSSL_PUT_ERROR(X509V3, SXNET_add_id_INTEGER, X509V3_R_USER_TOO_LONG);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_USER_TOO_LONG);
 		return 0;
 	}
 	if(!*psx) {
@@ -205,7 +205,7 @@
 		*psx = sx;
 	} else sx = *psx;
 	if(SXNET_get_id_INTEGER(sx, zone)) {
-		OPENSSL_PUT_ERROR(X509V3, SXNET_add_id_INTEGER, X509V3_R_DUPLICATE_ZONE_ID);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_DUPLICATE_ZONE_ID);
 		return 0;
 	}
 
@@ -218,7 +218,7 @@
 	return 1;
 	
 	err:
-	OPENSSL_PUT_ERROR(X509V3, SXNET_add_id_INTEGER, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	SXNETID_free(id);
 	SXNET_free(sx);
 	*psx = NULL;
@@ -230,7 +230,7 @@
 	ASN1_INTEGER *izone = NULL;
 	ASN1_OCTET_STRING *oct;
 	if(!(izone = s2i_ASN1_INTEGER(NULL, zone))) {
-		OPENSSL_PUT_ERROR(X509V3, SXNET_get_id_asc, X509V3_R_ERROR_CONVERTING_ZONE);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CONVERTING_ZONE);
 		return NULL;
 	}
 	oct = SXNET_get_id_INTEGER(sx, izone);
@@ -243,7 +243,7 @@
 	ASN1_INTEGER *izone = NULL;
 	ASN1_OCTET_STRING *oct;
 	if(!(izone = M_ASN1_INTEGER_new()) || !ASN1_INTEGER_set(izone, lzone)) {
-		OPENSSL_PUT_ERROR(X509V3, SXNET_get_id_ulong, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		M_ASN1_INTEGER_free(izone);
 		return NULL;
 	}
diff --git a/src/crypto/x509v3/v3_utl.c b/src/crypto/x509v3/v3_utl.c
index 77fc65c..aa65c79 100644
--- a/src/crypto/x509v3/v3_utl.c
+++ b/src/crypto/x509v3/v3_utl.c
@@ -70,6 +70,8 @@
 #include <openssl/obj.h>
 #include <openssl/x509v3.h>
 
+#include "../conf/internal.h"
+
 
 static char *strip_spaces(char *name);
 static int sk_strcmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b);
@@ -91,7 +93,7 @@
 	char *tname = NULL, *tvalue = NULL;
 	if(name && !(tname = BUF_strdup(name))) goto err;
 	if(value && !(tvalue = BUF_strdup(value))) goto err;
-	if(!(vtmp = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) goto err;
+	if(!(vtmp = CONF_VALUE_new())) goto err;
 	if(!*extlist && !(*extlist = sk_CONF_VALUE_new_null())) goto err;
 	vtmp->section = NULL;
 	vtmp->name = tname;
@@ -99,7 +101,7 @@
 	if(!sk_CONF_VALUE_push(*extlist, vtmp)) goto err;
 	return 1;
 	err:
-	OPENSSL_PUT_ERROR(X509V3, X509V3_add_value, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	if(vtmp) OPENSSL_free(vtmp);
 	if(tname) OPENSSL_free(tname);
 	if(tvalue) OPENSSL_free(tvalue);
@@ -145,7 +147,7 @@
 	if(!a) return NULL;
 	if(!(bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) ||
 	    !(strtmp = BN_bn2dec(bntmp)) )
-		OPENSSL_PUT_ERROR(X509V3, i2s_ASN1_ENUMERATED, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	BN_free(bntmp);
 	return strtmp;
 }
@@ -157,7 +159,7 @@
 	if(!a) return NULL;
 	if(!(bntmp = ASN1_INTEGER_to_BN(a, NULL)) ||
 	    !(strtmp = BN_bn2dec(bntmp)) )
-		OPENSSL_PUT_ERROR(X509V3, i2s_ASN1_INTEGER, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	BN_free(bntmp);
 	return strtmp;
 }
@@ -169,7 +171,7 @@
 	int isneg, ishex;
 	int ret;
 	if (!value) {
-		OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_INTEGER, X509V3_R_INVALID_NULL_VALUE);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_VALUE);
 		return 0;
 	}
 	bn = BN_new();
@@ -188,7 +190,7 @@
 
 	if (!ret || value[ret]) {
 		BN_free(bn);
-		OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_INTEGER, X509V3_R_BN_DEC2BN_ERROR);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_BN_DEC2BN_ERROR);
 		return 0;
 	}
 
@@ -197,7 +199,7 @@
 	aint = BN_to_ASN1_INTEGER(bn, NULL);
 	BN_free(bn);
 	if (!aint) {
-		OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_INTEGER, X509V3_R_BN_TO_ASN1_INTEGER_ERROR);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_BN_TO_ASN1_INTEGER_ERROR);
 		return 0;
 	}
 	if (isneg) aint->type |= V_ASN1_NEG;
@@ -232,7 +234,7 @@
 		return 1;
 	}
 	err:
-	OPENSSL_PUT_ERROR(X509V3, X509V3_get_value_bool, X509V3_R_INVALID_BOOLEAN_STRING);
+	OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_BOOLEAN_STRING);
 	X509V3_conf_err(value);
 	return 0;
 }
@@ -264,7 +266,7 @@
 	linebuf = BUF_strdup(line);
 	if (linebuf == NULL)
 		{
-		OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		goto err;
 		}
 	state = HDR_NAME;
@@ -279,7 +281,7 @@
 				*p = 0;
 				ntmp = strip_spaces(q);
 				if(!ntmp) {
-					OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_NAME);
+					OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_NAME);
 					goto err;
 				}
 				q = p + 1;
@@ -291,7 +293,7 @@
 				printf("%s\n", ntmp);
 #endif
 				if(!ntmp) {
-					OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_NAME);
+					OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_NAME);
 					goto err;
 				}
 				X509V3_add_value(ntmp, NULL, &values);
@@ -307,7 +309,7 @@
 				printf("%s\n", ntmp);
 #endif
 				if(!vtmp) {
-					OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_VALUE);
+					OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_VALUE);
 					goto err;
 				}
 				X509V3_add_value(ntmp, vtmp, &values);
@@ -324,7 +326,7 @@
 		printf("%s=%s\n", ntmp, vtmp);
 #endif
 		if(!vtmp) {
-			OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_VALUE);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_VALUE);
 			goto err;
 		}
 		X509V3_add_value(ntmp, vtmp, &values);
@@ -334,7 +336,7 @@
 		printf("%s\n", ntmp);
 #endif
 		if(!ntmp) {
-			OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_NAME);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_NAME);
 			goto err;
 		}
 		X509V3_add_value(ntmp, NULL, &values);
@@ -379,7 +381,7 @@
 	static const char hexdig[] = "0123456789ABCDEF";
 	if(!buffer || !len) return NULL;
 	if(!(tmp = OPENSSL_malloc(len * 3 + 1))) {
-		OPENSSL_PUT_ERROR(X509V3, hex_to_string, ERR_R_MALLOC_FAILURE);
+		OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
 	q = tmp;
@@ -402,7 +404,7 @@
 	unsigned char *hexbuf, *q;
 	unsigned char ch, cl, *p;
 	if(!str) {
-		OPENSSL_PUT_ERROR(X509V3, string_to_hex, X509V3_R_INVALID_NULL_ARGUMENT);
+		OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_ARGUMENT);
 		return NULL;
 	}
 	if(!(hexbuf = OPENSSL_malloc(strlen(str) >> 1))) goto err;
@@ -411,7 +413,7 @@
 		if(ch == ':') continue;
 		cl = *p++;
 		if(!cl) {
-			OPENSSL_PUT_ERROR(X509V3, string_to_hex, X509V3_R_ODD_NUMBER_OF_DIGITS);
+			OPENSSL_PUT_ERROR(X509V3, X509V3_R_ODD_NUMBER_OF_DIGITS);
 			OPENSSL_free(hexbuf);
 			return NULL;
 		}
@@ -435,12 +437,12 @@
 
 	err:
 	if(hexbuf) OPENSSL_free(hexbuf);
-	OPENSSL_PUT_ERROR(X509V3, string_to_hex, ERR_R_MALLOC_FAILURE);
+	OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
 	return NULL;
 
 	badhex:
 	OPENSSL_free(hexbuf);
-	OPENSSL_PUT_ERROR(X509V3, string_to_hex, X509V3_R_ILLEGAL_HEX_DIGIT);
+	OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_HEX_DIGIT);
 	return NULL;
 
 }
diff --git a/src/crypto/x509v3/v3nametest.c b/src/crypto/x509v3/v3name_test.c
similarity index 100%
rename from src/crypto/x509v3/v3nametest.c
rename to src/crypto/x509v3/v3name_test.c